Commit 307e14c0 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag '6.3-rc-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs client updates from Steve French:
 "The largest subset of this is from David Howells et al: making the
  cifs/smb3 driver pass iov_iters down to the lowest layers, directly to
  the network transport rather than passing lists of pages around,
  helping multiple areas:

   - Pin user pages, thereby fixing the race between concurrent DIO read
     and fork, where the pages containing the DIO read buffer may end up
     belonging to the child process and not the parent - with the result
     that the parent might not see the retrieved data.

   - cifs shouldn't take refs on pages extracted from non-user-backed
     iterators (eg. KVEC). With these changes, cifs will apply the
     appropriate cleanup.

   - Making it easier to transition to using folios in cifs rather than
     pages by dealing with them through BVEC and XARRAY iterators.

   - Allowing cifs to use the new splice function

  The remainder are:

   - fixes for stable, including various fixes for uninitialized memory,
     wrong length field causing mount issue to very old servers,
     important directory lease fixes and reconnect fixes

   - cleanups (unused code removal, change one element array usage, and
     a change form strtobool to kstrtobool, and Kconfig cleanups)

   - SMBDIRECT (RDMA) fixes including iov_iter integration and UAF fixes

   - reconnect fixes

   - multichannel fixes, including improving channel allocation (to
     least used channel)

   - remove the last use of lock_page_killable by moving to
     folio_lock_killable"

* tag '6.3-rc-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: (46 commits)
  update internal module version number for cifs.ko
  cifs: update ip_addr for ses only for primary chan setup
  cifs: use tcon allocation functions even for dummy tcon
  cifs: use the least loaded channel for sending requests
  cifs: DIO to/from KVEC-type iterators should now work
  cifs: Remove unused code
  cifs: Build the RDMA SGE list directly from an iterator
  cifs: Change the I/O paths to use an iterator rather than a page list
  cifs: Add a function to read into an iter from a socket
  cifs: Add some helper functions
  cifs: Add a function to Hash the contents of an iterator
  cifs: Add a function to build an RDMA SGE list from an iterator
  netfs: Add a function to extract an iterator into a scatterlist
  netfs: Add a function to extract a UBUF or IOVEC into a BVEC iterator
  cifs: Implement splice_read to pass down ITER_BVEC not ITER_PIPE
  splice: Export filemap/direct_splice_read()
  iov_iter: Add a function to extract a page list from an iterator
  iov_iter: Define flags to qualify page extraction.
  splice: Add a func to do a splice from an O_DIRECT file without ITER_PIPE
  splice: Add a func to do a splice from a buffered file without ITER_PIPE
  ...
parents d8ca6dbb fdbf8072
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -1236,11 +1236,11 @@ static int bio_iov_add_zone_append_page(struct bio *bio, struct page *page,
 */
static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
{
	iov_iter_extraction_t extraction_flags = 0;
	unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt;
	unsigned short entries_left = bio->bi_max_vecs - bio->bi_vcnt;
	struct bio_vec *bv = bio->bi_io_vec + bio->bi_vcnt;
	struct page **pages = (struct page **)bv;
	unsigned int gup_flags = 0;
	ssize_t size, left;
	unsigned len, i = 0;
	size_t offset, trim;
@@ -1255,7 +1255,7 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
	pages += entries_left * (PAGE_PTRS_PER_BVEC - 1);

	if (bio->bi_bdev && blk_queue_pci_p2pdma(bio->bi_bdev->bd_disk->queue))
		gup_flags |= FOLL_PCI_P2PDMA;
		extraction_flags |= ITER_ALLOW_P2PDMA;

	/*
	 * Each segment in the iov is required to be a block size multiple.
@@ -1266,7 +1266,7 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
	 */
	size = iov_iter_get_pages(iter, pages,
				  UINT_MAX - bio->bi_iter.bi_size,
				  nr_pages, &offset, gup_flags);
				  nr_pages, &offset, extraction_flags);
	if (unlikely(size <= 0))
		return size ? size : -EFAULT;

+4 −4
Original line number Diff line number Diff line
@@ -264,9 +264,9 @@ static struct bio *blk_rq_map_bio_alloc(struct request *rq,
static int bio_map_user_iov(struct request *rq, struct iov_iter *iter,
		gfp_t gfp_mask)
{
	iov_iter_extraction_t extraction_flags = 0;
	unsigned int max_sectors = queue_max_hw_sectors(rq->q);
	unsigned int nr_vecs = iov_iter_npages(iter, BIO_MAX_VECS);
	unsigned int gup_flags = 0;
	struct bio *bio;
	int ret;
	int j;
@@ -279,7 +279,7 @@ static int bio_map_user_iov(struct request *rq, struct iov_iter *iter,
		return -ENOMEM;

	if (blk_queue_pci_p2pdma(rq->q))
		gup_flags |= FOLL_PCI_P2PDMA;
		extraction_flags |= ITER_ALLOW_P2PDMA;

	while (iov_iter_count(iter)) {
		struct page **pages, *stack_pages[UIO_FASTIOV];
@@ -290,10 +290,10 @@ static int bio_map_user_iov(struct request *rq, struct iov_iter *iter,
		if (nr_vecs <= ARRAY_SIZE(stack_pages)) {
			pages = stack_pages;
			bytes = iov_iter_get_pages(iter, pages, LONG_MAX,
						   nr_vecs, &offs, gup_flags);
						   nr_vecs, &offs, extraction_flags);
		} else {
			bytes = iov_iter_get_pages_alloc(iter, &pages,
						LONG_MAX, &offs, gup_flags);
						LONG_MAX, &offs, extraction_flags);
		}
		if (unlikely(bytes <= 0)) {
			ret = bytes ? bytes : -EFAULT;
+34 −32
Original line number Diff line number Diff line
@@ -18,40 +18,38 @@ config CIFS
	select DNS_RESOLVER
	select ASN1
	select OID_REGISTRY
	select NETFS_SUPPORT
	help
	  This is the client VFS module for the SMB3 family of NAS protocols,
	  (including support for the most recent, most secure dialect SMB3.1.1)
	  as well as for earlier dialects such as SMB2.1, SMB2 and the older
	  Common Internet File System (CIFS) protocol.  CIFS was the successor
	  to the original dialect, the Server Message Block (SMB) protocol, the
	  native file sharing mechanism for most early PC operating systems.

	  The SMB3 protocol is supported by most modern operating systems
	  and NAS appliances (e.g. Samba, Windows 10, Windows Server 2016,
	  MacOS) and even in the cloud (e.g. Microsoft Azure).
	  The older CIFS protocol was included in Windows NT4, 2000 and XP (and
	  later) as well by Samba (which provides excellent CIFS and SMB3
	  server support for Linux and many other operating systems). Use of
	  dialects older than SMB2.1 is often discouraged on public networks.
	  This is the client VFS module for the SMB3 family of network file
	  protocols (including the most recent, most secure dialect SMB3.1.1).
	  This module also includes support for earlier dialects such as
	  SMB2.1, SMB2 and even the old Common Internet File System (CIFS)
	  protocol.  CIFS was the successor to the original network filesystem
	  protocol, Server Message Block (SMB ie SMB1), the native file sharing
	  mechanism for most early PC operating systems.

	  The SMB3.1.1 protocol is supported by most modern operating systems
	  and NAS appliances (e.g. Samba, Windows 11, Windows Server 2022,
	  MacOS) and even in the cloud (e.g. Microsoft Azure) and also by the
	  Linux kernel server, ksmbd.  Support for the older CIFS protocol was
	  included in Windows NT4, 2000 and XP (and later). Use of dialects
	  older than SMB2.1 is often discouraged on public networks.
	  This module also provides limited support for OS/2 and Windows ME
	  and similar very old servers.

	  This module provides an advanced network file system client
	  for mounting to SMB3 (and CIFS) compliant servers.  It includes
	  support for DFS (hierarchical name space), secure per-user
	  session establishment via Kerberos or NTLM or NTLMv2, RDMA
	  (smbdirect), advanced security features, per-share encryption,
	  directory leases, safe distributed caching (oplock), optional packet
	  signing, Unicode and other internationalization improvements.
	  This module provides an advanced network file system client for
	  mounting to SMB3 (and CIFS) compliant servers.  It includes support
	  for DFS (hierarchical name space), secure per-user session
	  establishment via Kerberos or NTLMv2, RDMA (smbdirect), advanced
	  security features, per-share encryption, packet-signing, snapshots,
	  directory leases, safe distributed caching (leases), multichannel,
	  Unicode and other internationalization improvements.

	  In general, the default dialects, SMB3 and later, enable better
	  performance, security and features, than would be possible with CIFS.
	  Note that when mounting to Samba, due to the CIFS POSIX extensions,
	  CIFS mounts can provide slightly better POSIX compatibility
	  than SMB3 mounts. SMB2/SMB3 mount options are also
	  slightly simpler (compared to CIFS) due to protocol improvements.

	  If you need to mount to Samba, Azure, Macs or Windows from this machine, say Y.
	  If you need to mount to Samba, Azure, ksmbd, Macs or Windows from this
	  machine, say Y.

config CIFS_STATS2
	bool "Extended statistics"
@@ -111,12 +109,12 @@ config CIFS_POSIX
	depends on CIFS && CIFS_ALLOW_INSECURE_LEGACY && CIFS_XATTR
	help
	  Enabling this option will cause the cifs client to attempt to
	  negotiate a newer dialect with servers, such as Samba 3.0.5
	  or later, that optionally can handle more POSIX like (rather
	  than Windows like) file behavior.  It also enables
	  support for POSIX ACLs (getfacl and setfacl) to servers
	  (such as Samba 3.10 and later) which can negotiate
	  CIFS POSIX ACL support.  If unsure, say N.
	  negotiate a feature of the older cifs dialect with servers, such as
	  Samba 3.0.5 or later, that optionally can handle more POSIX like
	  (rather than Windows like) file behavior.  It also enables support
	  for POSIX ACLs (getfacl and setfacl) to servers (such as Samba 3.10
	  and later) which can negotiate CIFS POSIX ACL support.  This config
	  option is not needed when mounting with SMB3.1.1. If unsure, say N.

config CIFS_DEBUG
	bool "Enable CIFS debugging routines"
@@ -178,6 +176,8 @@ config CIFS_NFSD_EXPORT
	help
	  Allows NFS server to export a CIFS mounted share (nfsd over cifs)

if CIFS

config CIFS_SMB_DIRECT
	bool "SMB Direct support"
	depends on CIFS=m && INFINIBAND && INFINIBAND_ADDR_TRANS || CIFS=y && INFINIBAND=y && INFINIBAND_ADDR_TRANS=y
@@ -201,3 +201,5 @@ config CIFS_ROOT
	  Enables root file system support over SMB protocol.

	  Most people say N here.

endif
+29 −14
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@

static struct cached_fid *init_cached_dir(const char *path);
static void free_cached_dir(struct cached_fid *cfid);
static void smb2_close_cached_fid(struct kref *ref);

static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
						    const char *path,
@@ -181,12 +182,13 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
	rqst[0].rq_iov = open_iov;
	rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;

	oparms.tcon = tcon;
	oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_FILE);
	oparms.desired_access = FILE_READ_ATTRIBUTES;
	oparms.disposition = FILE_OPEN;
	oparms.fid = pfid;
	oparms.reconnect = false;
	oparms = (struct cifs_open_parms) {
		.tcon = tcon,
		.create_options = cifs_create_options(cifs_sb, CREATE_NOT_FILE),
		.desired_access = FILE_READ_ATTRIBUTES,
		.disposition = FILE_OPEN,
		.fid = pfid,
	};

	rc = SMB2_open_init(tcon, server,
			    &rqst[0], &oplock, &oparms, utf16_path);
@@ -220,8 +222,8 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
		}
		goto oshr_free;
	}

	atomic_inc(&tcon->num_remote_opens);
	cfid->tcon = tcon;
	cfid->is_open = true;

	o_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base;
	oparms.fid->persistent_fid = o_rsp->PersistentFileId;
@@ -233,12 +235,12 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
	if (o_rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE)
		goto oshr_free;


	smb2_parse_contexts(server, o_rsp,
			    &oparms.fid->epoch,
			    oparms.fid->lease_key, &oplock,
			    NULL, NULL);

	if (!(oplock & SMB2_LEASE_READ_CACHING_HE))
		goto oshr_free;
	qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
	if (le32_to_cpu(qi_rsp->OutputBufferLength) < sizeof(struct smb2_file_all_info))
		goto oshr_free;
@@ -259,9 +261,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
		}
	}
	cfid->dentry = dentry;
	cfid->tcon = tcon;
	cfid->time = jiffies;
	cfid->is_open = true;
	cfid->has_lease = true;

oshr_free:
@@ -271,7 +271,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
	free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
	free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
	spin_lock(&cfids->cfid_list_lock);
	if (!cfid->has_lease) {
	if (rc && !cfid->has_lease) {
		if (cfid->on_list) {
			list_del(&cfid->entry);
			cfid->on_list = false;
@@ -280,13 +280,27 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
		rc = -ENOENT;
	}
	spin_unlock(&cfids->cfid_list_lock);
	if (!rc && !cfid->has_lease) {
		/*
		 * We are guaranteed to have two references at this point.
		 * One for the caller and one for a potential lease.
		 * Release the Lease-ref so that the directory will be closed
		 * when the caller closes the cached handle.
		 */
		kref_put(&cfid->refcount, smb2_close_cached_fid);
	}
	if (rc) {
		if (cfid->is_open)
			SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid,
				   cfid->fid.volatile_fid);
		free_cached_dir(cfid);
		cfid = NULL;
	}

	if (rc == 0)
	if (rc == 0) {
		*ret_cfid = cfid;
		atomic_inc(&tcon->num_remote_opens);
	}

	return rc;
}
@@ -335,6 +349,7 @@ smb2_close_cached_fid(struct kref *ref)
	if (cfid->is_open) {
		SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid,
			   cfid->fid.volatile_fid);
		atomic_dec(&cfid->tcon->num_remote_opens);
	}

	free_cached_dir(cfid);
+7 −4
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
@@ -455,8 +456,10 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)

			spin_lock(&ses->iface_lock);
			if (ses->iface_count)
				seq_printf(m, "\n\n\tServer interfaces: %zu",
					   ses->iface_count);
				seq_printf(m, "\n\n\tServer interfaces: %zu"
					   "\tLast updated: %lu seconds ago",
					   ses->iface_count,
					   (jiffies - ses->iface_last_update) / HZ);
			j = 0;
			list_for_each_entry(iface, &ses->iface_list,
						 iface_head) {
@@ -787,7 +790,7 @@ static ssize_t cifsFYI_proc_write(struct file *file, const char __user *buffer,
	rc = get_user(c[0], buffer);
	if (rc)
		return rc;
	if (strtobool(c, &bv) == 0)
	if (kstrtobool(c, &bv) == 0)
		cifsFYI = bv;
	else if ((c[0] > '1') && (c[0] <= '9'))
		cifsFYI = (int) (c[0] - '0'); /* see cifs_debug.h for meanings */
@@ -947,7 +950,7 @@ static ssize_t cifs_security_flags_proc_write(struct file *file,

	if (count < 3) {
		/* single char or single char followed by null */
		if (strtobool(flags_string, &bv) == 0) {
		if (kstrtobool(flags_string, &bv) == 0) {
			global_secflags = bv ? CIFSSEC_MAX : CIFSSEC_DEF;
			return count;
		} else if (!isdigit(flags_string[0])) {
Loading