linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator
@ 2025-08-06 20:36 David Howells
  2025-08-06 20:36 ` [RFC PATCH 01/31] iov_iter: Move ITER_DISCARD and ITER_XARRAY iteration out-of-line David Howells
                   ` (34 more replies)
  0 siblings, 35 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel

Hi Steve et al,

[!] NOTE: These patches are NOT FULLY WRITTEN, won't necessarily compile
    all the way through and haven't been fully tested and this is intended
    as a preview of what I'm working on.  Basic SMB1 and SMB2+ work as far
    as "cifs: Rewrite base TCP transmission".  Encrypted, signed and RDMA
    may work but haven't been tested; compressed is disabled.  Assume that
    anything beyond the specified point won't work.

I'm trying to work towards the network filesystems being able to use
zerocopy facilities such as MSG_SPLICE_PAGES and, in doing so, I think the
cifs driver can be simplified quite a bit.

However, making it possible to use the zerocopy facilities is probably
going to mean moving away from storing the data to be transmitted in slab
pages as slab pages don't have refcounts and their lifetime rules are
unsuitable for splicing.

So what I'd like to do is to allocate protocol bufferage from the netmem
allocator.  The netmem allocator, if I understand it correctly, manages DMA
mapping and IOMMU wrangling in bulk, and works as a bump/page fragment
allocator - which has the potential to improve performance a bit.

The aim is to build up a list of fragments for each request using a bvecq.
These form a segmented list and can be spliced together when assembling a
compound request.  The segmented list can then be passed to sendmsg() with
MSG_SPLICE_PAGES in a single call, thereby only having a single loop (in
the TCP stack) to shovel data, not loops-over-loops.  Possibly we can
dispense with corking also, provided we can tell TCP to flush the record
boundaries.  (Note that this also simplifies smbd_send() for RDMA).

To make this easier, I want to introduce a "request descriptor", which I'm
calling "struct smb_message" and allocate it at a higher level, notably the
PDU encoding routines in cifssmb.c and smb2pdu.c and then hand that down
into the transport.  It will contain the list of fragments that form the
message.

smb_message then replaces mid_q_struct, absorbing its contents.  The
transport then doesn't allocate these, but uses the ones that it is given
and the I/O thread gets to simplify its refcounting and do less of it.  The
rule is that smb_message gets an extra ref when it is enqueued and whoever
dequeues it gets this ref and either puts it or hands it on.  The PDU
encoding routines get a ref when allocating them and keep the refs until
they complete.

smb_message is then given a next pointer to allow compounds to be trivially
assembled, with the protocol wrangling being done in the transport.  This
next pointer also allows a bunch of fixed-size arrays to be got rid of
(which were imposing weird restrictions like reducing the maximum component
count of a compound if we stole a kvec[] slot for the transform header).

To this end, I make the following significant changes.  Note that some of
the changes are a way to transit to a later stage.

 (1) Make SMB1 transport use the SMB2 transport rather than having parallel
     dispatch code.

     (a) Get rid of the separation of the message buffer into two kvecs,
     	 one for the rfc1002 header and one for the rest.  This seems to be
     	 only to simplify the signing code - but at the expense of making a
     	 bunch of other places more complex.

     (b) Make SendReceive() wrap cifs_send_recv() as does SendReceive2().

     (c) Get rid of SendReceiveBlockingLock() in favour of using
     	 SendReceive() and a couple of flags to request interruptible
     	 waiting and to indicate Windows-type unlock rather than lock
     	 cancellation.

 (2) Replace mid_q_struct with smb_message and also include credits and
     smb_rqst therein.

 (3) Rewrite the base TCP transmission to be able to use MSG_SPLICE_PAGES.

     (a) Copy all the data involved in a message into a big buffer formed
     	 of a sequence of pages attached to a bvecq.

     (b) If encrypting the message just encrypt this buffer.  Converting
     	 this to a scatterlist is much simpler (and uses less memory) than
     	 encrypting from the protocol elements.

     (c) As the pages in the bvecq are just that, they have refcounts and
     	 can be passed to MSG_SPLICE_PAGES - thereby avoiding the copy in
     	 TCP.

     (d) Compression should be a matter of vmap()'ing these pages to form
     	 the source buffer, allocating a second buffer of pages to form a
     	 dest buffer, also in a bvecq, vmapping that and then doing the
     	 compression.  The first buffer can then just be replaced by the
     	 second.

     (e) __smb_send_rqst() can then do a single sendmsg() with
     	 MSG_SPLICE_PAGES() from an ITER_BVECQ-type iterator.

     (f) smbd_send() can push the same buffer to smbd_post_send_iter() from
     	 the same iterator.

 (4) Clean up mid->callback_data.  Replace it with a waitqueue in
     smb_message (for most commands) and a cifs_io_subrequest pointer (for
     read and write).  Make request completion wait on the smb_message
     waitqueue rather than on server->response_q to avoid thundering herd
     issues.

     (Also, I note that under some circumstances, cifs just wakes up the
     first thing on server->response_q without any reference to *what* it
     is waking up).

 (5) Add some more bits to smb_message to hold the buffers in a bvecq with
     the intent of killing of the smb_rqst struct.

     (a) The PDU encoders will have to work out how much memory they need
     	 for the request protocol bits in advance and tell the smb_message
     	 allocator their requirements.  This will get the requested amount
     	 from the netmem allocator, so it needs to be correctly sized.  A
     	 pointer is then set in smb->request to the buffer.

     (b) The smb_message is given a pointer (->next) to chain to another
     	 message to be compounded after it.

     (c) smb_send_recv_messages() will be used to dispatch a synchronous
     	 request.  If the head smb_message's ->next pointer is not NULL, it
     	 will set the appropriate compound chaining stuff and insert
     	 appropriate padding.  Then it will link the bvecq structs of those
     	 messages together.

 (6) Convert PDU encoders to allocate and use smb_message and pass it down.

     (a) So far, SMB2 Negotiate Protocol, Session Setup, Logoff, Tree
     	 Connect and Tree Disconnect have been done - and though they build
     	 if SMB1 and compression are disabled, they won't work yet and so
     	 haven't been tested.

     (b) SMB2 Posix Mkdir has been attempted and will compile, but is
     	 likely to need rejigging as it's a close associate of Create.

     (c) SMB2 Create/Open is partially done and won't compile.  This gets
     	 complicated because it's used in a lot of places and also gets
     	 compounded - so anything that gets compounded with it must also be
     	 converted.

The patches can be found here also:

	https://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs.git/log/?h=cifs-experimental

Thanks,
David

David Howells (31):
  iov_iter: Move ITER_DISCARD and ITER_XARRAY iteration out-of-line
  iov_iter: Add a segmented queue of bio_vec[]
  netfs: Provide facility to alloc buffer in a bvecq
  cifs, nls: Provide unicode size determination func
  cifs: Introduce an ALIGN8() macro
  cifs: Move the SMB1 transport code out of transport.c
  cifs: Rename mid_q_entry to smb_message
  cifs: Keep the CPU-endian command ID around
  cifs: Rename SMB2_xxxx_HE to SMB2_xxxx
  cifs: Make smb1's SendReceive() wrap cifs_send_recv()
  cifs: Fix SMB1 to not require separate kvec for the rfc1002 header
  cifs: Replace SendReceiveBlockingLock() with SendReceive() plus flags
  cifs: Institute message managing struct
  cifs: Split crypt_message() into encrypt and decrypt variants
  cifs: Use netfs_alloc/free_folioq_buffer()
  cifs: Rewrite base TCP transmission
  cifs: Rework smb2 decryption
  cifs: Pass smb_message structs down into the transport layer
  cifs: Clean up mid->callback_data and kill off mid->creator
  cifs: Don't need state locking in smb2_get_mid_entry()
  cifs: [DEBUG] smb_message refcounting
  cifs: Add netmem allocation functions
  cifs: Add more pieces to smb_message
  cifs: Convert SMB2 Negotiate Protocol request
  cifs: Convert SMB2 Session Setup request
  cifs: Convert SMB2 Logoff request
  cifs: Convert SMB2 Tree Connect request
  cifs: Convert SMB2 Tree Disconnect request
  cifs: Rearrange Create request subfuncs
  cifs: Convert SMB2 Posix Mkdir request
  cifs: Convert SMB2 Open request

 fs/netfs/Makefile             |    1 +
 fs/netfs/buffer.c             |  102 ++
 fs/nls/nls_base.c             |   33 +
 fs/smb/client/Makefile        |    2 +-
 fs/smb/client/cached_dir.c    |   41 +-
 fs/smb/client/cifs_debug.c    |   15 +-
 fs/smb/client/cifs_unicode.c  |   39 +
 fs/smb/client/cifs_unicode.h  |    2 +
 fs/smb/client/cifsencrypt.c   |   77 +-
 fs/smb/client/cifsfs.c        |   31 +-
 fs/smb/client/cifsglob.h      |  254 ++--
 fs/smb/client/cifsproto.h     |   91 +-
 fs/smb/client/cifssmb.c       |  123 +-
 fs/smb/client/cifstransport.c |  251 ++++
 fs/smb/client/compress.c      |    4 +-
 fs/smb/client/compress.h      |    6 +-
 fs/smb/client/connect.c       |  158 +-
 fs/smb/client/netmisc.c       |   15 +-
 fs/smb/client/ntlmssp.h       |   20 +-
 fs/smb/client/reparse.c       |    2 +-
 fs/smb/client/sess.c          |  271 ++--
 fs/smb/client/smb1ops.c       |  101 +-
 fs/smb/client/smb2file.c      |    2 +-
 fs/smb/client/smb2inode.c     |    6 +-
 fs/smb/client/smb2misc.c      |   80 +-
 fs/smb/client/smb2ops.c       |  570 +++----
 fs/smb/client/smb2pdu.c       | 2616 +++++++++++++++++----------------
 fs/smb/client/smb2proto.h     |   65 +-
 fs/smb/client/smb2transport.c |  229 ++-
 fs/smb/client/smbdirect.c     |   88 +-
 fs/smb/client/smbdirect.h     |    5 +-
 fs/smb/client/trace.h         |   61 +
 fs/smb/client/transport.c     | 1372 +++++++----------
 fs/smb/common/smb2pdu.h       |   92 +-
 fs/smb/server/connection.c    |    2 +-
 fs/smb/server/oplock.c        |    4 +-
 fs/smb/server/smb2misc.c      |   14 +-
 fs/smb/server/smb2ops.c       |   38 +-
 fs/smb/server/smb2pdu.c       |   66 +-
 fs/smb/server/smb_common.c    |    2 +-
 include/linux/bvec.h          |   13 +
 include/linux/iov_iter.h      |   77 +-
 include/linux/netfs.h         |    4 +
 include/linux/nls.h           |    1 +
 include/linux/uio.h           |   11 +
 lib/iov_iter.c                |  406 ++++-
 lib/tests/kunit_iov_iter.c    |  196 +++
 47 files changed, 4177 insertions(+), 3482 deletions(-)
 create mode 100644 fs/netfs/buffer.c
 create mode 100644 fs/smb/client/cifstransport.c


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [RFC PATCH 01/31] iov_iter: Move ITER_DISCARD and ITER_XARRAY iteration out-of-line
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 02/31] iov_iter: Add a segmented queue of bio_vec[] David Howells
                   ` (33 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel

Move ITER_DISCARD and ITER_XARRAY iteration out-of-line in preparation of
adding other iteration types which will also be out-of-line.

Signed-off-by: David Howells <dhowells@redhat.com>
---
 include/linux/iov_iter.h | 77 +++-----------------------------------
 lib/iov_iter.c           | 81 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 86 insertions(+), 72 deletions(-)

diff --git a/include/linux/iov_iter.h b/include/linux/iov_iter.h
index c4aa58032faf..0c47933df517 100644
--- a/include/linux/iov_iter.h
+++ b/include/linux/iov_iter.h
@@ -17,6 +17,9 @@ typedef size_t (*iov_step_f)(void *iter_base, size_t progress, size_t len,
 typedef size_t (*iov_ustep_f)(void __user *iter_base, size_t progress, size_t len,
 			      void *priv, void *priv2);
 
+size_t __iterate_and_advance2(struct iov_iter *iter, size_t len, void *priv,
+			      void *priv2, iov_ustep_f ustep, iov_step_f step);
+
 /*
  * Handle ITER_UBUF.
  */
@@ -195,72 +198,6 @@ size_t iterate_folioq(struct iov_iter *iter, size_t len, void *priv, void *priv2
 	return progress;
 }
 
-/*
- * Handle ITER_XARRAY.
- */
-static __always_inline
-size_t iterate_xarray(struct iov_iter *iter, size_t len, void *priv, void *priv2,
-		      iov_step_f step)
-{
-	struct folio *folio;
-	size_t progress = 0;
-	loff_t start = iter->xarray_start + iter->iov_offset;
-	pgoff_t index = start / PAGE_SIZE;
-	XA_STATE(xas, iter->xarray, index);
-
-	rcu_read_lock();
-	xas_for_each(&xas, folio, ULONG_MAX) {
-		size_t remain, consumed, offset, part, flen;
-
-		if (xas_retry(&xas, folio))
-			continue;
-		if (WARN_ON(xa_is_value(folio)))
-			break;
-		if (WARN_ON(folio_test_hugetlb(folio)))
-			break;
-
-		offset = offset_in_folio(folio, start + progress);
-		flen = min(folio_size(folio) - offset, len);
-
-		while (flen) {
-			void *base = kmap_local_folio(folio, offset);
-
-			part = min_t(size_t, flen,
-				     PAGE_SIZE - offset_in_page(offset));
-			remain = step(base, progress, part, priv, priv2);
-			kunmap_local(base);
-
-			consumed = part - remain;
-			progress += consumed;
-			len -= consumed;
-
-			if (remain || len == 0)
-				goto out;
-			flen -= consumed;
-			offset += consumed;
-		}
-	}
-
-out:
-	rcu_read_unlock();
-	iter->iov_offset += progress;
-	iter->count -= progress;
-	return progress;
-}
-
-/*
- * Handle ITER_DISCARD.
- */
-static __always_inline
-size_t iterate_discard(struct iov_iter *iter, size_t len, void *priv, void *priv2,
-		      iov_step_f step)
-{
-	size_t progress = len;
-
-	iter->count -= progress;
-	return progress;
-}
-
 /**
  * iterate_and_advance2 - Iterate over an iterator
  * @iter: The iterator to iterate over.
@@ -306,9 +243,7 @@ size_t iterate_and_advance2(struct iov_iter *iter, size_t len, void *priv,
 		return iterate_kvec(iter, len, priv, priv2, step);
 	if (iov_iter_is_folioq(iter))
 		return iterate_folioq(iter, len, priv, priv2, step);
-	if (iov_iter_is_xarray(iter))
-		return iterate_xarray(iter, len, priv, priv2, step);
-	return iterate_discard(iter, len, priv, priv2, step);
+	return __iterate_and_advance2(iter, len, priv, priv2, ustep, step);
 }
 
 /**
@@ -370,9 +305,7 @@ size_t iterate_and_advance_kernel(struct iov_iter *iter, size_t len, void *priv,
 		return iterate_kvec(iter, len, priv, priv2, step);
 	if (iov_iter_is_folioq(iter))
 		return iterate_folioq(iter, len, priv, priv2, step);
-	if (iov_iter_is_xarray(iter))
-		return iterate_xarray(iter, len, priv, priv2, step);
-	return iterate_discard(iter, len, priv, priv2, step);
+	return __iterate_and_advance2(iter, len, priv, priv2, NULL, step);
 }
 
 #endif /* _LINUX_IOV_ITER_H */
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index f9193f952f49..53e58903fe75 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -1928,3 +1928,84 @@ ssize_t iov_iter_extract_pages(struct iov_iter *i,
 	return -EFAULT;
 }
 EXPORT_SYMBOL_GPL(iov_iter_extract_pages);
+
+/*
+ * Handle ITER_XARRAY.
+ */
+static __always_inline
+size_t iterate_xarray(struct iov_iter *iter, size_t len, void *priv, void *priv2,
+		      iov_step_f step)
+{
+	struct folio *folio;
+	size_t progress = 0;
+	loff_t start = iter->xarray_start + iter->iov_offset;
+	pgoff_t index = start / PAGE_SIZE;
+	XA_STATE(xas, iter->xarray, index);
+
+	rcu_read_lock();
+	xas_for_each(&xas, folio, ULONG_MAX) {
+		size_t remain, consumed, offset, part, flen;
+
+		if (xas_retry(&xas, folio))
+			continue;
+		if (WARN_ON(xa_is_value(folio)))
+			break;
+		if (WARN_ON(folio_test_hugetlb(folio)))
+			break;
+
+		offset = offset_in_folio(folio, start + progress);
+		flen = min(folio_size(folio) - offset, len);
+
+		while (flen) {
+			void *base = kmap_local_folio(folio, offset);
+
+			part = min_t(size_t, flen,
+				     PAGE_SIZE - offset_in_page(offset));
+			remain = step(base, progress, part, priv, priv2);
+			kunmap_local(base);
+
+			consumed = part - remain;
+			progress += consumed;
+			len -= consumed;
+
+			if (remain || len == 0)
+				goto out;
+			flen -= consumed;
+			offset += consumed;
+		}
+	}
+
+out:
+	rcu_read_unlock();
+	iter->iov_offset += progress;
+	iter->count -= progress;
+	return progress;
+}
+
+/*
+ * Handle ITER_DISCARD.
+ */
+static __always_inline
+size_t iterate_discard(struct iov_iter *iter, size_t len, void *priv, void *priv2,
+		      iov_step_f step)
+{
+	size_t progress = len;
+
+	iter->count -= progress;
+	return progress;
+}
+
+/*
+ * Out of line iteration for iterator types that don't need such fast handling.
+ */
+size_t __iterate_and_advance2(struct iov_iter *iter, size_t len, void *priv,
+			      void *priv2, iov_ustep_f ustep, iov_step_f step)
+{
+	if (iov_iter_is_discard(iter))
+		return iterate_discard(iter, len, priv, priv2, step);
+	if (iov_iter_is_xarray(iter))
+		return iterate_xarray(iter, len, priv, priv2, step);
+	WARN_ON(1);
+	return 0;
+}
+EXPORT_SYMBOL(__iterate_and_advance2);


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 02/31] iov_iter: Add a segmented queue of bio_vec[]
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
  2025-08-06 20:36 ` [RFC PATCH 01/31] iov_iter: Move ITER_DISCARD and ITER_XARRAY iteration out-of-line David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 03/31] netfs: Provide facility to alloc buffer in a bvecq David Howells
                   ` (32 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel

Add a segmented queue of bio_vec[].  This allows an indefinite quantity of
elements to be handled.  A rolling buffer can also be implemented over them
where new bio_vecs can be added to the leading edge and spent bio_vecs can
be cleared from the trailing edge.

Signed-off-by: David Howells <dhowells@redhat.com>
---
 include/linux/bvec.h       |  13 ++
 include/linux/uio.h        |  11 ++
 lib/iov_iter.c             | 325 ++++++++++++++++++++++++++++++++++++-
 lib/tests/kunit_iov_iter.c | 196 ++++++++++++++++++++++
 4 files changed, 543 insertions(+), 2 deletions(-)

diff --git a/include/linux/bvec.h b/include/linux/bvec.h
index 0a80e1f9aa20..7986c9019fa0 100644
--- a/include/linux/bvec.h
+++ b/include/linux/bvec.h
@@ -298,4 +298,17 @@ static inline phys_addr_t bvec_phys(const struct bio_vec *bvec)
 	return page_to_phys(bvec->bv_page) + bvec->bv_offset;
 }
 
+/*
+ * Segmented bio_vec queue.  These can be linked together to form messages of
+ * indefinite length and iterated over with an ITER_BVECQ iterator.
+ */
+struct bvecq {
+	struct bvecq	*next;		/* Next bvec in the list or NULL */
+	struct bvecq	*prev;		/* Prev bvec in the list or NULL */
+	u16		max_segs;	/* Number of elements allocated in bv[] */
+	u16		nr_segs;	/* Number of elements in bv[] used */
+	u16		cleared;	/* Number of elements used in bv[] cleared */
+	struct bio_vec	bv[] __counted_by(max_segs);
+};
+
 #endif /* __LINUX_BVEC_H */
diff --git a/include/linux/uio.h b/include/linux/uio.h
index 2e86c653186c..2c04646be91a 100644
--- a/include/linux/uio.h
+++ b/include/linux/uio.h
@@ -27,6 +27,7 @@ enum iter_type {
 	ITER_BVEC,
 	ITER_KVEC,
 	ITER_FOLIOQ,
+	ITER_BVECQ,
 	ITER_XARRAY,
 	ITER_DISCARD,
 };
@@ -69,6 +70,7 @@ struct iov_iter {
 				const struct kvec *kvec;
 				const struct bio_vec *bvec;
 				const struct folio_queue *folioq;
+				const struct bvecq *bvecq;
 				struct xarray *xarray;
 				void __user *ubuf;
 			};
@@ -78,6 +80,7 @@ struct iov_iter {
 	union {
 		unsigned long nr_segs;
 		u8 folioq_slot;
+		u16 bvecq_slot;
 		loff_t xarray_start;
 	};
 };
@@ -150,6 +153,11 @@ static inline bool iov_iter_is_folioq(const struct iov_iter *i)
 	return iov_iter_type(i) == ITER_FOLIOQ;
 }
 
+static inline bool iov_iter_is_bvecq(const struct iov_iter *i)
+{
+	return iov_iter_type(i) == ITER_BVECQ;
+}
+
 static inline bool iov_iter_is_xarray(const struct iov_iter *i)
 {
 	return iov_iter_type(i) == ITER_XARRAY;
@@ -300,6 +308,9 @@ void iov_iter_discard(struct iov_iter *i, unsigned int direction, size_t count);
 void iov_iter_folio_queue(struct iov_iter *i, unsigned int direction,
 			  const struct folio_queue *folioq,
 			  unsigned int first_slot, unsigned int offset, size_t count);
+void iov_iter_bvec_queue(struct iov_iter *i, unsigned int direction,
+			 const struct bvecq *bvecq,
+			 unsigned int first_slot, unsigned int offset, size_t count);
 void iov_iter_xarray(struct iov_iter *i, unsigned int direction, struct xarray *xarray,
 		     loff_t start, size_t count);
 ssize_t iov_iter_get_pages2(struct iov_iter *i, struct page **pages,
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index 53e58903fe75..aefd41f689b7 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -559,6 +559,39 @@ static void iov_iter_folioq_advance(struct iov_iter *i, size_t size)
 	i->folioq = folioq;
 }
 
+static void iov_iter_bvecq_advance(struct iov_iter *i, size_t by)
+{
+	const struct bvecq *bq = i->bvecq;
+	unsigned int slot = i->bvecq_slot;
+
+	if (!i->count)
+		return;
+	i->count -= by;
+
+	if (slot >= bq->nr_segs) {
+		bq = bq->next;
+		slot = 0;
+	}
+
+	by += i->iov_offset; /* From beginning of current segment. */
+	do {
+		size_t len = bq->bv[slot].bv_len;
+
+		if (likely(by < len))
+			break;
+		by -= len;
+		slot++;
+		if (slot >= bq->nr_segs && bq->next) {
+			bq = bq->next;
+			slot = 0;
+		}
+	} while (by);
+
+	i->iov_offset = by;
+	i->bvecq_slot = slot;
+	i->bvecq = bq;
+}
+
 void iov_iter_advance(struct iov_iter *i, size_t size)
 {
 	if (unlikely(i->count < size))
@@ -573,6 +606,8 @@ void iov_iter_advance(struct iov_iter *i, size_t size)
 		iov_iter_bvec_advance(i, size);
 	} else if (iov_iter_is_folioq(i)) {
 		iov_iter_folioq_advance(i, size);
+	} else if (iov_iter_is_bvecq(i)) {
+		iov_iter_bvecq_advance(i, size);
 	} else if (iov_iter_is_discard(i)) {
 		i->count -= size;
 	}
@@ -605,6 +640,32 @@ static void iov_iter_folioq_revert(struct iov_iter *i, size_t unroll)
 	i->folioq = folioq;
 }
 
+static void iov_iter_bvecq_revert(struct iov_iter *i, size_t unroll)
+{
+	const struct bvecq *bq = i->bvecq;
+	unsigned int slot = i->bvecq_slot;
+
+	for (;;) {
+		size_t len;
+
+		if (slot == 0) {
+			bq = bq->prev;
+			slot = bq->nr_segs;
+		}
+		slot--;
+
+		len = bq->bv[slot].bv_len;
+		if (unroll <= len) {
+			i->iov_offset = len - unroll;
+			break;
+		}
+		unroll -= len;
+	}
+
+	i->bvecq_slot = slot;
+	i->bvecq = bq;
+}
+
 void iov_iter_revert(struct iov_iter *i, size_t unroll)
 {
 	if (!unroll)
@@ -639,6 +700,9 @@ void iov_iter_revert(struct iov_iter *i, size_t unroll)
 	} else if (iov_iter_is_folioq(i)) {
 		i->iov_offset = 0;
 		iov_iter_folioq_revert(i, unroll);
+	} else if (iov_iter_is_bvecq(i)) {
+		i->iov_offset = 0;
+		iov_iter_bvecq_revert(i, unroll);
 	} else { /* same logics for iovec and kvec */
 		const struct iovec *iov = iter_iov(i);
 		while (1) {
@@ -666,9 +730,12 @@ size_t iov_iter_single_seg_count(const struct iov_iter *i)
 		if (iov_iter_is_bvec(i))
 			return min(i->count, i->bvec->bv_len - i->iov_offset);
 	}
+	if (!i->count)
+		return 0;
 	if (unlikely(iov_iter_is_folioq(i)))
-		return !i->count ? 0 :
-			umin(folioq_folio_size(i->folioq, i->folioq_slot), i->count);
+		return umin(folioq_folio_size(i->folioq, i->folioq_slot), i->count);
+	if (unlikely(iov_iter_is_bvecq(i)))
+		return min(i->count, i->bvecq->bv[i->bvecq_slot].bv_len - i->iov_offset);
 	return i->count;
 }
 EXPORT_SYMBOL(iov_iter_single_seg_count);
@@ -735,6 +802,35 @@ void iov_iter_folio_queue(struct iov_iter *i, unsigned int direction,
 }
 EXPORT_SYMBOL(iov_iter_folio_queue);
 
+/**
+ * iov_iter_bvec_queue - Initialise an I/O iterator to use a segmented bvec queue
+ * @i: The iterator to initialise.
+ * @direction: The direction of the transfer.
+ * @bvecq: The starting point in the bvec queue.
+ * @first_slot: The first slot in the bvec queue to use
+ * @offset: The offset into the bvec in the first slot to start at
+ * @count: The size of the I/O buffer in bytes.
+ *
+ * Set up an I/O iterator to either draw data out of the buffers attached to an
+ * inode or to inject data into those buffers.  The pages *must* be prevented
+ * from evaporation, either by the caller.
+ */
+void iov_iter_bvec_queue(struct iov_iter *i, unsigned int direction,
+			 const struct bvecq *bvecq, unsigned int first_slot,
+			 unsigned int offset, size_t count)
+{
+	BUG_ON(direction & ~1);
+	*i = (struct iov_iter) {
+		.iter_type	= ITER_BVECQ,
+		.data_source	= direction,
+		.bvecq		= bvecq,
+		.bvecq_slot	= first_slot,
+		.count		= count,
+		.iov_offset	= offset,
+	};
+}
+EXPORT_SYMBOL(iov_iter_bvec_queue);
+
 /**
  * iov_iter_xarray - Initialise an I/O iterator to use the pages in an xarray
  * @i: The iterator to initialise.
@@ -834,6 +930,42 @@ static bool iov_iter_aligned_bvec(const struct iov_iter *i, unsigned addr_mask,
 	return true;
 }
 
+static bool iov_iter_aligned_bvecq(const struct iov_iter *iter, unsigned long addr_mask,
+				   unsigned long len_mask)
+{
+	const struct bvecq *bq = iter->bvecq;
+	unsigned int slot = iter->bvecq_slot;
+	size_t skip = iter->iov_offset;
+	size_t size = iter->count;
+
+	if (slot == bq->nr_segs) {
+		/* The iterator may have been extended. */
+		bq = bq->next;
+		slot = 0;
+	}
+
+	for (;;) {
+		const struct bio_vec *bvec = &bq->bv[slot];
+		size_t part;
+
+		part = umin(bvec->bv_len - skip, size);
+		if (part & len_mask)
+			return false;
+		if ((bvec->bv_offset + skip) & addr_mask)
+			return false;
+		if (part >= size)
+			return true;
+
+		size -= part;
+		skip = 0;
+		slot++;
+		if (slot == bq->nr_segs) {
+			bq++;
+			slot = 0;
+		}
+	}
+}
+
 /**
  * iov_iter_is_aligned() - Check if the addresses and lengths of each segments
  * 	are aligned to the parameters.
@@ -875,6 +1007,9 @@ bool iov_iter_is_aligned(const struct iov_iter *i, unsigned addr_mask,
 			return false;
 	}
 
+	if (iov_iter_is_bvecq(i))
+		return iov_iter_aligned_bvecq(i, addr_mask, len_mask);
+
 	return true;
 }
 EXPORT_SYMBOL_GPL(iov_iter_is_aligned);
@@ -922,6 +1057,40 @@ static unsigned long iov_iter_alignment_bvec(const struct iov_iter *i)
 	return res;
 }
 
+static unsigned long iov_iter_alignment_bvecq(const struct iov_iter *iter)
+{
+	const struct bvecq *bq = iter->bvecq;
+	unsigned long res = 0;
+	unsigned int slot = iter->bvecq_slot;
+	size_t skip = iter->iov_offset;
+	size_t size = iter->count;
+
+	if (slot == bq->nr_segs) {
+		/* The iterator may have been extended. */
+		bq = bq->next;
+		slot = 0;
+	}
+
+	for (;;) {
+		const struct bio_vec *bvec = &bq->bv[slot];
+		size_t part;
+
+		part = umin(bvec->bv_len - skip, size);
+		res |= bvec->bv_offset + skip;
+		res |= part;
+
+		size -= part;
+		skip = 0;
+		slot++;
+		if (slot == bq->nr_segs) {
+			bq++;
+			slot = 0;
+		}
+	}
+
+	return res;
+}
+
 unsigned long iov_iter_alignment(const struct iov_iter *i)
 {
 	if (likely(iter_is_ubuf(i))) {
@@ -941,6 +1110,8 @@ unsigned long iov_iter_alignment(const struct iov_iter *i)
 	/* With both xarray and folioq types, we're dealing with whole folios. */
 	if (iov_iter_is_folioq(i))
 		return i->iov_offset | i->count;
+	if (iov_iter_is_bvecq(i))
+		return iov_iter_alignment_bvecq(i);
 	if (iov_iter_is_xarray(i))
 		return (i->xarray_start + i->iov_offset) | i->count;
 
@@ -1275,6 +1446,38 @@ static int bvec_npages(const struct iov_iter *i, int maxpages)
 	return npages;
 }
 
+static size_t iov_npages_bvecq(const struct iov_iter *iter, size_t maxpages)
+{
+	const struct bvecq *bq = iter->bvecq;
+	unsigned int slot = iter->bvecq_slot;
+	size_t npages = 0;
+	size_t skip = iter->iov_offset;
+	size_t size = iter->count;
+
+	if (slot == bq->nr_segs) {
+		/* The iterator may have been extended. */
+		bq = bq->next;
+		slot = 0;
+	}
+
+	do {
+		const struct bio_vec *bvec = &bq->bv[slot];
+		size_t offs = (bvec->bv_offset + skip) % PAGE_SIZE;
+		size_t part = umin(bvec->bv_len - skip, size);
+
+		npages += DIV_ROUND_UP(offs + part, PAGE_SIZE);
+
+		size -= part;
+		skip = 0;
+		slot++;
+		if (slot == bq->nr_segs) {
+			bq++;
+			slot = 0;
+		}
+	} while (npages > maxpages);
+	return umin(npages, maxpages);
+}
+
 int iov_iter_npages(const struct iov_iter *i, int maxpages)
 {
 	if (unlikely(!i->count))
@@ -1294,6 +1497,8 @@ int iov_iter_npages(const struct iov_iter *i, int maxpages)
 		int npages = DIV_ROUND_UP(offset + i->count, PAGE_SIZE);
 		return min(npages, maxpages);
 	}
+	if (iov_iter_is_bvecq(i))
+		return iov_npages_bvecq(i, maxpages);
 	if (iov_iter_is_xarray(i)) {
 		unsigned offset = (i->xarray_start + i->iov_offset) % PAGE_SIZE;
 		int npages = DIV_ROUND_UP(offset + i->count, PAGE_SIZE);
@@ -1637,6 +1842,65 @@ static ssize_t iov_iter_extract_folioq_pages(struct iov_iter *i,
 	return extracted;
 }
 
+/*
+ * Extract a list of virtually contiguous pages from an ITER_BVECQ iterator.
+ * This does not get references on the pages, nor does it get a pin on them.
+ */
+static ssize_t iov_iter_extract_bvecq_pages(struct iov_iter *i,
+					    struct page ***pages, size_t maxsize,
+					    unsigned int maxpages,
+					    iov_iter_extraction_t extraction_flags,
+					    size_t *offset0)
+{
+	const struct bvecq *bq = i->bvecq;
+	struct bvec_iter bi;
+	size_t size = 0;
+	int k = 0;
+
+	bi.bi_idx	= i->bvecq_slot;
+	bi.bi_size	= maxsize;
+	bi.bi_bvec_done	= i->iov_offset;
+
+	maxpages = want_pages_array(pages, maxsize, i->iov_offset, maxpages);
+
+	while (bi.bi_size && bi.bi_idx < bq->nr_segs) {
+		struct bio_vec bv = bvec_iter_bvec(bq->bv, bi);
+
+		/*
+		 * The iov_iter_extract_pages interface only allows an offset
+		 * into the first page.  Break out of the loop if we see an
+		 * offset into subsequent pages, the caller will have to call
+		 * iov_iter_extract_pages again for the reminder.
+		 */
+		if (k) {
+			if (bv.bv_offset)
+				break;
+		} else {
+			*offset0 = bv.bv_offset;
+		}
+
+		(*pages)[k++] = bv.bv_page;
+		size += bv.bv_len;
+
+		if (k >= maxpages)
+			break;
+
+		/*
+		 * We are done when the end of the bvec doesn't align to a page
+		 * boundary as that would create a hole in the returned space.
+		 * The caller will handle this with another call to
+		 * iov_iter_extract_pages.
+		 */
+		if (bv.bv_offset + bv.bv_len != PAGE_SIZE)
+			break;
+
+		bvec_iter_advance_single(bq->bv, &bi, bv.bv_len);
+	}
+
+	iov_iter_advance(i, size);
+	return size;
+}
+
 /*
  * Extract a list of contiguous pages from an ITER_XARRAY iterator.  This does not
  * get references on the pages, nor does it get a pin on them.
@@ -1921,6 +2185,10 @@ ssize_t iov_iter_extract_pages(struct iov_iter *i,
 		return iov_iter_extract_folioq_pages(i, pages, maxsize,
 						     maxpages, extraction_flags,
 						     offset0);
+	if (iov_iter_is_bvecq(i))
+		return iov_iter_extract_bvecq_pages(i, pages, maxsize,
+						    maxpages, extraction_flags,
+						    offset0);
 	if (iov_iter_is_xarray(i))
 		return iov_iter_extract_xarray_pages(i, pages, maxsize,
 						     maxpages, extraction_flags,
@@ -1995,6 +2263,57 @@ size_t iterate_discard(struct iov_iter *iter, size_t len, void *priv, void *priv
 	return progress;
 }
 
+/*
+ * Handle ITER_BVECQ.
+ */
+static __always_inline
+size_t iterate_bvecq(struct iov_iter *iter, size_t len, void *priv, void *priv2,
+		     iov_step_f step)
+{
+	const struct bvecq *bq = iter->bvecq;
+	unsigned int slot = iter->bvecq_slot;
+	size_t progress = 0, skip = iter->iov_offset;
+
+	if (slot == bq->nr_segs) {
+		/* The iterator may have been extended. */
+		bq = bq->next;
+		slot = 0;
+	}
+
+	do {
+		const struct bio_vec *bvec = &bq->bv[slot];
+		struct page *page = bvec->bv_page + (bvec->bv_offset + skip) / PAGE_SIZE;
+		size_t part, remain, consumed;
+		size_t poff = (bvec->bv_offset + skip) % PAGE_SIZE;
+		void *base;
+
+		part = umin(umin(bvec->bv_len, PAGE_SIZE - poff), len);
+		base = kmap_local_page(page) + poff;
+		remain = step(base, progress, part, priv, priv2);
+		kunmap_local(base);
+		consumed = part - remain;
+		len -= consumed;
+		progress += consumed;
+		skip += consumed;
+		if (skip >= bvec->bv_len) {
+			skip = 0;
+			slot++;
+			if (slot == bq->nr_segs) {
+				bq = bq->next;
+				slot = 0;
+			}
+		}
+		if (remain)
+			break;
+	} while (len);
+
+	iter->bvecq_slot = slot;
+	iter->bvecq = bq;
+	iter->iov_offset = skip;
+	iter->count -= progress;
+	return progress;
+}
+
 /*
  * Out of line iteration for iterator types that don't need such fast handling.
  */
@@ -2003,6 +2322,8 @@ size_t __iterate_and_advance2(struct iov_iter *iter, size_t len, void *priv,
 {
 	if (iov_iter_is_discard(iter))
 		return iterate_discard(iter, len, priv, priv2, step);
+	if (iov_iter_is_bvecq(iter))
+		return iterate_bvecq(iter, len, priv, priv2, step);
 	if (iov_iter_is_xarray(iter))
 		return iterate_xarray(iter, len, priv, priv2, step);
 	WARN_ON(1);
diff --git a/lib/tests/kunit_iov_iter.c b/lib/tests/kunit_iov_iter.c
index 48342736d016..4c62b509c949 100644
--- a/lib/tests/kunit_iov_iter.c
+++ b/lib/tests/kunit_iov_iter.c
@@ -536,6 +536,200 @@ static void __init iov_kunit_copy_from_folioq(struct kunit *test)
 	KUNIT_SUCCEED(test);
 }
 
+static void iov_kunit_destroy_bvecq(void *data)
+{
+	struct bvecq *bq, *next;
+
+	for (bq = data; bq; bq = next) {
+		next = bq->next;
+		for (int i = 0; i < bq->nr_segs; i++)
+			if (bq->bv[i].bv_page)
+				put_page(bq->bv[i].bv_page);
+		kfree(bq);
+	}
+}
+
+static struct bvecq *iov_kunit_alloc_bvecq(struct kunit *test, unsigned int max_segs)
+{
+	struct bvecq *bq;
+
+	bq = kzalloc(struct_size(bq, bv, max_segs), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bq);
+	bq->max_segs = max_segs;
+	return bq;
+}
+
+static struct bvecq *iov_kunit_create_bvecq(struct kunit *test, unsigned int max_segs)
+{
+	struct bvecq *bq;
+
+	bq = iov_kunit_alloc_bvecq(test, max_segs);
+	kunit_add_action_or_reset(test, iov_kunit_destroy_bvecq, bq);
+	return bq;
+}
+
+static void __init iov_kunit_load_bvecq(struct kunit *test,
+					struct iov_iter *iter, int dir,
+					struct bvecq *bq_head,
+					struct page **pages, size_t npages)
+{
+	struct bvecq *bq = bq_head;
+	size_t size = 0;
+
+	for (int i = 0; i < npages; i++) {
+		if (bq->nr_segs >= bq->max_segs) {
+			bq->next = iov_kunit_alloc_bvecq(test, 8);
+			bq->next->prev = bq;
+			bq = bq->next;
+		}
+		bvec_set_page(&bq->bv[bq->nr_segs], pages[i], PAGE_SIZE, 0);
+		bq->nr_segs++;
+		size += PAGE_SIZE;
+	}
+	iov_iter_bvec_queue(iter, dir, bq_head, 0, 0, size);
+}
+
+#if 0
+static void dump_bvecq(const struct bvecq *bq)
+{
+	int j = 0;
+
+	printk("Dump:\n");
+	for (; bq; bq = bq->next, j++) {
+		for (int i = 0; i < bq->nr_segs; i++) {
+			const struct bio_vec *bv = &bq->bv[i];
+
+			printk("  [%x:%02x] %lx %04x %04x\n",
+			       j, i, page_to_pfn(bv->bv_page), bv->bv_offset, bv->bv_len);
+		}
+	}
+}
+#endif
+
+/*
+ * Test copying to a ITER_BVECQ-type iterator.
+ */
+static void __init iov_kunit_copy_to_bvecq(struct kunit *test)
+{
+	const struct kvec_test_range *pr;
+	struct iov_iter iter;
+	struct bvecq *bq;
+	struct page **spages, **bpages;
+	u8 *scratch, *buffer;
+	size_t bufsize, npages, size, copied;
+	int i, patt;
+
+	bufsize = 0x100000;
+	npages = bufsize / PAGE_SIZE;
+
+	bq = iov_kunit_create_bvecq(test, 8);
+
+	scratch = iov_kunit_create_buffer(test, &spages, npages);
+	for (i = 0; i < bufsize; i++)
+		scratch[i] = pattern(i);
+
+	buffer = iov_kunit_create_buffer(test, &bpages, npages);
+	memset(buffer, 0, bufsize);
+
+	iov_kunit_load_bvecq(test, &iter, READ, bq, bpages, npages);
+
+	i = 0;
+	for (pr = kvec_test_ranges; pr->from >= 0; pr++) {
+		size = pr->to - pr->from;
+		KUNIT_ASSERT_LE(test, pr->to, bufsize);
+
+		iov_iter_bvec_queue(&iter, READ, bq, 0, 0, pr->to);
+		iov_iter_advance(&iter, pr->from);
+		copied = copy_to_iter(scratch + i, size, &iter);
+
+		KUNIT_EXPECT_EQ(test, copied, size);
+		KUNIT_EXPECT_EQ(test, iter.count, 0);
+		i += size;
+		if (test->status == KUNIT_FAILURE)
+			goto stop;
+	}
+
+	/* Build the expected image in the scratch buffer. */
+	patt = 0;
+	memset(scratch, 0, bufsize);
+	for (pr = kvec_test_ranges; pr->from >= 0; pr++)
+		for (i = pr->from; i < pr->to; i++)
+			scratch[i] = pattern(patt++);
+
+	/* Compare the images */
+	for (i = 0; i < bufsize; i++) {
+		KUNIT_EXPECT_EQ_MSG(test, buffer[i], scratch[i], "at i=%x", i);
+		if (buffer[i] != scratch[i])
+			return;
+	}
+
+stop:
+	KUNIT_SUCCEED(test);
+}
+
+/*
+ * Test copying from a ITER_BVECQ-type iterator.
+ */
+static void __init iov_kunit_copy_from_bvecq(struct kunit *test)
+{
+	const struct kvec_test_range *pr;
+	struct iov_iter iter;
+	struct bvecq *bq;
+	struct page **spages, **bpages;
+	u8 *scratch, *buffer;
+	size_t bufsize, npages, size, copied;
+	int i, j;
+
+	bufsize = 0x100000;
+	npages = bufsize / PAGE_SIZE;
+
+	bq = iov_kunit_create_bvecq(test, 8);
+
+	buffer = iov_kunit_create_buffer(test, &bpages, npages);
+	for (i = 0; i < bufsize; i++)
+		buffer[i] = pattern(i);
+
+	scratch = iov_kunit_create_buffer(test, &spages, npages);
+	memset(scratch, 0, bufsize);
+
+	iov_kunit_load_bvecq(test, &iter, READ, bq, bpages, npages);
+
+	i = 0;
+	for (pr = kvec_test_ranges; pr->from >= 0; pr++) {
+		size = pr->to - pr->from;
+		KUNIT_ASSERT_LE(test, pr->to, bufsize);
+
+		iov_iter_bvec_queue(&iter, WRITE, bq, 0, 0, pr->to);
+		iov_iter_advance(&iter, pr->from);
+		copied = copy_from_iter(scratch + i, size, &iter);
+
+		KUNIT_EXPECT_EQ(test, copied, size);
+		KUNIT_EXPECT_EQ(test, iter.count, 0);
+		i += size;
+	}
+
+	/* Build the expected image in the main buffer. */
+	i = 0;
+	memset(buffer, 0, bufsize);
+	for (pr = kvec_test_ranges; pr->from >= 0; pr++) {
+		for (j = pr->from; j < pr->to; j++) {
+			buffer[i++] = pattern(j);
+			if (i >= bufsize)
+				goto stop;
+		}
+	}
+stop:
+
+	/* Compare the images */
+	for (i = 0; i < bufsize; i++) {
+		KUNIT_EXPECT_EQ_MSG(test, scratch[i], buffer[i], "at i=%x", i);
+		if (scratch[i] != buffer[i])
+			return;
+	}
+
+	KUNIT_SUCCEED(test);
+}
+
 static void iov_kunit_destroy_xarray(void *data)
 {
 	struct xarray *xarray = data;
@@ -1016,6 +1210,8 @@ static struct kunit_case __refdata iov_kunit_cases[] = {
 	KUNIT_CASE(iov_kunit_copy_from_bvec),
 	KUNIT_CASE(iov_kunit_copy_to_folioq),
 	KUNIT_CASE(iov_kunit_copy_from_folioq),
+	KUNIT_CASE(iov_kunit_copy_to_bvecq),
+	KUNIT_CASE(iov_kunit_copy_from_bvecq),
 	KUNIT_CASE(iov_kunit_copy_to_xarray),
 	KUNIT_CASE(iov_kunit_copy_from_xarray),
 	KUNIT_CASE(iov_kunit_extract_pages_kvec),


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 03/31] netfs: Provide facility to alloc buffer in a bvecq
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
  2025-08-06 20:36 ` [RFC PATCH 01/31] iov_iter: Move ITER_DISCARD and ITER_XARRAY iteration out-of-line David Howells
  2025-08-06 20:36 ` [RFC PATCH 02/31] iov_iter: Add a segmented queue of bio_vec[] David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 04/31] cifs, nls: Provide unicode size determination func David Howells
                   ` (31 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Provide facility to allocate a series of bvecq structs and to attach
sufficient pages to that series to provide a buffer for the specified
amount of space.  This can be used to do things like creating an encryption
buffer in cifs and it can then be attached to an ITER_BVECQ iterator and
passed to a socket.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/netfs/Makefile     |   1 +
 fs/netfs/buffer.c     | 101 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/netfs.h |   4 ++
 3 files changed, 106 insertions(+)
 create mode 100644 fs/netfs/buffer.c

diff --git a/fs/netfs/Makefile b/fs/netfs/Makefile
index b43188d64bd8..afab6603bd98 100644
--- a/fs/netfs/Makefile
+++ b/fs/netfs/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
 netfs-y := \
+	buffer.o \
 	buffered_read.o \
 	buffered_write.o \
 	direct_read.o \
diff --git a/fs/netfs/buffer.c b/fs/netfs/buffer.c
new file mode 100644
index 000000000000..1e4ed2746e95
--- /dev/null
+++ b/fs/netfs/buffer.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Buffering helpers for bvec_queues
+ *
+ * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+#include "internal.h"
+
+void dump_bvecq(const struct bvecq *bq)
+{
+	int b = 0;
+
+	for (; bq; bq = bq->next, b++) {
+		printk("BQ[%u] %u/%u\n", b, bq->nr_segs, bq->max_segs);
+		for (int s = 0; s < bq->nr_segs; s++) {
+			const struct bio_vec *bv = &bq->bv[s];
+			printk("BQ[%u:%u] %10lx %04x %04x %u\n",
+			       b, s,
+			       bv->bv_page ? page_to_pfn(bv->bv_page) : 0,
+			       bv->bv_offset, bv->bv_len,
+			       page_count(bv->bv_page));
+		}
+	}
+}
+
+/**
+ * netfs_alloc_bvecq_buffer - Allocate buffer space into a bvec queue
+ * @size: Target size of the buffer.
+ * @pre_slots: Number of preamble slots to set aside
+ * @gfp: The allocation constraints.
+ */
+struct bvecq *netfs_alloc_bvecq_buffer(size_t size, unsigned int pre_slots, gfp_t gfp)
+{
+	struct bvecq *head = NULL, *tail = NULL, *p = NULL;
+	size_t count = DIV_ROUND_UP(size, PAGE_SIZE);
+	int max_segs = 32;
+
+	_enter("%zx,%zx,%u", size, count, pre_slots);
+
+	do {
+		struct page **pages;
+		int want, got;
+
+		p = kzalloc(struct_size(p, bv, max_segs), gfp);
+		if (!p)
+			goto oom;
+		if (tail) {
+			tail->next = p;
+			p->prev = tail;
+		} else {
+			head = p;
+		}
+		tail = p;
+		pages = (struct page **)&p->bv[max_segs];
+		pages -= max_segs - pre_slots;
+
+		want = umin(count, max_segs - pre_slots);
+		got = alloc_pages_bulk(gfp, want, pages);
+		if (got < want) {
+			for (int i = 0; i < got; i++)
+				__free_page(pages[i]);
+			goto oom;
+		}
+
+		tail->max_segs = max_segs;
+		tail->nr_segs = pre_slots + got;
+		for (int i = 0; i < got; i++) {
+			int j = pre_slots + i;
+			set_page_count(pages[i], 1);
+			bvec_set_page(&tail->bv[j], pages[i], PAGE_SIZE, 0);
+		}
+
+		count -= got;
+		pre_slots = 0;
+	} while (count > 0);
+
+	return head;
+oom:
+	netfs_free_bvecq_buffer(head);
+	return NULL;
+}
+EXPORT_SYMBOL(netfs_alloc_bvecq_buffer);
+
+/**
+ * netfs_free_bvecq_buffer - Free a bvec queue
+ * @bq: The start of the folio queue to free
+ *
+ * Free up a chain of bvecqs and the pages it points to.
+ */
+void netfs_free_bvecq_buffer(struct bvecq *bq)
+{
+	struct bvecq *next;
+
+	for (; bq; bq = next) {
+		for (int seg = 0; seg < bq->nr_segs; seg++)
+			__free_page(bq->bv[seg].bv_page);
+		next = bq->next;
+		kfree(bq);
+	}
+}
+EXPORT_SYMBOL(netfs_free_bvecq_buffer);
diff --git a/include/linux/netfs.h b/include/linux/netfs.h
index f43f075852c0..8756129b7472 100644
--- a/include/linux/netfs.h
+++ b/include/linux/netfs.h
@@ -23,6 +23,7 @@
 enum netfs_sreq_ref_trace;
 typedef struct mempool_s mempool_t;
 struct folio_queue;
+struct bvecq;
 
 /**
  * folio_start_private_2 - Start an fscache write on a folio.  [DEPRECATED]
@@ -462,6 +463,9 @@ int netfs_alloc_folioq_buffer(struct address_space *mapping,
 			      struct folio_queue **_buffer,
 			      size_t *_cur_size, ssize_t size, gfp_t gfp);
 void netfs_free_folioq_buffer(struct folio_queue *fq);
+void dump_bvecq(const struct bvecq *bq);
+struct bvecq *netfs_alloc_bvecq_buffer(size_t size, unsigned int pre_slots, gfp_t gfp);
+void netfs_free_bvecq_buffer(struct bvecq *bq);
 
 /**
  * netfs_inode - Get the netfs inode context from the inode


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 04/31] cifs, nls: Provide unicode size determination func
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (2 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 03/31] netfs: Provide facility to alloc buffer in a bvecq David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 05/31] cifs: Introduce an ALIGN8() macro David Howells
                   ` (30 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/nls/nls_base.c            | 33 ++++++++++++++++++++++++++++++
 fs/smb/client/cifs_unicode.c | 39 ++++++++++++++++++++++++++++++++++++
 fs/smb/client/cifs_unicode.h |  2 ++
 include/linux/nls.h          |  1 +
 4 files changed, 75 insertions(+)

diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c
index 18d597e49a19..f6927c7d9fe1 100644
--- a/fs/nls/nls_base.c
+++ b/fs/nls/nls_base.c
@@ -171,6 +171,39 @@ int utf8s_to_utf16s(const u8 *s, int inlen, enum utf16_endian endian,
 }
 EXPORT_SYMBOL(utf8s_to_utf16s);
 
+/**
+ * utf8s_to_len_utf16s - Determine the length of a conversion of UTF8 to UTF16.
+ * @s: The source utf8 string
+ * @inlen: The length of the string
+ */
+ssize_t utf8s_to_len_utf16s(const u8 *s, int inlen)
+{
+	unicode_t u;
+	size_t outcount = 0;
+	int size;
+
+	while (inlen > 0 && *s) {
+		if (*s & 0x80) {
+			size = utf8_to_utf32(s, inlen, &u);
+			if (size < 0)
+				return -EINVAL;
+			s += size;
+			inlen -= size;
+
+			if (u >= PLANE_SIZE)
+				outcount += 2;
+			else
+				outcount++;
+		} else {
+			s++;
+			outcount++;
+			inlen--;
+		}
+	}
+	return outcount * sizeof(wchar_t);
+}
+EXPORT_SYMBOL(utf8s_to_len_utf16s);
+
 static inline unsigned long get_utf16(unsigned c, enum utf16_endian endian)
 {
 	switch (endian) {
diff --git a/fs/smb/client/cifs_unicode.c b/fs/smb/client/cifs_unicode.c
index 4cc6e0896fad..ba4b361613f6 100644
--- a/fs/smb/client/cifs_unicode.c
+++ b/fs/smb/client/cifs_unicode.c
@@ -290,6 +290,45 @@ cifs_strtoUTF16(__le16 *to, const char *from, int len,
 	return i;
 }
 
+/*
+ * Work out how long a string will be once converted to UTF16 in bytes.  This
+ * does not include a NUL terminator.
+ */
+size_t cifs_size_strtoUTF16(const char *from, int len,
+			    const struct nls_table *codepage)
+{
+	wchar_t wchar_to; /* needed to quiet sparse */
+	ssize_t out_len = 0;
+	int charlen;
+
+	/* special case for utf8 to handle no plane0 chars */
+	if (strcmp(codepage->charset, "utf8") == 0) {
+		out_len = utf8s_to_len_utf16s(from, len);
+		if (out_len >= 0)
+			goto success;
+		/*
+		 * On failure, fall back to UCS encoding as this function
+		 * should not return negative values currently can fail only if
+		 * source contains invalid encoded characters
+		 */
+	}
+
+	for (; len && *from; len -= charlen) {
+		charlen = codepage->char2uni(from, len, &wchar_to);
+		if (charlen < 1) {
+			cifs_dbg(VFS, "strtoUTF16: char2uni of 0x%x returned %d\n",
+				 *from, charlen);
+			/* Replace with a question mark */
+			charlen = 1;
+		}
+		from += charlen;
+		out_len += 2;
+	}
+
+success:
+	return out_len;
+}
+
 /*
  * cifs_utf16_bytes - how long will a string be after conversion?
  * @utf16 - pointer to input string
diff --git a/fs/smb/client/cifs_unicode.h b/fs/smb/client/cifs_unicode.h
index e137a0dfbbe9..c3519a46a2b5 100644
--- a/fs/smb/client/cifs_unicode.h
+++ b/fs/smb/client/cifs_unicode.h
@@ -60,6 +60,8 @@ int cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
 int cifs_utf16_bytes(const __le16 *from, int maxbytes,
 		     const struct nls_table *codepage);
 int cifs_strtoUTF16(__le16 *, const char *, int, const struct nls_table *);
+size_t cifs_size_strtoUTF16(const char *from, int len,
+			    const struct nls_table *codepage);
 char *cifs_strndup_from_utf16(const char *src, const int maxlen,
 			      const bool is_unicode,
 			      const struct nls_table *codepage);
diff --git a/include/linux/nls.h b/include/linux/nls.h
index e0bf8367b274..026da1d5ffaa 100644
--- a/include/linux/nls.h
+++ b/include/linux/nls.h
@@ -56,6 +56,7 @@ extern int utf8_to_utf32(const u8 *s, int len, unicode_t *pu);
 extern int utf32_to_utf8(unicode_t u, u8 *s, int maxlen);
 extern int utf8s_to_utf16s(const u8 *s, int len,
 		enum utf16_endian endian, wchar_t *pwcs, int maxlen);
+ssize_t utf8s_to_len_utf16s(const u8 *s, int inlen);
 extern int utf16s_to_utf8s(const wchar_t *pwcs, int len,
 		enum utf16_endian endian, u8 *s, int maxlen);
 


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 05/31] cifs: Introduce an ALIGN8() macro
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (3 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 04/31] cifs, nls: Provide unicode size determination func David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 06/31] cifs: Move the SMB1 transport code out of transport.c David Howells
                   ` (29 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

The PDU generation seems to do ALIGN(x, 8) a lot, so make a macro for that.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/cifsglob.h |  2 ++
 fs/smb/client/reparse.c  |  2 +-
 fs/smb/client/smb2file.c |  2 +-
 fs/smb/client/smb2misc.c |  2 +-
 fs/smb/client/smb2pdu.c  | 28 ++++++++++++++--------------
 5 files changed, 19 insertions(+), 17 deletions(-)

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 89160bc34d35..67c1a63a08ba 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -2375,4 +2375,6 @@ static inline bool cifs_netbios_name(const char *name, size_t namelen)
 	return ret;
 }
 
+#define ALIGN8(x) ALIGN((x), 8)
+
 #endif	/* _CIFS_GLOB_H */
diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
index 5fa29a97ac15..2622f90ebc92 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -571,7 +571,7 @@ static struct smb2_create_ea_ctx *ea_create_context(u32 dlen, size_t *cc_len)
 {
 	struct smb2_create_ea_ctx *cc;
 
-	*cc_len = round_up(sizeof(*cc) + dlen, 8);
+	*cc_len = ALIGN8(sizeof(*cc) + dlen);
 	cc = kzalloc(*cc_len, GFP_KERNEL);
 	if (!cc)
 		return ERR_PTR(-ENOMEM);
diff --git a/fs/smb/client/smb2file.c b/fs/smb/client/smb2file.c
index a7f629238830..1c8fc06cd46f 100644
--- a/fs/smb/client/smb2file.c
+++ b/fs/smb/client/smb2file.c
@@ -48,7 +48,7 @@ static struct smb2_symlink_err_rsp *symlink_data(const struct kvec *iov)
 			cifs_dbg(FYI, "%s: skipping unhandled error context: 0x%x\n",
 				 __func__, le32_to_cpu(p->ErrorId));
 
-			len = ALIGN(le32_to_cpu(p->ErrorDataLength), 8);
+			len = ALIGN8(le32_to_cpu(p->ErrorDataLength));
 			p = (struct smb2_error_context_rsp *)(p->ErrorContextData + len);
 		} while (p < end);
 	} else if (le32_to_cpu(err->ByteCount) >= sizeof(*sym) &&
diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c
index cddf273c14ae..93ce9fc7b4a4 100644
--- a/fs/smb/client/smb2misc.c
+++ b/fs/smb/client/smb2misc.c
@@ -252,7 +252,7 @@ smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *server)
 		 * Some windows servers (win2016) will pad also the final
 		 * PDU in a compound to 8 bytes.
 		 */
-		if (ALIGN(calc_len, 8) == len)
+		if (ALIGN8(calc_len) == len)
 			return 0;
 
 		/*
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 2df93a75e3b8..96df4aa7a7af 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -619,14 +619,14 @@ build_signing_ctxt(struct smb2_signing_capabilities *pneg_ctxt)
 	/*
 	 * Context Data length must be rounded to multiple of 8 for some servers
 	 */
-	pneg_ctxt->DataLength = cpu_to_le16(ALIGN(sizeof(struct smb2_signing_capabilities) -
+	pneg_ctxt->DataLength = cpu_to_le16(ALIGN8(sizeof(struct smb2_signing_capabilities) -
 					    sizeof(struct smb2_neg_context) +
-					    (num_algs * sizeof(u16)), 8));
+					    (num_algs * sizeof(u16))));
 	pneg_ctxt->SigningAlgorithmCount = cpu_to_le16(num_algs);
 	pneg_ctxt->SigningAlgorithms[0] = cpu_to_le16(SIGNING_ALG_AES_CMAC);
 
 	ctxt_len += sizeof(__le16) * num_algs;
-	ctxt_len = ALIGN(ctxt_len, 8);
+	ctxt_len = ALIGN8(ctxt_len);
 	return ctxt_len;
 	/* TBD add SIGNING_ALG_AES_GMAC and/or SIGNING_ALG_HMAC_SHA256 */
 }
@@ -663,7 +663,7 @@ build_netname_ctxt(struct smb2_netname_neg_context *pneg_ctxt, char *hostname)
 	/* copy up to max of first 100 bytes of server name to NetName field */
 	pneg_ctxt->DataLength = cpu_to_le16(2 * cifs_strtoUTF16(pneg_ctxt->NetName, hostname, 100, cp));
 	/* context size is DataLength + minimal smb2_neg_context */
-	return ALIGN(le16_to_cpu(pneg_ctxt->DataLength) + sizeof(struct smb2_neg_context), 8);
+	return ALIGN8(le16_to_cpu(pneg_ctxt->DataLength) + sizeof(struct smb2_neg_context));
 }
 
 static void
@@ -709,18 +709,18 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
 	 * round up total_len of fixed part of SMB3 negotiate request to 8
 	 * byte boundary before adding negotiate contexts
 	 */
-	*total_len = ALIGN(*total_len, 8);
+	*total_len = ALIGN8(*total_len);
 
 	pneg_ctxt = (*total_len) + (char *)req;
 	req->NegotiateContextOffset = cpu_to_le32(*total_len);
 
 	build_preauth_ctxt((struct smb2_preauth_neg_context *)pneg_ctxt);
-	ctxt_len = ALIGN(sizeof(struct smb2_preauth_neg_context), 8);
+	ctxt_len = ALIGN8(sizeof(struct smb2_preauth_neg_context));
 	*total_len += ctxt_len;
 	pneg_ctxt += ctxt_len;
 
 	build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt);
-	ctxt_len = ALIGN(sizeof(struct smb2_encryption_neg_context), 8);
+	ctxt_len = ALIGN8(sizeof(struct smb2_encryption_neg_context));
 	*total_len += ctxt_len;
 	pneg_ctxt += ctxt_len;
 
@@ -749,7 +749,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
 	if (server->compression.requested) {
 		build_compression_ctxt((struct smb2_compression_capabilities_context *)
 				pneg_ctxt);
-		ctxt_len = ALIGN(sizeof(struct smb2_compression_capabilities_context), 8);
+		ctxt_len = ALIGN8(sizeof(struct smb2_compression_capabilities_context));
 		*total_len += ctxt_len;
 		pneg_ctxt += ctxt_len;
 		neg_context_count++;
@@ -940,7 +940,7 @@ static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
 		 * aligned offset following the previous negotiate context.
 		 */
 		if (i + 1 != ctxt_cnt)
-			clen = ALIGN(clen, 8);
+			clen = ALIGN8(clen);
 		if (clen > len_of_ctxts)
 			break;
 
@@ -2631,7 +2631,7 @@ create_sd_buf(umode_t mode, bool set_owner, unsigned int *len)
 	unsigned int group_offset = 0;
 	struct smb3_acl acl = {};
 
-	*len = round_up(sizeof(struct crt_sd_ctxt) + (sizeof(struct smb_ace) * 4), 8);
+	*len = ALIGN8(sizeof(struct crt_sd_ctxt) + (sizeof(struct smb_ace) * 4));
 
 	if (set_owner) {
 		/* sizeof(struct owner_group_sids) is already multiple of 8 so no need to round */
@@ -2706,7 +2706,7 @@ create_sd_buf(umode_t mode, bool set_owner, unsigned int *len)
 	memcpy(aclptr, &acl, sizeof(struct smb3_acl));
 
 	buf->ccontext.DataLength = cpu_to_le32(ptr - (__u8 *)&buf->sd);
-	*len = round_up((unsigned int)(ptr - (__u8 *)buf), 8);
+	*len = ALIGN8((unsigned int)(ptr - (__u8 *)buf));
 
 	return buf;
 }
@@ -2799,7 +2799,7 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len,
 	 * final path needs to be 8-byte aligned as specified in
 	 * MS-SMB2 2.2.13 SMB2 CREATE Request.
 	 */
-	*out_size = round_up(*out_len * sizeof(__le16), 8);
+	*out_size = ALIGN8(*out_len * sizeof(__le16));
 	*out_path = kzalloc(*out_size + sizeof(__le16) /* null */, GFP_KERNEL);
 	if (!*out_path)
 		return -ENOMEM;
@@ -3064,7 +3064,7 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
 		uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2;
 		/* MUST set path len (NameLength) to 0 opening root of share */
 		req->NameLength = cpu_to_le16(uni_path_len - 2);
-		copy_size = round_up(uni_path_len, 8);
+		copy_size = ALIGN8(uni_path_len);
 		copy_path = kzalloc(copy_size, GFP_KERNEL);
 		if (!copy_path)
 			return -ENOMEM;
@@ -4490,7 +4490,7 @@ smb2_new_read_req(void **buf, unsigned int *total_len,
 	if (request_type & CHAINED_REQUEST) {
 		if (!(request_type & END_OF_CHAIN)) {
 			/* next 8-byte aligned request */
-			*total_len = ALIGN(*total_len, 8);
+			*total_len = ALIGN8(*total_len);
 			shdr->NextCommand = cpu_to_le32(*total_len);
 		} else /* END_OF_CHAIN */
 			shdr->NextCommand = 0;


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 06/31] cifs: Move the SMB1 transport code out of transport.c
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (4 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 05/31] cifs: Introduce an ALIGN8() macro David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 07/31] cifs: Rename mid_q_entry to smb_message David Howells
                   ` (28 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/Makefile        |   2 +-
 fs/smb/client/cifsproto.h     |  15 +
 fs/smb/client/cifstransport.c | 566 ++++++++++++++++++++++++++++++++++
 fs/smb/client/transport.c     | 559 +--------------------------------
 4 files changed, 588 insertions(+), 554 deletions(-)
 create mode 100644 fs/smb/client/cifstransport.c

diff --git a/fs/smb/client/Makefile b/fs/smb/client/Makefile
index 22023e30915b..4c97b31a25c2 100644
--- a/fs/smb/client/Makefile
+++ b/fs/smb/client/Makefile
@@ -32,6 +32,6 @@ cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o
 
 cifs-$(CONFIG_CIFS_ROOT) += cifsroot.o
 
-cifs-$(CONFIG_CIFS_ALLOW_INSECURE_LEGACY) += smb1ops.o cifssmb.o
+cifs-$(CONFIG_CIFS_ALLOW_INSECURE_LEGACY) += smb1ops.o cifssmb.o cifstransport.o
 
 cifs-$(CONFIG_CIFS_COMPRESSION) += compress.o compress/lz77.o
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index 045227ed4efc..8661ab105b4f 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -116,16 +116,31 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
 			int * /* bytes returned */ , const int);
 extern int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
 			    char *in_buf, int flags);
+int cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server);
 extern struct mid_q_entry *cifs_setup_request(struct cifs_ses *,
 				struct TCP_Server_Info *,
 				struct smb_rqst *);
 extern struct mid_q_entry *cifs_setup_async_request(struct TCP_Server_Info *,
 						struct smb_rqst *);
+int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
+		    struct smb_rqst *rqst);
 extern int cifs_check_receive(struct mid_q_entry *mid,
 			struct TCP_Server_Info *server, bool log_error);
+int wait_for_free_request(struct TCP_Server_Info *server, const int flags,
+			  unsigned int *instance);
 extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server,
 				 size_t size, size_t *num,
 				 struct cifs_credits *credits);
+
+static inline int
+send_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
+	    struct mid_q_entry *mid)
+{
+	return server->ops->send_cancel ?
+				server->ops->send_cancel(server, rqst, mid) : 0;
+}
+
+int wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ);
 extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
 			struct kvec *, int /* nvec to send */,
 			int * /* type of buf returned */, const int flags,
diff --git a/fs/smb/client/cifstransport.c b/fs/smb/client/cifstransport.c
new file mode 100644
index 000000000000..241e0b427357
--- /dev/null
+++ b/fs/smb/client/cifstransport.c
@@ -0,0 +1,566 @@
+// SPDX-License-Identifier: LGPL-2.1
+/*
+ *
+ *   Copyright (C) International Business Machines  Corp., 2002,2008
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *   Jeremy Allison (jra@samba.org) 2006.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/gfp.h>
+#include <linux/wait.h>
+#include <linux/net.h>
+#include <linux/delay.h>
+#include <linux/freezer.h>
+#include <linux/tcp.h>
+#include <linux/bvec.h>
+#include <linux/highmem.h>
+#include <linux/uaccess.h>
+#include <linux/processor.h>
+#include <linux/mempool.h>
+#include <linux/sched/signal.h>
+#include <linux/task_io_accounting_ops.h>
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+#include "smb2proto.h"
+#include "smbdirect.h"
+#include "compress.h"
+
+/* Max number of iovectors we can use off the stack when sending requests. */
+#define CIFS_MAX_IOV_SIZE 8
+
+static struct mid_q_entry *
+alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
+{
+	struct mid_q_entry *temp;
+
+	if (server == NULL) {
+		cifs_dbg(VFS, "%s: null TCP session\n", __func__);
+		return NULL;
+	}
+
+	temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
+	memset(temp, 0, sizeof(struct mid_q_entry));
+	kref_init(&temp->refcount);
+	temp->mid = get_mid(smb_buffer);
+	temp->pid = current->pid;
+	temp->command = cpu_to_le16(smb_buffer->Command);
+	cifs_dbg(FYI, "For smb_command %d\n", smb_buffer->Command);
+	/* easier to use jiffies */
+	/* when mid allocated can be before when sent */
+	temp->when_alloc = jiffies;
+	temp->server = server;
+
+	/*
+	 * The default is for the mid to be synchronous, so the
+	 * default callback just wakes up the current task.
+	 */
+	get_task_struct(current);
+	temp->creator = current;
+	temp->callback = cifs_wake_up_task;
+	temp->callback_data = current;
+
+	atomic_inc(&mid_count);
+	temp->mid_state = MID_REQUEST_ALLOCATED;
+	return temp;
+}
+
+int
+smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
+	 unsigned int smb_buf_length)
+{
+	struct kvec iov[2];
+	struct smb_rqst rqst = { .rq_iov = iov,
+				 .rq_nvec = 2 };
+
+	iov[0].iov_base = smb_buffer;
+	iov[0].iov_len = 4;
+	iov[1].iov_base = (char *)smb_buffer + 4;
+	iov[1].iov_len = smb_buf_length;
+
+	return __smb_send_rqst(server, 1, &rqst);
+}
+
+static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
+			struct mid_q_entry **ppmidQ)
+{
+	spin_lock(&ses->ses_lock);
+	if (ses->ses_status == SES_NEW) {
+		if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
+			(in_buf->Command != SMB_COM_NEGOTIATE)) {
+			spin_unlock(&ses->ses_lock);
+			return -EAGAIN;
+		}
+		/* else ok - we are setting up session */
+	}
+
+	if (ses->ses_status == SES_EXITING) {
+		/* check if SMB session is bad because we are setting it up */
+		if (in_buf->Command != SMB_COM_LOGOFF_ANDX) {
+			spin_unlock(&ses->ses_lock);
+			return -EAGAIN;
+		}
+		/* else ok - we are shutting down session */
+	}
+	spin_unlock(&ses->ses_lock);
+
+	*ppmidQ = alloc_mid(in_buf, ses->server);
+	if (*ppmidQ == NULL)
+		return -ENOMEM;
+	spin_lock(&ses->server->mid_lock);
+	list_add_tail(&(*ppmidQ)->qhead, &ses->server->pending_mid_q);
+	spin_unlock(&ses->server->mid_lock);
+	return 0;
+}
+
+struct mid_q_entry *
+cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
+{
+	int rc;
+	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
+	struct mid_q_entry *mid;
+
+	if (rqst->rq_iov[0].iov_len != 4 ||
+	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
+		return ERR_PTR(-EIO);
+
+	/* enable signing if server requires it */
+	if (server->sign)
+		hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+	mid = alloc_mid(hdr, server);
+	if (mid == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	rc = cifs_sign_rqst(rqst, server, &mid->sequence_number);
+	if (rc) {
+		release_mid(mid);
+		return ERR_PTR(rc);
+	}
+
+	return mid;
+}
+
+/*
+ *
+ * Send an SMB Request.  No response info (other than return code)
+ * needs to be parsed.
+ *
+ * flags indicate the type of request buffer and how long to wait
+ * and whether to log NT STATUS code (error) before mapping it to POSIX error
+ *
+ */
+int
+SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
+		 char *in_buf, int flags)
+{
+	int rc;
+	struct kvec iov[1];
+	struct kvec rsp_iov;
+	int resp_buf_type;
+
+	iov[0].iov_base = in_buf;
+	iov[0].iov_len = get_rfc1002_length(in_buf) + 4;
+	flags |= CIFS_NO_RSP_BUF;
+	rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
+	cifs_dbg(NOISY, "SendRcvNoRsp flags %d rc %d\n", flags, rc);
+
+	return rc;
+}
+
+int
+cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
+		   bool log_error)
+{
+	unsigned int len = get_rfc1002_length(mid->resp_buf) + 4;
+
+	dump_smb(mid->resp_buf, min_t(u32, 92, len));
+
+	/* convert the length into a more usable form */
+	if (server->sign) {
+		struct kvec iov[2];
+		int rc = 0;
+		struct smb_rqst rqst = { .rq_iov = iov,
+					 .rq_nvec = 2 };
+
+		iov[0].iov_base = mid->resp_buf;
+		iov[0].iov_len = 4;
+		iov[1].iov_base = (char *)mid->resp_buf + 4;
+		iov[1].iov_len = len - 4;
+		/* FIXME: add code to kill session */
+		rc = cifs_verify_signature(&rqst, server,
+					   mid->sequence_number);
+		if (rc)
+			cifs_server_dbg(VFS, "SMB signature verification returned error = %d\n",
+				 rc);
+	}
+
+	/* BB special case reconnect tid and uid here? */
+	return map_and_check_smb_error(mid, log_error);
+}
+
+struct mid_q_entry *
+cifs_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *ignored,
+		   struct smb_rqst *rqst)
+{
+	int rc;
+	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
+	struct mid_q_entry *mid;
+
+	if (rqst->rq_iov[0].iov_len != 4 ||
+	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
+		return ERR_PTR(-EIO);
+
+	rc = allocate_mid(ses, hdr, &mid);
+	if (rc)
+		return ERR_PTR(rc);
+	rc = cifs_sign_rqst(rqst, ses->server, &mid->sequence_number);
+	if (rc) {
+		delete_mid(mid);
+		return ERR_PTR(rc);
+	}
+	return mid;
+}
+
+int
+SendReceive2(const unsigned int xid, struct cifs_ses *ses,
+	     struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
+	     const int flags, struct kvec *resp_iov)
+{
+	struct smb_rqst rqst;
+	struct kvec s_iov[CIFS_MAX_IOV_SIZE], *new_iov;
+	int rc;
+
+	if (n_vec + 1 > CIFS_MAX_IOV_SIZE) {
+		new_iov = kmalloc_array(n_vec + 1, sizeof(struct kvec),
+					GFP_KERNEL);
+		if (!new_iov) {
+			/* otherwise cifs_send_recv below sets resp_buf_type */
+			*resp_buf_type = CIFS_NO_BUFFER;
+			return -ENOMEM;
+		}
+	} else
+		new_iov = s_iov;
+
+	/* 1st iov is a RFC1001 length followed by the rest of the packet */
+	memcpy(new_iov + 1, iov, (sizeof(struct kvec) * n_vec));
+
+	new_iov[0].iov_base = new_iov[1].iov_base;
+	new_iov[0].iov_len = 4;
+	new_iov[1].iov_base += 4;
+	new_iov[1].iov_len -= 4;
+
+	memset(&rqst, 0, sizeof(struct smb_rqst));
+	rqst.rq_iov = new_iov;
+	rqst.rq_nvec = n_vec + 1;
+
+	rc = cifs_send_recv(xid, ses, ses->server,
+			    &rqst, resp_buf_type, flags, resp_iov);
+	if (n_vec + 1 > CIFS_MAX_IOV_SIZE)
+		kfree(new_iov);
+	return rc;
+}
+
+int
+SendReceive(const unsigned int xid, struct cifs_ses *ses,
+	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
+	    int *pbytes_returned, const int flags)
+{
+	int rc = 0;
+	struct mid_q_entry *midQ;
+	unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
+	struct kvec iov = { .iov_base = in_buf, .iov_len = len };
+	struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
+	struct cifs_credits credits = { .value = 1, .instance = 0 };
+	struct TCP_Server_Info *server;
+
+	if (ses == NULL) {
+		cifs_dbg(VFS, "Null smb session\n");
+		return -EIO;
+	}
+	server = ses->server;
+	if (server == NULL) {
+		cifs_dbg(VFS, "Null tcp session\n");
+		return -EIO;
+	}
+
+	spin_lock(&server->srv_lock);
+	if (server->tcpStatus == CifsExiting) {
+		spin_unlock(&server->srv_lock);
+		return -ENOENT;
+	}
+	spin_unlock(&server->srv_lock);
+
+	/* Ensure that we do not send more than 50 overlapping requests
+	   to the same server. We may make this configurable later or
+	   use ses->maxReq */
+
+	if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
+		cifs_server_dbg(VFS, "Invalid length, greater than maximum frame, %d\n",
+				len);
+		return -EIO;
+	}
+
+	rc = wait_for_free_request(server, flags, &credits.instance);
+	if (rc)
+		return rc;
+
+	/* make sure that we sign in the same order that we send on this socket
+	   and avoid races inside tcp sendmsg code that could cause corruption
+	   of smb data */
+
+	cifs_server_lock(server);
+
+	rc = allocate_mid(ses, in_buf, &midQ);
+	if (rc) {
+		cifs_server_unlock(server);
+		/* Update # of requests on wire to server */
+		add_credits(server, &credits, 0);
+		return rc;
+	}
+
+	rc = cifs_sign_smb(in_buf, server, &midQ->sequence_number);
+	if (rc) {
+		cifs_server_unlock(server);
+		goto out;
+	}
+
+	midQ->mid_state = MID_REQUEST_SUBMITTED;
+
+	rc = smb_send(server, in_buf, len);
+	cifs_save_when_sent(midQ);
+
+	if (rc < 0)
+		server->sequence_number -= 2;
+
+	cifs_server_unlock(server);
+
+	if (rc < 0)
+		goto out;
+
+	rc = wait_for_response(server, midQ);
+	if (rc != 0) {
+		send_cancel(server, &rqst, midQ);
+		spin_lock(&server->mid_lock);
+		if (midQ->mid_state == MID_REQUEST_SUBMITTED ||
+		    midQ->mid_state == MID_RESPONSE_RECEIVED) {
+			/* no longer considered to be "in-flight" */
+			midQ->callback = release_mid;
+			spin_unlock(&server->mid_lock);
+			add_credits(server, &credits, 0);
+			return rc;
+		}
+		spin_unlock(&server->mid_lock);
+	}
+
+	rc = cifs_sync_mid_result(midQ, server);
+	if (rc != 0) {
+		add_credits(server, &credits, 0);
+		return rc;
+	}
+
+	if (!midQ->resp_buf || !out_buf ||
+	    midQ->mid_state != MID_RESPONSE_READY) {
+		rc = -EIO;
+		cifs_server_dbg(VFS, "Bad MID state?\n");
+		goto out;
+	}
+
+	*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
+	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
+	rc = cifs_check_receive(midQ, server, 0);
+out:
+	delete_mid(midQ);
+	add_credits(server, &credits, 0);
+
+	return rc;
+}
+
+/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
+   blocking lock to return. */
+
+static int
+send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon,
+			struct smb_hdr *in_buf,
+			struct smb_hdr *out_buf)
+{
+	int bytes_returned;
+	struct cifs_ses *ses = tcon->ses;
+	LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
+
+	/* We just modify the current in_buf to change
+	   the type of lock from LOCKING_ANDX_SHARED_LOCK
+	   or LOCKING_ANDX_EXCLUSIVE_LOCK to
+	   LOCKING_ANDX_CANCEL_LOCK. */
+
+	pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
+	pSMB->Timeout = 0;
+	pSMB->hdr.Mid = get_next_mid(ses->server);
+
+	return SendReceive(xid, ses, in_buf, out_buf,
+			&bytes_returned, 0);
+}
+
+int
+SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
+	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
+	    int *pbytes_returned)
+{
+	int rc = 0;
+	int rstart = 0;
+	struct mid_q_entry *midQ;
+	struct cifs_ses *ses;
+	unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
+	struct kvec iov = { .iov_base = in_buf, .iov_len = len };
+	struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
+	unsigned int instance;
+	struct TCP_Server_Info *server;
+
+	if (tcon == NULL || tcon->ses == NULL) {
+		cifs_dbg(VFS, "Null smb session\n");
+		return -EIO;
+	}
+	ses = tcon->ses;
+	server = ses->server;
+
+	if (server == NULL) {
+		cifs_dbg(VFS, "Null tcp session\n");
+		return -EIO;
+	}
+
+	spin_lock(&server->srv_lock);
+	if (server->tcpStatus == CifsExiting) {
+		spin_unlock(&server->srv_lock);
+		return -ENOENT;
+	}
+	spin_unlock(&server->srv_lock);
+
+	/* Ensure that we do not send more than 50 overlapping requests
+	   to the same server. We may make this configurable later or
+	   use ses->maxReq */
+
+	if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
+		cifs_tcon_dbg(VFS, "Invalid length, greater than maximum frame, %d\n",
+			      len);
+		return -EIO;
+	}
+
+	rc = wait_for_free_request(server, CIFS_BLOCKING_OP, &instance);
+	if (rc)
+		return rc;
+
+	/* make sure that we sign in the same order that we send on this socket
+	   and avoid races inside tcp sendmsg code that could cause corruption
+	   of smb data */
+
+	cifs_server_lock(server);
+
+	rc = allocate_mid(ses, in_buf, &midQ);
+	if (rc) {
+		cifs_server_unlock(server);
+		return rc;
+	}
+
+	rc = cifs_sign_smb(in_buf, server, &midQ->sequence_number);
+	if (rc) {
+		delete_mid(midQ);
+		cifs_server_unlock(server);
+		return rc;
+	}
+
+	midQ->mid_state = MID_REQUEST_SUBMITTED;
+	rc = smb_send(server, in_buf, len);
+	cifs_save_when_sent(midQ);
+
+	if (rc < 0)
+		server->sequence_number -= 2;
+
+	cifs_server_unlock(server);
+
+	if (rc < 0) {
+		delete_mid(midQ);
+		return rc;
+	}
+
+	/* Wait for a reply - allow signals to interrupt. */
+	rc = wait_event_interruptible(server->response_q,
+		(!(midQ->mid_state == MID_REQUEST_SUBMITTED ||
+		   midQ->mid_state == MID_RESPONSE_RECEIVED)) ||
+		((server->tcpStatus != CifsGood) &&
+		 (server->tcpStatus != CifsNew)));
+
+	/* Were we interrupted by a signal ? */
+	spin_lock(&server->srv_lock);
+	if ((rc == -ERESTARTSYS) &&
+		(midQ->mid_state == MID_REQUEST_SUBMITTED ||
+		 midQ->mid_state == MID_RESPONSE_RECEIVED) &&
+		((server->tcpStatus == CifsGood) ||
+		 (server->tcpStatus == CifsNew))) {
+		spin_unlock(&server->srv_lock);
+
+		if (in_buf->Command == SMB_COM_TRANSACTION2) {
+			/* POSIX lock. We send a NT_CANCEL SMB to cause the
+			   blocking lock to return. */
+			rc = send_cancel(server, &rqst, midQ);
+			if (rc) {
+				delete_mid(midQ);
+				return rc;
+			}
+		} else {
+			/* Windows lock. We send a LOCKINGX_CANCEL_LOCK
+			   to cause the blocking lock to return. */
+
+			rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
+
+			/* If we get -ENOLCK back the lock may have
+			   already been removed. Don't exit in this case. */
+			if (rc && rc != -ENOLCK) {
+				delete_mid(midQ);
+				return rc;
+			}
+		}
+
+		rc = wait_for_response(server, midQ);
+		if (rc) {
+			send_cancel(server, &rqst, midQ);
+			spin_lock(&server->mid_lock);
+			if (midQ->mid_state == MID_REQUEST_SUBMITTED ||
+			    midQ->mid_state == MID_RESPONSE_RECEIVED) {
+				/* no longer considered to be "in-flight" */
+				midQ->callback = release_mid;
+				spin_unlock(&server->mid_lock);
+				return rc;
+			}
+			spin_unlock(&server->mid_lock);
+		}
+
+		/* We got the response - restart system call. */
+		rstart = 1;
+		spin_lock(&server->srv_lock);
+	}
+	spin_unlock(&server->srv_lock);
+
+	rc = cifs_sync_mid_result(midQ, server);
+	if (rc != 0)
+		return rc;
+
+	/* rcvd frame is ok */
+	if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_READY) {
+		rc = -EIO;
+		cifs_tcon_dbg(VFS, "Bad MID state?\n");
+		goto out;
+	}
+
+	*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
+	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
+	rc = cifs_check_receive(midQ, server, 0);
+out:
+	delete_mid(midQ);
+	if (rstart && rc == -EACCES)
+		return -ERESTARTSYS;
+	return rc;
+}
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index 191783f553ce..68c73e22c3c9 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -30,9 +30,6 @@
 #include "smbdirect.h"
 #include "compress.h"
 
-/* Max number of iovectors we can use off the stack when sending requests. */
-#define CIFS_MAX_IOV_SIZE 8
-
 void
 cifs_wake_up_task(struct mid_q_entry *mid)
 {
@@ -41,42 +38,6 @@ cifs_wake_up_task(struct mid_q_entry *mid)
 	wake_up_process(mid->callback_data);
 }
 
-static struct mid_q_entry *
-alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
-{
-	struct mid_q_entry *temp;
-
-	if (server == NULL) {
-		cifs_dbg(VFS, "%s: null TCP session\n", __func__);
-		return NULL;
-	}
-
-	temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
-	memset(temp, 0, sizeof(struct mid_q_entry));
-	kref_init(&temp->refcount);
-	temp->mid = get_mid(smb_buffer);
-	temp->pid = current->pid;
-	temp->command = cpu_to_le16(smb_buffer->Command);
-	cifs_dbg(FYI, "For smb_command %d\n", smb_buffer->Command);
-	/* easier to use jiffies */
-	/* when mid allocated can be before when sent */
-	temp->when_alloc = jiffies;
-	temp->server = server;
-
-	/*
-	 * The default is for the mid to be synchronous, so the
-	 * default callback just wakes up the current task.
-	 */
-	get_task_struct(current);
-	temp->creator = current;
-	temp->callback = cifs_wake_up_task;
-	temp->callback_data = current;
-
-	atomic_inc(&mid_count);
-	temp->mid_state = MID_REQUEST_ALLOCATED;
-	return temp;
-}
-
 void __release_mid(struct kref *refcount)
 {
 	struct mid_q_entry *midEntry =
@@ -269,9 +230,8 @@ smb_rqst_len(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 	return buflen;
 }
 
-static int
-__smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
-		struct smb_rqst *rqst)
+int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
+		    struct smb_rqst *rqst)
 {
 	int rc;
 	struct kvec *iov;
@@ -456,22 +416,6 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
 	return rc;
 }
 
-int
-smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
-	 unsigned int smb_buf_length)
-{
-	struct kvec iov[2];
-	struct smb_rqst rqst = { .rq_iov = iov,
-				 .rq_nvec = 2 };
-
-	iov[0].iov_base = smb_buffer;
-	iov[0].iov_len = 4;
-	iov[1].iov_base = (char *)smb_buffer + 4;
-	iov[1].iov_len = smb_buf_length;
-
-	return __smb_send_rqst(server, 1, &rqst);
-}
-
 static int
 wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
 		      const int timeout, const int flags,
@@ -626,9 +570,8 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
 	return 0;
 }
 
-static int
-wait_for_free_request(struct TCP_Server_Info *server, const int flags,
-		      unsigned int *instance)
+int wait_for_free_request(struct TCP_Server_Info *server, const int flags,
+			  unsigned int *instance)
 {
 	return wait_for_free_credits(server, 1, -1, flags,
 				     instance);
@@ -690,40 +633,7 @@ cifs_wait_mtu_credits(struct TCP_Server_Info *server, size_t size,
 	return 0;
 }
 
-static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
-			struct mid_q_entry **ppmidQ)
-{
-	spin_lock(&ses->ses_lock);
-	if (ses->ses_status == SES_NEW) {
-		if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
-			(in_buf->Command != SMB_COM_NEGOTIATE)) {
-			spin_unlock(&ses->ses_lock);
-			return -EAGAIN;
-		}
-		/* else ok - we are setting up session */
-	}
-
-	if (ses->ses_status == SES_EXITING) {
-		/* check if SMB session is bad because we are setting it up */
-		if (in_buf->Command != SMB_COM_LOGOFF_ANDX) {
-			spin_unlock(&ses->ses_lock);
-			return -EAGAIN;
-		}
-		/* else ok - we are shutting down session */
-	}
-	spin_unlock(&ses->ses_lock);
-
-	*ppmidQ = alloc_mid(in_buf, ses->server);
-	if (*ppmidQ == NULL)
-		return -ENOMEM;
-	spin_lock(&ses->server->mid_lock);
-	list_add_tail(&(*ppmidQ)->qhead, &ses->server->pending_mid_q);
-	spin_unlock(&ses->server->mid_lock);
-	return 0;
-}
-
-static int
-wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
+int wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
 {
 	int error;
 
@@ -737,34 +647,6 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
 	return 0;
 }
 
-struct mid_q_entry *
-cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
-{
-	int rc;
-	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
-	struct mid_q_entry *mid;
-
-	if (rqst->rq_iov[0].iov_len != 4 ||
-	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
-		return ERR_PTR(-EIO);
-
-	/* enable signing if server requires it */
-	if (server->sign)
-		hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
-
-	mid = alloc_mid(hdr, server);
-	if (mid == NULL)
-		return ERR_PTR(-ENOMEM);
-
-	rc = cifs_sign_rqst(rqst, server, &mid->sequence_number);
-	if (rc) {
-		release_mid(mid);
-		return ERR_PTR(rc);
-	}
-
-	return mid;
-}
-
 /*
  * Send a SMB request and set the callback function in the mid to handle
  * the result. Caller is responsible for dealing with timeouts.
@@ -845,35 +727,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 	return rc;
 }
 
-/*
- *
- * Send an SMB Request.  No response info (other than return code)
- * needs to be parsed.
- *
- * flags indicate the type of request buffer and how long to wait
- * and whether to log NT STATUS code (error) before mapping it to POSIX error
- *
- */
-int
-SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
-		 char *in_buf, int flags)
-{
-	int rc;
-	struct kvec iov[1];
-	struct kvec rsp_iov;
-	int resp_buf_type;
-
-	iov[0].iov_base = in_buf;
-	iov[0].iov_len = get_rfc1002_length(in_buf) + 4;
-	flags |= CIFS_NO_RSP_BUF;
-	rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
-	cifs_dbg(NOISY, "SendRcvNoRsp flags %d rc %d\n", flags, rc);
-
-	return rc;
-}
-
-static int
-cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
+int cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
 {
 	int rc = 0;
 
@@ -915,68 +769,6 @@ cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
 	return rc;
 }
 
-static inline int
-send_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
-	    struct mid_q_entry *mid)
-{
-	return server->ops->send_cancel ?
-				server->ops->send_cancel(server, rqst, mid) : 0;
-}
-
-int
-cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
-		   bool log_error)
-{
-	unsigned int len = get_rfc1002_length(mid->resp_buf) + 4;
-
-	dump_smb(mid->resp_buf, min_t(u32, 92, len));
-
-	/* convert the length into a more usable form */
-	if (server->sign) {
-		struct kvec iov[2];
-		int rc = 0;
-		struct smb_rqst rqst = { .rq_iov = iov,
-					 .rq_nvec = 2 };
-
-		iov[0].iov_base = mid->resp_buf;
-		iov[0].iov_len = 4;
-		iov[1].iov_base = (char *)mid->resp_buf + 4;
-		iov[1].iov_len = len - 4;
-		/* FIXME: add code to kill session */
-		rc = cifs_verify_signature(&rqst, server,
-					   mid->sequence_number);
-		if (rc)
-			cifs_server_dbg(VFS, "SMB signature verification returned error = %d\n",
-				 rc);
-	}
-
-	/* BB special case reconnect tid and uid here? */
-	return map_and_check_smb_error(mid, log_error);
-}
-
-struct mid_q_entry *
-cifs_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *ignored,
-		   struct smb_rqst *rqst)
-{
-	int rc;
-	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
-	struct mid_q_entry *mid;
-
-	if (rqst->rq_iov[0].iov_len != 4 ||
-	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
-		return ERR_PTR(-EIO);
-
-	rc = allocate_mid(ses, hdr, &mid);
-	if (rc)
-		return ERR_PTR(rc);
-	rc = cifs_sign_rqst(rqst, ses->server, &mid->sequence_number);
-	if (rc) {
-		delete_mid(mid);
-		return ERR_PTR(rc);
-	}
-	return mid;
-}
-
 static void
 cifs_compound_callback(struct mid_q_entry *mid)
 {
@@ -1304,345 +1096,6 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
 				  rqst, resp_buf_type, resp_iov);
 }
 
-int
-SendReceive2(const unsigned int xid, struct cifs_ses *ses,
-	     struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
-	     const int flags, struct kvec *resp_iov)
-{
-	struct smb_rqst rqst;
-	struct kvec s_iov[CIFS_MAX_IOV_SIZE], *new_iov;
-	int rc;
-
-	if (n_vec + 1 > CIFS_MAX_IOV_SIZE) {
-		new_iov = kmalloc_array(n_vec + 1, sizeof(struct kvec),
-					GFP_KERNEL);
-		if (!new_iov) {
-			/* otherwise cifs_send_recv below sets resp_buf_type */
-			*resp_buf_type = CIFS_NO_BUFFER;
-			return -ENOMEM;
-		}
-	} else
-		new_iov = s_iov;
-
-	/* 1st iov is a RFC1001 length followed by the rest of the packet */
-	memcpy(new_iov + 1, iov, (sizeof(struct kvec) * n_vec));
-
-	new_iov[0].iov_base = new_iov[1].iov_base;
-	new_iov[0].iov_len = 4;
-	new_iov[1].iov_base += 4;
-	new_iov[1].iov_len -= 4;
-
-	memset(&rqst, 0, sizeof(struct smb_rqst));
-	rqst.rq_iov = new_iov;
-	rqst.rq_nvec = n_vec + 1;
-
-	rc = cifs_send_recv(xid, ses, ses->server,
-			    &rqst, resp_buf_type, flags, resp_iov);
-	if (n_vec + 1 > CIFS_MAX_IOV_SIZE)
-		kfree(new_iov);
-	return rc;
-}
-
-int
-SendReceive(const unsigned int xid, struct cifs_ses *ses,
-	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
-	    int *pbytes_returned, const int flags)
-{
-	int rc = 0;
-	struct mid_q_entry *midQ;
-	unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
-	struct kvec iov = { .iov_base = in_buf, .iov_len = len };
-	struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
-	struct cifs_credits credits = { .value = 1, .instance = 0 };
-	struct TCP_Server_Info *server;
-
-	if (ses == NULL) {
-		cifs_dbg(VFS, "Null smb session\n");
-		return -EIO;
-	}
-	server = ses->server;
-	if (server == NULL) {
-		cifs_dbg(VFS, "Null tcp session\n");
-		return -EIO;
-	}
-
-	spin_lock(&server->srv_lock);
-	if (server->tcpStatus == CifsExiting) {
-		spin_unlock(&server->srv_lock);
-		return -ENOENT;
-	}
-	spin_unlock(&server->srv_lock);
-
-	/* Ensure that we do not send more than 50 overlapping requests
-	   to the same server. We may make this configurable later or
-	   use ses->maxReq */
-
-	if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
-		cifs_server_dbg(VFS, "Invalid length, greater than maximum frame, %d\n",
-				len);
-		return -EIO;
-	}
-
-	rc = wait_for_free_request(server, flags, &credits.instance);
-	if (rc)
-		return rc;
-
-	/* make sure that we sign in the same order that we send on this socket
-	   and avoid races inside tcp sendmsg code that could cause corruption
-	   of smb data */
-
-	cifs_server_lock(server);
-
-	rc = allocate_mid(ses, in_buf, &midQ);
-	if (rc) {
-		cifs_server_unlock(server);
-		/* Update # of requests on wire to server */
-		add_credits(server, &credits, 0);
-		return rc;
-	}
-
-	rc = cifs_sign_smb(in_buf, server, &midQ->sequence_number);
-	if (rc) {
-		cifs_server_unlock(server);
-		goto out;
-	}
-
-	midQ->mid_state = MID_REQUEST_SUBMITTED;
-
-	rc = smb_send(server, in_buf, len);
-	cifs_save_when_sent(midQ);
-
-	if (rc < 0)
-		server->sequence_number -= 2;
-
-	cifs_server_unlock(server);
-
-	if (rc < 0)
-		goto out;
-
-	rc = wait_for_response(server, midQ);
-	if (rc != 0) {
-		send_cancel(server, &rqst, midQ);
-		spin_lock(&server->mid_lock);
-		if (midQ->mid_state == MID_REQUEST_SUBMITTED ||
-		    midQ->mid_state == MID_RESPONSE_RECEIVED) {
-			/* no longer considered to be "in-flight" */
-			midQ->callback = release_mid;
-			spin_unlock(&server->mid_lock);
-			add_credits(server, &credits, 0);
-			return rc;
-		}
-		spin_unlock(&server->mid_lock);
-	}
-
-	rc = cifs_sync_mid_result(midQ, server);
-	if (rc != 0) {
-		add_credits(server, &credits, 0);
-		return rc;
-	}
-
-	if (!midQ->resp_buf || !out_buf ||
-	    midQ->mid_state != MID_RESPONSE_READY) {
-		rc = -EIO;
-		cifs_server_dbg(VFS, "Bad MID state?\n");
-		goto out;
-	}
-
-	*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
-	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
-	rc = cifs_check_receive(midQ, server, 0);
-out:
-	delete_mid(midQ);
-	add_credits(server, &credits, 0);
-
-	return rc;
-}
-
-/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
-   blocking lock to return. */
-
-static int
-send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon,
-			struct smb_hdr *in_buf,
-			struct smb_hdr *out_buf)
-{
-	int bytes_returned;
-	struct cifs_ses *ses = tcon->ses;
-	LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
-
-	/* We just modify the current in_buf to change
-	   the type of lock from LOCKING_ANDX_SHARED_LOCK
-	   or LOCKING_ANDX_EXCLUSIVE_LOCK to
-	   LOCKING_ANDX_CANCEL_LOCK. */
-
-	pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
-	pSMB->Timeout = 0;
-	pSMB->hdr.Mid = get_next_mid(ses->server);
-
-	return SendReceive(xid, ses, in_buf, out_buf,
-			&bytes_returned, 0);
-}
-
-int
-SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
-	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
-	    int *pbytes_returned)
-{
-	int rc = 0;
-	int rstart = 0;
-	struct mid_q_entry *midQ;
-	struct cifs_ses *ses;
-	unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
-	struct kvec iov = { .iov_base = in_buf, .iov_len = len };
-	struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
-	unsigned int instance;
-	struct TCP_Server_Info *server;
-
-	if (tcon == NULL || tcon->ses == NULL) {
-		cifs_dbg(VFS, "Null smb session\n");
-		return -EIO;
-	}
-	ses = tcon->ses;
-	server = ses->server;
-
-	if (server == NULL) {
-		cifs_dbg(VFS, "Null tcp session\n");
-		return -EIO;
-	}
-
-	spin_lock(&server->srv_lock);
-	if (server->tcpStatus == CifsExiting) {
-		spin_unlock(&server->srv_lock);
-		return -ENOENT;
-	}
-	spin_unlock(&server->srv_lock);
-
-	/* Ensure that we do not send more than 50 overlapping requests
-	   to the same server. We may make this configurable later or
-	   use ses->maxReq */
-
-	if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
-		cifs_tcon_dbg(VFS, "Invalid length, greater than maximum frame, %d\n",
-			      len);
-		return -EIO;
-	}
-
-	rc = wait_for_free_request(server, CIFS_BLOCKING_OP, &instance);
-	if (rc)
-		return rc;
-
-	/* make sure that we sign in the same order that we send on this socket
-	   and avoid races inside tcp sendmsg code that could cause corruption
-	   of smb data */
-
-	cifs_server_lock(server);
-
-	rc = allocate_mid(ses, in_buf, &midQ);
-	if (rc) {
-		cifs_server_unlock(server);
-		return rc;
-	}
-
-	rc = cifs_sign_smb(in_buf, server, &midQ->sequence_number);
-	if (rc) {
-		delete_mid(midQ);
-		cifs_server_unlock(server);
-		return rc;
-	}
-
-	midQ->mid_state = MID_REQUEST_SUBMITTED;
-	rc = smb_send(server, in_buf, len);
-	cifs_save_when_sent(midQ);
-
-	if (rc < 0)
-		server->sequence_number -= 2;
-
-	cifs_server_unlock(server);
-
-	if (rc < 0) {
-		delete_mid(midQ);
-		return rc;
-	}
-
-	/* Wait for a reply - allow signals to interrupt. */
-	rc = wait_event_interruptible(server->response_q,
-		(!(midQ->mid_state == MID_REQUEST_SUBMITTED ||
-		   midQ->mid_state == MID_RESPONSE_RECEIVED)) ||
-		((server->tcpStatus != CifsGood) &&
-		 (server->tcpStatus != CifsNew)));
-
-	/* Were we interrupted by a signal ? */
-	spin_lock(&server->srv_lock);
-	if ((rc == -ERESTARTSYS) &&
-		(midQ->mid_state == MID_REQUEST_SUBMITTED ||
-		 midQ->mid_state == MID_RESPONSE_RECEIVED) &&
-		((server->tcpStatus == CifsGood) ||
-		 (server->tcpStatus == CifsNew))) {
-		spin_unlock(&server->srv_lock);
-
-		if (in_buf->Command == SMB_COM_TRANSACTION2) {
-			/* POSIX lock. We send a NT_CANCEL SMB to cause the
-			   blocking lock to return. */
-			rc = send_cancel(server, &rqst, midQ);
-			if (rc) {
-				delete_mid(midQ);
-				return rc;
-			}
-		} else {
-			/* Windows lock. We send a LOCKINGX_CANCEL_LOCK
-			   to cause the blocking lock to return. */
-
-			rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
-
-			/* If we get -ENOLCK back the lock may have
-			   already been removed. Don't exit in this case. */
-			if (rc && rc != -ENOLCK) {
-				delete_mid(midQ);
-				return rc;
-			}
-		}
-
-		rc = wait_for_response(server, midQ);
-		if (rc) {
-			send_cancel(server, &rqst, midQ);
-			spin_lock(&server->mid_lock);
-			if (midQ->mid_state == MID_REQUEST_SUBMITTED ||
-			    midQ->mid_state == MID_RESPONSE_RECEIVED) {
-				/* no longer considered to be "in-flight" */
-				midQ->callback = release_mid;
-				spin_unlock(&server->mid_lock);
-				return rc;
-			}
-			spin_unlock(&server->mid_lock);
-		}
-
-		/* We got the response - restart system call. */
-		rstart = 1;
-		spin_lock(&server->srv_lock);
-	}
-	spin_unlock(&server->srv_lock);
-
-	rc = cifs_sync_mid_result(midQ, server);
-	if (rc != 0)
-		return rc;
-
-	/* rcvd frame is ok */
-	if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_READY) {
-		rc = -EIO;
-		cifs_tcon_dbg(VFS, "Bad MID state?\n");
-		goto out;
-	}
-
-	*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
-	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
-	rc = cifs_check_receive(midQ, server, 0);
-out:
-	delete_mid(midQ);
-	if (rstart && rc == -EACCES)
-		return -ERESTARTSYS;
-	return rc;
-}
-
 /*
  * Discard any remaining data in the current SMB. To do this, we borrow the
  * current bigbuf.


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 07/31] cifs: Rename mid_q_entry to smb_message
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (5 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 06/31] cifs: Move the SMB1 transport code out of transport.c David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 08/31] cifs: Keep the CPU-endian command ID around David Howells
                   ` (27 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/cifs_debug.c    |  14 +-
 fs/smb/client/cifsfs.c        |  31 +++--
 fs/smb/client/cifsglob.h      |  48 +++----
 fs/smb/client/cifsproto.h     |  34 ++---
 fs/smb/client/cifssmb.c       |  82 ++++++------
 fs/smb/client/cifstransport.c | 156 +++++++++++-----------
 fs/smb/client/connect.c       | 152 +++++++++++-----------
 fs/smb/client/netmisc.c       |  14 +-
 fs/smb/client/smb1ops.c       |  46 +++----
 fs/smb/client/smb2misc.c      |   8 +-
 fs/smb/client/smb2ops.c       | 122 +++++++++---------
 fs/smb/client/smb2pdu.c       |  47 ++++---
 fs/smb/client/smb2proto.h     |  10 +-
 fs/smb/client/smb2transport.c |  60 ++++-----
 fs/smb/client/transport.c     | 235 +++++++++++++++++-----------------
 15 files changed, 529 insertions(+), 530 deletions(-)

diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c
index 3fdf75737d43..163e8954b940 100644
--- a/fs/smb/client/cifs_debug.c
+++ b/fs/smb/client/cifs_debug.c
@@ -300,7 +300,7 @@ static __always_inline const char *compression_alg_str(__le16 alg)
 
 static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
 {
-	struct mid_q_entry *mid_entry;
+	struct smb_message *smb;
 	struct TCP_Server_Info *server;
 	struct TCP_Server_Info *chan_server;
 	struct cifs_ses *ses;
@@ -624,13 +624,13 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
 				seq_printf(m, "\n\tServer ConnectionId: 0x%llx",
 					   chan_server->conn_id);
 				spin_lock(&chan_server->mid_lock);
-				list_for_each_entry(mid_entry, &chan_server->pending_mid_q, qhead) {
+				list_for_each_entry(smb, &chan_server->pending_mid_q, qhead) {
 					seq_printf(m, "\n\t\tState: %d com: %d pid: %d cbdata: %p mid %llu",
-						   mid_entry->mid_state,
-						   le16_to_cpu(mid_entry->command),
-						   mid_entry->pid,
-						   mid_entry->callback_data,
-						   mid_entry->mid);
+						   smb->mid_state,
+						   le16_to_cpu(smb->command),
+						   smb->pid,
+						   smb->callback_data,
+						   smb->mid);
 				}
 				spin_unlock(&chan_server->mid_lock);
 			}
diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index 0a5266ecfd15..4e2a1d07125b 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -380,13 +380,13 @@ static int cifs_permission(struct mnt_idmap *idmap,
 
 static struct kmem_cache *cifs_inode_cachep;
 static struct kmem_cache *cifs_req_cachep;
-static struct kmem_cache *cifs_mid_cachep;
+static struct kmem_cache *smb_message_cachep;
 static struct kmem_cache *cifs_sm_req_cachep;
 static struct kmem_cache *cifs_io_request_cachep;
 static struct kmem_cache *cifs_io_subrequest_cachep;
 mempool_t *cifs_sm_req_poolp;
 mempool_t *cifs_req_poolp;
-mempool_t *cifs_mid_poolp;
+mempool_t smb_message_pool;
 mempool_t cifs_io_request_pool;
 mempool_t cifs_io_subrequest_pool;
 
@@ -1765,28 +1765,27 @@ cifs_destroy_request_bufs(void)
 	kmem_cache_destroy(cifs_sm_req_cachep);
 }
 
-static int init_mids(void)
+static int init_smb_message(void)
 {
-	cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids",
-					    sizeof(struct mid_q_entry), 0,
-					    SLAB_HWCACHE_ALIGN, NULL);
-	if (cifs_mid_cachep == NULL)
+	smb_message_cachep = kmem_cache_create("cifs_smb_message",
+					       sizeof(struct smb_message), 0,
+					       SLAB_HWCACHE_ALIGN, NULL);
+	if (smb_message_cachep == NULL)
 		return -ENOMEM;
 
 	/* 3 is a reasonable minimum number of simultaneous operations */
-	cifs_mid_poolp = mempool_create_slab_pool(3, cifs_mid_cachep);
-	if (cifs_mid_poolp == NULL) {
-		kmem_cache_destroy(cifs_mid_cachep);
+	if (mempool_init_slab_pool(&smb_message_pool, 3, smb_message_cachep) < 0) {
+		kmem_cache_destroy(smb_message_cachep);
 		return -ENOMEM;
 	}
 
 	return 0;
 }
 
-static void destroy_mids(void)
+static void destroy_smb_message(void)
 {
-	mempool_destroy(cifs_mid_poolp);
-	kmem_cache_destroy(cifs_mid_cachep);
+	mempool_exit(&smb_message_pool);
+	kmem_cache_destroy(smb_message_cachep);
 }
 
 static int cifs_init_netfs(void)
@@ -1946,7 +1945,7 @@ init_cifs(void)
 	if (rc)
 		goto out_destroy_inodecache;
 
-	rc = init_mids();
+	rc = init_smb_message();
 	if (rc)
 		goto out_destroy_netfs;
 
@@ -2003,7 +2002,7 @@ init_cifs(void)
 #endif
 	cifs_destroy_request_bufs();
 out_destroy_mids:
-	destroy_mids();
+	destroy_smb_message();
 out_destroy_netfs:
 	cifs_destroy_netfs();
 out_destroy_inodecache:
@@ -2045,7 +2044,7 @@ exit_cifs(void)
 	dfs_cache_destroy();
 #endif
 	cifs_destroy_request_bufs();
-	destroy_mids();
+	destroy_smb_message();
 	cifs_destroy_netfs();
 	cifs_destroy_inodecache();
 	destroy_workqueue(deferredclose_wq);
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 67c1a63a08ba..5d523099e298 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -295,7 +295,7 @@ struct smb_rqst {
 	struct folio_queue *rq_buffer;	/* Buffer for encryption */
 };
 
-struct mid_q_entry;
+struct smb_message;
 struct TCP_Server_Info;
 struct cifsFileInfo;
 struct cifs_ses;
@@ -313,24 +313,24 @@ struct cifs_credits;
 
 struct smb_version_operations {
 	int (*send_cancel)(struct TCP_Server_Info *, struct smb_rqst *,
-			   struct mid_q_entry *);
+			   struct smb_message *smb);
 	bool (*compare_fids)(struct cifsFileInfo *, struct cifsFileInfo *);
 	/* setup request: allocate mid, sign message */
-	struct mid_q_entry *(*setup_request)(struct cifs_ses *,
+	struct smb_message *(*setup_request)(struct cifs_ses *,
 					     struct TCP_Server_Info *,
 					     struct smb_rqst *);
 	/* setup async request: allocate mid, sign message */
-	struct mid_q_entry *(*setup_async_request)(struct TCP_Server_Info *,
-						struct smb_rqst *);
+	struct smb_message *(*setup_async_request)(struct TCP_Server_Info *,
+						   struct smb_rqst *);
 	/* check response: verify signature, map error */
-	int (*check_receive)(struct mid_q_entry *, struct TCP_Server_Info *,
+	int (*check_receive)(struct smb_message *, struct TCP_Server_Info *,
 			     bool);
 	void (*add_credits)(struct TCP_Server_Info *server,
 			    struct cifs_credits *credits,
 			    const int optype);
 	void (*set_credits)(struct TCP_Server_Info *, const int);
 	int * (*get_credits_field)(struct TCP_Server_Info *, const int);
-	unsigned int (*get_credits)(struct mid_q_entry *);
+	unsigned int (*get_credits)(struct smb_message *smb);
 	__u64 (*get_next_mid)(struct TCP_Server_Info *);
 	void (*revert_current_mid)(struct TCP_Server_Info *server,
 				   const unsigned int val);
@@ -347,7 +347,7 @@ struct smb_version_operations {
 	/* map smb to linux error */
 	int (*map_error)(char *, bool);
 	/* find mid corresponding to the response message */
-	struct mid_q_entry * (*find_mid)(struct TCP_Server_Info *, char *);
+	struct smb_message * (*find_mid)(struct TCP_Server_Info *, char *);
 	void (*dump_detail)(void *buf, struct TCP_Server_Info *ptcp_info);
 	void (*clear_stats)(struct cifs_tcon *);
 	void (*print_stats)(struct seq_file *m, struct cifs_tcon *);
@@ -355,12 +355,12 @@ struct smb_version_operations {
 	/* verify the message */
 	int (*check_message)(char *, unsigned int, struct TCP_Server_Info *);
 	bool (*is_oplock_break)(char *, struct TCP_Server_Info *);
-	int (*handle_cancelled_mid)(struct mid_q_entry *, struct TCP_Server_Info *);
+	int (*handle_cancelled_mid)(struct smb_message *smb, struct TCP_Server_Info *server);
 	void (*downgrade_oplock)(struct TCP_Server_Info *server,
 				 struct cifsInodeInfo *cinode, __u32 oplock,
 				 __u16 epoch, bool *purge_cache);
 	/* process transaction2 response */
-	bool (*check_trans2)(struct mid_q_entry *, struct TCP_Server_Info *,
+	bool (*check_trans2)(struct smb_message *smb, struct TCP_Server_Info *server,
 			     char *, int);
 	/* check if we need to negotiate */
 	bool (*need_neg)(struct TCP_Server_Info *);
@@ -597,7 +597,7 @@ struct smb_version_operations {
 				 struct smb_rqst *, struct smb_rqst *);
 	int (*is_transform_hdr)(void *buf);
 	int (*receive_transform)(struct TCP_Server_Info *,
-				 struct mid_q_entry **, char **, int *);
+				 struct smb_message **smb, char **, int *);
 	enum securityEnum (*select_sectype)(struct TCP_Server_Info *,
 			    enum securityEnum);
 	int (*next_header)(struct TCP_Server_Info *server, char *buf,
@@ -1683,8 +1683,8 @@ static inline void cifs_stats_bytes_read(struct cifs_tcon *tcon,
  * Returns zero on a successful receive, or an error. The receive state in
  * the TCP_Server_Info will also be updated.
  */
-typedef int (mid_receive_t)(struct TCP_Server_Info *server,
-			    struct mid_q_entry *mid);
+typedef int (*mid_receive_t)(struct TCP_Server_Info *server,
+			    struct smb_message *msg);
 
 /*
  * This is the prototype for the mid callback function. This is called once the
@@ -1694,17 +1694,17 @@ typedef int (mid_receive_t)(struct TCP_Server_Info *server,
  * - it will be called by cifsd, with no locks held
  * - the mid will be removed from any lists
  */
-typedef void (mid_callback_t)(struct mid_q_entry *mid);
+typedef void (*mid_callback_t)(struct smb_message *smb);
 
 /*
  * This is the protopyte for mid handle function. This is called once the mid
  * has been recognized after decryption of the message.
  */
-typedef int (mid_handle_t)(struct TCP_Server_Info *server,
-			    struct mid_q_entry *mid);
+typedef int (*mid_handle_t)(struct TCP_Server_Info *server,
+			    struct smb_message *smb);
 
 /* one of these for every pending CIFS request to the server */
-struct mid_q_entry {
+struct smb_message {
 	struct list_head qhead;	/* mids waiting on reply from this server */
 	struct kref refcount;
 	struct TCP_Server_Info *server;	/* server corresponding to this mid */
@@ -1718,9 +1718,9 @@ struct mid_q_entry {
 	unsigned long when_sent; /* time when smb send finished */
 	unsigned long when_received; /* when demux complete (taken off wire) */
 #endif
-	mid_receive_t *receive; /* call receive callback */
-	mid_callback_t *callback; /* call completion callback */
-	mid_handle_t *handle; /* call handle mid callback */
+	mid_receive_t receive; /* call receive callback */
+	mid_callback_t callback; /* call completion callback */
+	mid_handle_t handle; /* call handle mid callback */
 	void *callback_data;	  /* general purpose pointer for callback */
 	struct task_struct *creator;
 	void *resp_buf;		/* pointer to received SMB header */
@@ -1767,12 +1767,12 @@ static inline void cifs_num_waiters_dec(struct TCP_Server_Info *server)
 }
 
 #ifdef CONFIG_CIFS_STATS2
-static inline void cifs_save_when_sent(struct mid_q_entry *mid)
+static inline void cifs_save_when_sent(struct smb_message *smb)
 {
-	mid->when_sent = jiffies;
+	smb->when_sent = jiffies;
 }
 #else
-static inline void cifs_save_when_sent(struct mid_q_entry *mid)
+static inline void cifs_save_when_sent(struct smb_message *smb)
 {
 }
 #endif
@@ -2124,7 +2124,7 @@ extern __u32 cifs_lock_secret;
 
 extern mempool_t *cifs_sm_req_poolp;
 extern mempool_t *cifs_req_poolp;
-extern mempool_t *cifs_mid_poolp;
+extern mempool_t smb_message_pool;
 extern mempool_t cifs_io_request_pool;
 extern mempool_t cifs_io_subrequest_pool;
 
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index 8661ab105b4f..1126feb4ba5f 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -83,11 +83,11 @@ extern char *cifs_build_path_to_root(struct smb3_fs_context *ctx,
 				     int add_treename);
 extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
 char *cifs_build_devname(char *nodename, const char *prepath);
-extern void delete_mid(struct mid_q_entry *mid);
+extern void delete_mid(struct smb_message *smb);
 void __release_mid(struct kref *refcount);
-extern void cifs_wake_up_task(struct mid_q_entry *mid);
+extern void cifs_wake_up_task(struct smb_message *smb);
 extern int cifs_handle_standard(struct TCP_Server_Info *server,
-				struct mid_q_entry *mid);
+				struct smb_message *smb);
 extern char *smb3_fs_context_fullpath(const struct smb3_fs_context *ctx,
 				      char dirsep);
 extern int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx);
@@ -97,8 +97,8 @@ extern bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs);
 extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
 extern int cifs_call_async(struct TCP_Server_Info *server,
 			struct smb_rqst *rqst,
-			mid_receive_t *receive, mid_callback_t *callback,
-			mid_handle_t *handle, void *cbdata, const int flags,
+			mid_receive_t receive, mid_callback_t callback,
+			mid_handle_t handle, void *cbdata, const int flags,
 			const struct cifs_credits *exist_credits);
 extern struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses);
 extern int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
@@ -116,15 +116,15 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
 			int * /* bytes returned */ , const int);
 extern int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
 			    char *in_buf, int flags);
-int cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server);
-extern struct mid_q_entry *cifs_setup_request(struct cifs_ses *,
+int cifs_sync_mid_result(struct smb_message *smb, struct TCP_Server_Info *server);
+extern struct smb_message *cifs_setup_request(struct cifs_ses *,
 				struct TCP_Server_Info *,
 				struct smb_rqst *);
-extern struct mid_q_entry *cifs_setup_async_request(struct TCP_Server_Info *,
+extern struct smb_message *cifs_setup_async_request(struct TCP_Server_Info *,
 						struct smb_rqst *);
 int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
 		    struct smb_rqst *rqst);
-extern int cifs_check_receive(struct mid_q_entry *mid,
+extern int cifs_check_receive(struct smb_message *msg,
 			struct TCP_Server_Info *server, bool log_error);
 int wait_for_free_request(struct TCP_Server_Info *server, const int flags,
 			  unsigned int *instance);
@@ -134,13 +134,13 @@ extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server,
 
 static inline int
 send_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
-	    struct mid_q_entry *mid)
+	    struct smb_message *smb)
 {
 	return server->ops->send_cancel ?
-				server->ops->send_cancel(server, rqst, mid) : 0;
+				server->ops->send_cancel(server, rqst, smb) : 0;
 }
 
-int wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ);
+int wait_for_response(struct TCP_Server_Info *server, struct smb_message *smb);
 extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
 			struct kvec *, int /* nvec to send */,
 			int * /* type of buf returned */, const int flags,
@@ -186,7 +186,7 @@ extern int decode_negTokenInit(unsigned char *security_blob, int length,
 extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len);
 extern void cifs_set_port(struct sockaddr *addr, const unsigned short int port);
 extern int map_smb_to_linux_error(char *buf, bool logErr);
-extern int map_and_check_smb_error(struct mid_q_entry *mid, bool logErr);
+extern int map_and_check_smb_error(struct smb_message *smb, bool logErr);
 extern void header_assemble(struct smb_hdr *, char /* command */ ,
 			    const struct cifs_tcon *, int /* length of
 			    fixed section (word count) in two byte units */);
@@ -269,7 +269,7 @@ extern unsigned int setup_special_mode_ACE(struct smb_ace *pace,
 					   __u64 nmode);
 extern unsigned int setup_special_user_owner_ACE(struct smb_ace *pace);
 
-extern void dequeue_mid(struct mid_q_entry *mid, bool malformed);
+extern void dequeue_mid(struct smb_message *smb, bool malformed);
 extern int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
 			         unsigned int to_read);
 extern ssize_t cifs_discard_from_socket(struct TCP_Server_Info *server,
@@ -613,7 +613,7 @@ extern struct cifs_ses *
 cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx);
 
 int cifs_async_readv(struct cifs_io_subrequest *rdata);
-int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);
+int cifs_readv_receive(struct TCP_Server_Info *server, struct smb_message *smb);
 
 void cifs_async_writev(struct cifs_io_subrequest *wdata);
 int cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
@@ -762,9 +762,9 @@ static inline bool dfs_src_pathname_equal(const char *s1, const char *s2)
 	return true;
 }
 
-static inline void release_mid(struct mid_q_entry *mid)
+static inline void release_mid(struct smb_message *smb)
 {
-	kref_put(&mid->refcount, __release_mid);
+	kref_put(&smb->refcount, __release_mid);
 }
 
 static inline void cifs_free_open_info(struct cifs_open_info_data *data)
diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
index 75142f49d65d..879fa0ad6e44 100644
--- a/fs/smb/client/cifssmb.c
+++ b/fs/smb/client/cifssmb.c
@@ -577,12 +577,12 @@ CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
  * FIXME: maybe we should consider checking that the reply matches request?
  */
 static void
-cifs_echo_callback(struct mid_q_entry *mid)
+cifs_echo_callback(struct smb_message *smb)
 {
-	struct TCP_Server_Info *server = mid->callback_data;
+	struct TCP_Server_Info *server = smb->callback_data;
 	struct cifs_credits credits = { .value = 1, .instance = 0 };
 
-	release_mid(mid);
+	release_mid(smb);
 	add_credits(server, &credits, CIFS_ECHO_OP);
 }
 
@@ -1296,9 +1296,9 @@ CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
 }
 
 static void
-cifs_readv_callback(struct mid_q_entry *mid)
+cifs_readv_callback(struct smb_message *smb)
 {
-	struct cifs_io_subrequest *rdata = mid->callback_data;
+	struct cifs_io_subrequest *rdata = smb->callback_data;
 	struct netfs_inode *ictx = netfs_inode(rdata->rreq->inode);
 	struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink);
 	struct TCP_Server_Info *server = tcon->ses->server;
@@ -1313,10 +1313,10 @@ cifs_readv_callback(struct mid_q_entry *mid)
 	};
 
 	cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%zu\n",
-		 __func__, mid->mid, mid->mid_state, rdata->result,
+		 __func__, smb->mid, smb->mid_state, rdata->result,
 		 rdata->subreq.len);
 
-	switch (mid->mid_state) {
+	switch (smb->mid_state) {
 	case MID_RESPONSE_RECEIVED:
 		/* result already set, check signature */
 		if (server->sign) {
@@ -1324,7 +1324,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
 
 			iov_iter_truncate(&rqst.rq_iter, rdata->got_bytes);
 			rc = cifs_verify_signature(&rqst, server,
-						  mid->sequence_number);
+						  smb->sequence_number);
 			if (rc)
 				cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
 					 rc);
@@ -1379,7 +1379,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
 	rdata->subreq.transferred += rdata->got_bytes;
 	trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_progress);
 	netfs_read_subreq_terminated(&rdata->subreq);
-	release_mid(mid);
+	release_mid(smb);
 	add_credits(server, &credits, 0);
 }
 
@@ -1682,12 +1682,12 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
  * workqueue completion task.
  */
 static void
-cifs_writev_callback(struct mid_q_entry *mid)
+cifs_writev_callback(struct smb_message *smb)
 {
-	struct cifs_io_subrequest *wdata = mid->callback_data;
+	struct cifs_io_subrequest *wdata = smb->callback_data;
 	struct TCP_Server_Info *server = wdata->server;
 	struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink);
-	WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
+	WRITE_RSP *rsp = (WRITE_RSP *)smb->resp_buf;
 	struct cifs_credits credits = {
 		.value = 1,
 		.instance = 0,
@@ -1697,15 +1697,15 @@ cifs_writev_callback(struct mid_q_entry *mid)
 	ssize_t result;
 	size_t written;
 
-	switch (mid->mid_state) {
+	switch (smb->mid_state) {
 	case MID_RESPONSE_RECEIVED:
-		result = cifs_check_receive(mid, tcon->ses->server, 0);
+		result = cifs_check_receive(smb, tcon->ses->server, 0);
 		if (result != 0)
 			break;
 
-		written = le16_to_cpu(smb->CountHigh);
+		written = le16_to_cpu(rsp->CountHigh);
 		written <<= 16;
-		written += le16_to_cpu(smb->Count);
+		written += le16_to_cpu(rsp->Count);
 		/*
 		 * Mask off high 16 bits when bytes written as returned
 		 * by the server is greater than bytes requested by the
@@ -1749,7 +1749,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
 			      0, cifs_trace_rw_credits_write_response_clear);
 	wdata->credits.value = 0;
 	cifs_write_subrequest_terminated(wdata, result);
-	release_mid(mid);
+	release_mid(smb);
 	trace_smb3_rw_credits(credits.rreq_debug_id, credits.rreq_debug_index, 0,
 			      server->credits, server->in_flight,
 			      credits.value, cifs_trace_rw_credits_write_response_add);
@@ -1761,7 +1761,7 @@ void
 cifs_async_writev(struct cifs_io_subrequest *wdata)
 {
 	int rc = -EACCES;
-	WRITE_REQ *smb = NULL;
+	WRITE_REQ *req = NULL;
 	int wct;
 	struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink);
 	struct kvec iov[2];
@@ -1778,30 +1778,30 @@ cifs_async_writev(struct cifs_io_subrequest *wdata)
 		}
 	}
 
-	rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
+	rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&req);
 	if (rc)
 		goto async_writev_out;
 
-	smb->hdr.Pid = cpu_to_le16((__u16)wdata->req->pid);
-	smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->req->pid >> 16));
+	req->hdr.Pid = cpu_to_le16((__u16)wdata->req->pid);
+	req->hdr.PidHigh = cpu_to_le16((__u16)(wdata->req->pid >> 16));
 
-	smb->AndXCommand = 0xFF;	/* none */
-	smb->Fid = wdata->req->cfile->fid.netfid;
-	smb->OffsetLow = cpu_to_le32(wdata->subreq.start & 0xFFFFFFFF);
+	req->AndXCommand = 0xFF;	/* none */
+	req->Fid = wdata->req->cfile->fid.netfid;
+	req->OffsetLow = cpu_to_le32(wdata->subreq.start & 0xFFFFFFFF);
 	if (wct == 14)
-		smb->OffsetHigh = cpu_to_le32(wdata->subreq.start >> 32);
-	smb->Reserved = 0xFFFFFFFF;
-	smb->WriteMode = 0;
-	smb->Remaining = 0;
+		req->OffsetHigh = cpu_to_le32(wdata->subreq.start >> 32);
+	req->Reserved = 0xFFFFFFFF;
+	req->WriteMode = 0;
+	req->Remaining = 0;
 
-	smb->DataOffset =
+	req->DataOffset =
 	    cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
 
 	/* 4 for RFC1001 length + 1 for BCC */
 	iov[0].iov_len = 4;
-	iov[0].iov_base = smb;
-	iov[1].iov_len = get_rfc1002_length(smb) + 1;
-	iov[1].iov_base = (char *)smb + 4;
+	iov[0].iov_base = req;
+	iov[1].iov_len = get_rfc1002_length(req) + 1;
+	iov[1].iov_base = (char *)req + 4;
 
 	rqst.rq_iov = iov;
 	rqst.rq_nvec = 2;
@@ -1810,18 +1810,18 @@ cifs_async_writev(struct cifs_io_subrequest *wdata)
 	cifs_dbg(FYI, "async write at %llu %zu bytes\n",
 		 wdata->subreq.start, wdata->subreq.len);
 
-	smb->DataLengthLow = cpu_to_le16(wdata->subreq.len & 0xFFFF);
-	smb->DataLengthHigh = cpu_to_le16(wdata->subreq.len >> 16);
+	req->DataLengthLow = cpu_to_le16(wdata->subreq.len & 0xFFFF);
+	req->DataLengthHigh = cpu_to_le16(wdata->subreq.len >> 16);
 
 	if (wct == 14) {
-		inc_rfc1001_len(&smb->hdr, wdata->subreq.len + 1);
-		put_bcc(wdata->subreq.len + 1, &smb->hdr);
+		inc_rfc1001_len(&req->hdr, wdata->subreq.len + 1);
+		put_bcc(wdata->subreq.len + 1, &req->hdr);
 	} else {
 		/* wct == 12 */
-		struct smb_com_writex_req *smbw =
-				(struct smb_com_writex_req *)smb;
-		inc_rfc1001_len(&smbw->hdr, wdata->subreq.len + 5);
-		put_bcc(wdata->subreq.len + 5, &smbw->hdr);
+		struct smb_com_writex_req *reqw =
+				(struct smb_com_writex_req *)req;
+		inc_rfc1001_len(&reqw->hdr, wdata->subreq.len + 5);
+		put_bcc(wdata->subreq.len + 5, &reqw->hdr);
 		iov[1].iov_len += 4; /* pad bigger by four bytes */
 	}
 
@@ -1832,7 +1832,7 @@ cifs_async_writev(struct cifs_io_subrequest *wdata)
 		cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
 
 async_writev_out:
-	cifs_small_buf_release(smb);
+	cifs_small_buf_release(req);
 out:
 	if (rc) {
 		add_credits_and_wake_if(wdata->server, &wdata->credits, 0);
diff --git a/fs/smb/client/cifstransport.c b/fs/smb/client/cifstransport.c
index 241e0b427357..20709ae52d26 100644
--- a/fs/smb/client/cifstransport.c
+++ b/fs/smb/client/cifstransport.c
@@ -33,40 +33,40 @@
 /* Max number of iovectors we can use off the stack when sending requests. */
 #define CIFS_MAX_IOV_SIZE 8
 
-static struct mid_q_entry *
+static struct smb_message *
 alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
 {
-	struct mid_q_entry *temp;
+	struct smb_message *smb;
 
 	if (server == NULL) {
 		cifs_dbg(VFS, "%s: null TCP session\n", __func__);
 		return NULL;
 	}
 
-	temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
-	memset(temp, 0, sizeof(struct mid_q_entry));
-	kref_init(&temp->refcount);
-	temp->mid = get_mid(smb_buffer);
-	temp->pid = current->pid;
-	temp->command = cpu_to_le16(smb_buffer->Command);
+	smb = mempool_alloc(&smb_message_pool, GFP_NOFS);
+	memset(smb, 0, sizeof(struct smb_message));
+	kref_init(&smb->refcount);
+	smb->mid = get_mid(smb_buffer);
+	smb->pid = current->pid;
+	smb->command = cpu_to_le16(smb_buffer->Command);
 	cifs_dbg(FYI, "For smb_command %d\n", smb_buffer->Command);
 	/* easier to use jiffies */
 	/* when mid allocated can be before when sent */
-	temp->when_alloc = jiffies;
-	temp->server = server;
+	smb->when_alloc = jiffies;
+	smb->server = server;
 
 	/*
 	 * The default is for the mid to be synchronous, so the
 	 * default callback just wakes up the current task.
 	 */
 	get_task_struct(current);
-	temp->creator = current;
-	temp->callback = cifs_wake_up_task;
-	temp->callback_data = current;
+	smb->creator = current;
+	smb->callback = cifs_wake_up_task;
+	smb->callback_data = current;
 
 	atomic_inc(&mid_count);
-	temp->mid_state = MID_REQUEST_ALLOCATED;
-	return temp;
+	smb->mid_state = MID_REQUEST_ALLOCATED;
+	return smb;
 }
 
 int
@@ -86,7 +86,7 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
 }
 
 static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
-			struct mid_q_entry **ppmidQ)
+			struct smb_message **ppmidQ)
 {
 	spin_lock(&ses->ses_lock);
 	if (ses->ses_status == SES_NEW) {
@@ -117,12 +117,12 @@ static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
 	return 0;
 }
 
-struct mid_q_entry *
+struct smb_message *
 cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 {
 	int rc;
 	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
-	struct mid_q_entry *mid;
+	struct smb_message *smb;
 
 	if (rqst->rq_iov[0].iov_len != 4 ||
 	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
@@ -132,17 +132,17 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 	if (server->sign)
 		hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
-	mid = alloc_mid(hdr, server);
-	if (mid == NULL)
+	smb = alloc_mid(hdr, server);
+	if (smb == NULL)
 		return ERR_PTR(-ENOMEM);
 
-	rc = cifs_sign_rqst(rqst, server, &mid->sequence_number);
+	rc = cifs_sign_rqst(rqst, server, &smb->sequence_number);
 	if (rc) {
-		release_mid(mid);
+		release_mid(smb);
 		return ERR_PTR(rc);
 	}
 
-	return mid;
+	return smb;
 }
 
 /*
@@ -173,12 +173,12 @@ SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
 }
 
 int
-cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
+cifs_check_receive(struct smb_message *smb, struct TCP_Server_Info *server,
 		   bool log_error)
 {
-	unsigned int len = get_rfc1002_length(mid->resp_buf) + 4;
+	unsigned int len = get_rfc1002_length(smb->resp_buf) + 4;
 
-	dump_smb(mid->resp_buf, min_t(u32, 92, len));
+	dump_smb(smb->resp_buf, min_t(u32, 92, len));
 
 	/* convert the length into a more usable form */
 	if (server->sign) {
@@ -187,43 +187,43 @@ cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
 		struct smb_rqst rqst = { .rq_iov = iov,
 					 .rq_nvec = 2 };
 
-		iov[0].iov_base = mid->resp_buf;
+		iov[0].iov_base = smb->resp_buf;
 		iov[0].iov_len = 4;
-		iov[1].iov_base = (char *)mid->resp_buf + 4;
+		iov[1].iov_base = (char *)smb->resp_buf + 4;
 		iov[1].iov_len = len - 4;
 		/* FIXME: add code to kill session */
 		rc = cifs_verify_signature(&rqst, server,
-					   mid->sequence_number);
+					   smb->sequence_number);
 		if (rc)
 			cifs_server_dbg(VFS, "SMB signature verification returned error = %d\n",
 				 rc);
 	}
 
 	/* BB special case reconnect tid and uid here? */
-	return map_and_check_smb_error(mid, log_error);
+	return map_and_check_smb_error(smb, log_error);
 }
 
-struct mid_q_entry *
+struct smb_message *
 cifs_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *ignored,
 		   struct smb_rqst *rqst)
 {
 	int rc;
 	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
-	struct mid_q_entry *mid;
+	struct smb_message *smb;
 
 	if (rqst->rq_iov[0].iov_len != 4 ||
 	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
 		return ERR_PTR(-EIO);
 
-	rc = allocate_mid(ses, hdr, &mid);
+	rc = allocate_mid(ses, hdr, &smb);
 	if (rc)
 		return ERR_PTR(rc);
-	rc = cifs_sign_rqst(rqst, ses->server, &mid->sequence_number);
+	rc = cifs_sign_rqst(rqst, ses->server, &smb->sequence_number);
 	if (rc) {
-		delete_mid(mid);
+		delete_mid(smb);
 		return ERR_PTR(rc);
 	}
-	return mid;
+	return smb;
 }
 
 int
@@ -271,7 +271,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 	    int *pbytes_returned, const int flags)
 {
 	int rc = 0;
-	struct mid_q_entry *midQ;
+	struct smb_message *smb;
 	unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
 	struct kvec iov = { .iov_base = in_buf, .iov_len = len };
 	struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
@@ -315,7 +315,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 
 	cifs_server_lock(server);
 
-	rc = allocate_mid(ses, in_buf, &midQ);
+	rc = allocate_mid(ses, in_buf, &smb);
 	if (rc) {
 		cifs_server_unlock(server);
 		/* Update # of requests on wire to server */
@@ -323,16 +323,16 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 		return rc;
 	}
 
-	rc = cifs_sign_smb(in_buf, server, &midQ->sequence_number);
+	rc = cifs_sign_smb(in_buf, server, &smb->sequence_number);
 	if (rc) {
 		cifs_server_unlock(server);
 		goto out;
 	}
 
-	midQ->mid_state = MID_REQUEST_SUBMITTED;
+	smb->mid_state = MID_REQUEST_SUBMITTED;
 
 	rc = smb_send(server, in_buf, len);
-	cifs_save_when_sent(midQ);
+	cifs_save_when_sent(smb);
 
 	if (rc < 0)
 		server->sequence_number -= 2;
@@ -342,14 +342,14 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 	if (rc < 0)
 		goto out;
 
-	rc = wait_for_response(server, midQ);
+	rc = wait_for_response(server, smb);
 	if (rc != 0) {
-		send_cancel(server, &rqst, midQ);
+		send_cancel(server, &rqst, smb);
 		spin_lock(&server->mid_lock);
-		if (midQ->mid_state == MID_REQUEST_SUBMITTED ||
-		    midQ->mid_state == MID_RESPONSE_RECEIVED) {
+		if (smb->mid_state == MID_REQUEST_SUBMITTED ||
+		    smb->mid_state == MID_RESPONSE_RECEIVED) {
 			/* no longer considered to be "in-flight" */
-			midQ->callback = release_mid;
+			smb->callback = release_mid;
 			spin_unlock(&server->mid_lock);
 			add_credits(server, &credits, 0);
 			return rc;
@@ -357,24 +357,24 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 		spin_unlock(&server->mid_lock);
 	}
 
-	rc = cifs_sync_mid_result(midQ, server);
+	rc = cifs_sync_mid_result(smb, server);
 	if (rc != 0) {
 		add_credits(server, &credits, 0);
 		return rc;
 	}
 
-	if (!midQ->resp_buf || !out_buf ||
-	    midQ->mid_state != MID_RESPONSE_READY) {
+	if (!smb->resp_buf || !out_buf ||
+	    smb->mid_state != MID_RESPONSE_READY) {
 		rc = -EIO;
 		cifs_server_dbg(VFS, "Bad MID state?\n");
 		goto out;
 	}
 
-	*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
-	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
-	rc = cifs_check_receive(midQ, server, 0);
+	*pbytes_returned = get_rfc1002_length(smb->resp_buf);
+	memcpy(out_buf, smb->resp_buf, *pbytes_returned + 4);
+	rc = cifs_check_receive(smb, server, 0);
 out:
-	delete_mid(midQ);
+	delete_mid(smb);
 	add_credits(server, &credits, 0);
 
 	return rc;
@@ -412,7 +412,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 {
 	int rc = 0;
 	int rstart = 0;
-	struct mid_q_entry *midQ;
+	struct smb_message *smb;
 	struct cifs_ses *ses;
 	unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
 	struct kvec iov = { .iov_base = in_buf, .iov_len = len };
@@ -459,22 +459,22 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 
 	cifs_server_lock(server);
 
-	rc = allocate_mid(ses, in_buf, &midQ);
+	rc = allocate_mid(ses, in_buf, &smb);
 	if (rc) {
 		cifs_server_unlock(server);
 		return rc;
 	}
 
-	rc = cifs_sign_smb(in_buf, server, &midQ->sequence_number);
+	rc = cifs_sign_smb(in_buf, server, &smb->sequence_number);
 	if (rc) {
-		delete_mid(midQ);
+		delete_mid(smb);
 		cifs_server_unlock(server);
 		return rc;
 	}
 
-	midQ->mid_state = MID_REQUEST_SUBMITTED;
+	smb->mid_state = MID_REQUEST_SUBMITTED;
 	rc = smb_send(server, in_buf, len);
-	cifs_save_when_sent(midQ);
+	cifs_save_when_sent(smb);
 
 	if (rc < 0)
 		server->sequence_number -= 2;
@@ -482,22 +482,22 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 	cifs_server_unlock(server);
 
 	if (rc < 0) {
-		delete_mid(midQ);
+		delete_mid(smb);
 		return rc;
 	}
 
 	/* Wait for a reply - allow signals to interrupt. */
 	rc = wait_event_interruptible(server->response_q,
-		(!(midQ->mid_state == MID_REQUEST_SUBMITTED ||
-		   midQ->mid_state == MID_RESPONSE_RECEIVED)) ||
+		(!(smb->mid_state == MID_REQUEST_SUBMITTED ||
+		   smb->mid_state == MID_RESPONSE_RECEIVED)) ||
 		((server->tcpStatus != CifsGood) &&
 		 (server->tcpStatus != CifsNew)));
 
 	/* Were we interrupted by a signal ? */
 	spin_lock(&server->srv_lock);
 	if ((rc == -ERESTARTSYS) &&
-		(midQ->mid_state == MID_REQUEST_SUBMITTED ||
-		 midQ->mid_state == MID_RESPONSE_RECEIVED) &&
+		(smb->mid_state == MID_REQUEST_SUBMITTED ||
+		 smb->mid_state == MID_RESPONSE_RECEIVED) &&
 		((server->tcpStatus == CifsGood) ||
 		 (server->tcpStatus == CifsNew))) {
 		spin_unlock(&server->srv_lock);
@@ -505,9 +505,9 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 		if (in_buf->Command == SMB_COM_TRANSACTION2) {
 			/* POSIX lock. We send a NT_CANCEL SMB to cause the
 			   blocking lock to return. */
-			rc = send_cancel(server, &rqst, midQ);
+			rc = send_cancel(server, &rqst, smb);
 			if (rc) {
-				delete_mid(midQ);
+				delete_mid(smb);
 				return rc;
 			}
 		} else {
@@ -519,19 +519,19 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 			/* If we get -ENOLCK back the lock may have
 			   already been removed. Don't exit in this case. */
 			if (rc && rc != -ENOLCK) {
-				delete_mid(midQ);
+				delete_mid(smb);
 				return rc;
 			}
 		}
 
-		rc = wait_for_response(server, midQ);
+		rc = wait_for_response(server, smb);
 		if (rc) {
-			send_cancel(server, &rqst, midQ);
+			send_cancel(server, &rqst, smb);
 			spin_lock(&server->mid_lock);
-			if (midQ->mid_state == MID_REQUEST_SUBMITTED ||
-			    midQ->mid_state == MID_RESPONSE_RECEIVED) {
+			if (smb->mid_state == MID_REQUEST_SUBMITTED ||
+			    smb->mid_state == MID_RESPONSE_RECEIVED) {
 				/* no longer considered to be "in-flight" */
-				midQ->callback = release_mid;
+				smb->callback = release_mid;
 				spin_unlock(&server->mid_lock);
 				return rc;
 			}
@@ -544,22 +544,22 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 	}
 	spin_unlock(&server->srv_lock);
 
-	rc = cifs_sync_mid_result(midQ, server);
+	rc = cifs_sync_mid_result(smb, server);
 	if (rc != 0)
 		return rc;
 
 	/* rcvd frame is ok */
-	if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_READY) {
+	if (out_buf == NULL || smb->mid_state != MID_RESPONSE_READY) {
 		rc = -EIO;
 		cifs_tcon_dbg(VFS, "Bad MID state?\n");
 		goto out;
 	}
 
-	*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
-	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
-	rc = cifs_check_receive(midQ, server, 0);
+	*pbytes_returned = get_rfc1002_length(smb->resp_buf);
+	memcpy(out_buf, smb->resp_buf, *pbytes_returned + 4);
+	rc = cifs_check_receive(smb, server, 0);
 out:
-	delete_mid(midQ);
+	delete_mid(smb);
 	if (rstart && rc == -EACCES)
 		return -ERESTARTSYS;
 	return rc;
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index 205f547ca49e..9abaca4c8eba 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -293,7 +293,7 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
 static void
 cifs_abort_connection(struct TCP_Server_Info *server)
 {
-	struct mid_q_entry *mid, *nmid;
+	struct smb_message *smb, *nsmb;
 	struct list_head retry_list;
 
 	server->maxBuf = 0;
@@ -322,21 +322,21 @@ cifs_abort_connection(struct TCP_Server_Info *server)
 	INIT_LIST_HEAD(&retry_list);
 	cifs_dbg(FYI, "%s: moving mids to private list\n", __func__);
 	spin_lock(&server->mid_lock);
-	list_for_each_entry_safe(mid, nmid, &server->pending_mid_q, qhead) {
-		kref_get(&mid->refcount);
-		if (mid->mid_state == MID_REQUEST_SUBMITTED)
-			mid->mid_state = MID_RETRY_NEEDED;
-		list_move(&mid->qhead, &retry_list);
-		mid->mid_flags |= MID_DELETED;
+	list_for_each_entry_safe(smb, nsmb, &server->pending_mid_q, qhead) {
+		kref_get(&smb->refcount);
+		if (smb->mid_state == MID_REQUEST_SUBMITTED)
+			smb->mid_state = MID_RETRY_NEEDED;
+		list_move(&smb->qhead, &retry_list);
+		smb->mid_flags |= MID_DELETED;
 	}
 	spin_unlock(&server->mid_lock);
 	cifs_server_unlock(server);
 
 	cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__);
-	list_for_each_entry_safe(mid, nmid, &retry_list, qhead) {
-		list_del_init(&mid->qhead);
-		mid->callback(mid);
-		release_mid(mid);
+	list_for_each_entry_safe(smb, nsmb, &retry_list, qhead) {
+		list_del_init(&smb->qhead);
+		smb->callback(smb);
+		release_mid(smb);
 	}
 
 	if (cifs_rdma_enabled(server)) {
@@ -872,7 +872,7 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
 		    !server->with_rfc1001 &&
 		    server->rfc1001_sessinit != 0) {
 			int rc, mid_rc;
-			struct mid_q_entry *mid, *nmid;
+			struct smb_message *smb, *nsmb;
 			LIST_HEAD(dispose_list);
 
 			cifs_dbg(FYI, "RFC 1002 negative session response during SMB Negotiate, retrying with NetBIOS session\n");
@@ -885,10 +885,10 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
 			 * corresponding to SMB1/SMB2 Negotiate packet.
 			 */
 			spin_lock(&server->mid_lock);
-			list_for_each_entry_safe(mid, nmid, &server->pending_mid_q, qhead) {
-				kref_get(&mid->refcount);
-				list_move(&mid->qhead, &dispose_list);
-				mid->mid_flags |= MID_DELETED;
+			list_for_each_entry_safe(smb, nsmb, &server->pending_mid_q, qhead) {
+				kref_get(&smb->refcount);
+				list_move(&smb->qhead, &dispose_list);
+				smb->mid_flags |= MID_DELETED;
 			}
 			spin_unlock(&server->mid_lock);
 
@@ -915,12 +915,12 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
 			 * callback. Use MID_RC state which indicates that the
 			 * return code should be read from mid_rc member.
 			 */
-			list_for_each_entry_safe(mid, nmid, &dispose_list, qhead) {
-				list_del_init(&mid->qhead);
-				mid->mid_rc = mid_rc;
-				mid->mid_state = MID_RC;
-				mid->callback(mid);
-				release_mid(mid);
+			list_for_each_entry_safe(smb, nsmb, &dispose_list, qhead) {
+				list_del_init(&smb->qhead);
+				smb->mid_rc = mid_rc;
+				smb->mid_state = MID_RC;
+				smb->callback(smb);
+				release_mid(smb);
 			}
 
 			/*
@@ -952,27 +952,27 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
 }
 
 void
-dequeue_mid(struct mid_q_entry *mid, bool malformed)
+dequeue_mid(struct smb_message *smb, bool malformed)
 {
 #ifdef CONFIG_CIFS_STATS2
-	mid->when_received = jiffies;
+	smb->when_received = jiffies;
 #endif
-	spin_lock(&mid->server->mid_lock);
+	spin_lock(&smb->server->mid_lock);
 	if (!malformed)
-		mid->mid_state = MID_RESPONSE_RECEIVED;
+		smb->mid_state = MID_RESPONSE_RECEIVED;
 	else
-		mid->mid_state = MID_RESPONSE_MALFORMED;
+		smb->mid_state = MID_RESPONSE_MALFORMED;
 	/*
 	 * Trying to handle/dequeue a mid after the send_recv()
 	 * function has finished processing it is a bug.
 	 */
-	if (mid->mid_flags & MID_DELETED) {
-		spin_unlock(&mid->server->mid_lock);
+	if (smb->mid_flags & MID_DELETED) {
+		spin_unlock(&smb->server->mid_lock);
 		pr_warn_once("trying to dequeue a deleted mid\n");
 	} else {
-		list_del_init(&mid->qhead);
-		mid->mid_flags |= MID_DELETED;
-		spin_unlock(&mid->server->mid_lock);
+		list_del_init(&smb->qhead);
+		smb->mid_flags |= MID_DELETED;
+		spin_unlock(&smb->server->mid_lock);
 	}
 }
 
@@ -991,24 +991,24 @@ smb2_get_credits_from_hdr(char *buffer, struct TCP_Server_Info *server)
 }
 
 static void
-handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
+handle_mid(struct smb_message *smb, struct TCP_Server_Info *server,
 	   char *buf, int malformed)
 {
 	if (server->ops->check_trans2 &&
-	    server->ops->check_trans2(mid, server, buf, malformed))
+	    server->ops->check_trans2(smb, server, buf, malformed))
 		return;
-	mid->credits_received = smb2_get_credits_from_hdr(buf, server);
-	mid->resp_buf = buf;
-	mid->large_buf = server->large_buf;
+	smb->credits_received = smb2_get_credits_from_hdr(buf, server);
+	smb->resp_buf = buf;
+	smb->large_buf = server->large_buf;
 	/* Was previous buf put in mpx struct for multi-rsp? */
-	if (!mid->multiRsp) {
+	if (!smb->multiRsp) {
 		/* smb buffer will be freed by user thread */
 		if (server->large_buf)
 			server->bigbuf = NULL;
 		else
 			server->smallbuf = NULL;
 	}
-	dequeue_mid(mid, malformed);
+	dequeue_mid(smb, malformed);
 }
 
 int
@@ -1097,28 +1097,28 @@ clean_demultiplex_info(struct TCP_Server_Info *server)
 	}
 
 	if (!list_empty(&server->pending_mid_q)) {
-		struct mid_q_entry *mid_entry;
+		struct smb_message *smb;
 		struct list_head *tmp, *tmp2;
 		LIST_HEAD(dispose_list);
 
 		spin_lock(&server->mid_lock);
 		list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
-			mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-			cifs_dbg(FYI, "Clearing mid %llu\n", mid_entry->mid);
-			kref_get(&mid_entry->refcount);
-			mid_entry->mid_state = MID_SHUTDOWN;
-			list_move(&mid_entry->qhead, &dispose_list);
-			mid_entry->mid_flags |= MID_DELETED;
+			smb = list_entry(tmp, struct smb_message, qhead);
+			cifs_dbg(FYI, "Clearing mid %llu\n", smb->mid);
+			kref_get(&smb->refcount);
+			smb->mid_state = MID_SHUTDOWN;
+			list_move(&smb->qhead, &dispose_list);
+			smb->mid_flags |= MID_DELETED;
 		}
 		spin_unlock(&server->mid_lock);
 
 		/* now walk dispose list and issue callbacks */
 		list_for_each_safe(tmp, tmp2, &dispose_list) {
-			mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-			cifs_dbg(FYI, "Callback mid %llu\n", mid_entry->mid);
-			list_del_init(&mid_entry->qhead);
-			mid_entry->callback(mid_entry);
-			release_mid(mid_entry);
+			smb = list_entry(tmp, struct smb_message, qhead);
+			cifs_dbg(FYI, "Callback mid %llu\n", smb->mid);
+			list_del_init(&smb->qhead);
+			smb->callback(smb);
+			release_mid(smb);
 		}
 		/* 1/8th of sec is more than enough time for them to exit */
 		msleep(125);
@@ -1152,7 +1152,7 @@ clean_demultiplex_info(struct TCP_Server_Info *server)
 }
 
 static int
-standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
+standard_receive3(struct TCP_Server_Info *server, struct smb_message *smb)
 {
 	int length;
 	char *buf = server->smallbuf;
@@ -1183,11 +1183,11 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 
 	dump_smb(buf, server->total_read);
 
-	return cifs_handle_standard(server, mid);
+	return cifs_handle_standard(server, smb);
 }
 
 int
-cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
+cifs_handle_standard(struct TCP_Server_Info *server, struct smb_message *smb)
 {
 	char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
 	int rc;
@@ -1215,10 +1215,10 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 	    server->ops->is_status_pending(buf, server))
 		return -1;
 
-	if (!mid)
+	if (!smb)
 		return rc;
 
-	handle_mid(mid, server, buf, rc);
+	handle_mid(smb, server, buf, rc);
 	return 0;
 }
 
@@ -1255,13 +1255,13 @@ smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server)
 static int
 cifs_demultiplex_thread(void *p)
 {
-	int i, num_mids, length;
+	int i, num_smbs, length;
 	struct TCP_Server_Info *server = p;
 	unsigned int pdu_length;
 	unsigned int next_offset;
 	char *buf = NULL;
 	struct task_struct *task_to_wake = NULL;
-	struct mid_q_entry *mids[MAX_COMPOUND];
+	struct smb_message *smbs[MAX_COMPOUND];
 	char *bufs[MAX_COMPOUND];
 	unsigned int noreclaim_flag, num_io_timeout = 0;
 	bool pending_reconnect = false;
@@ -1336,32 +1336,32 @@ cifs_demultiplex_thread(void *p)
 				server->pdu_size = next_offset;
 		}
 
-		memset(mids, 0, sizeof(mids));
+		memset(smbs, 0, sizeof(smbs));
 		memset(bufs, 0, sizeof(bufs));
-		num_mids = 0;
+		num_smbs = 0;
 
 		if (server->ops->is_transform_hdr &&
 		    server->ops->receive_transform &&
 		    server->ops->is_transform_hdr(buf)) {
 			length = server->ops->receive_transform(server,
-								mids,
+								smbs,
 								bufs,
-								&num_mids);
+								&num_smbs);
 		} else {
-			mids[0] = server->ops->find_mid(server, buf);
+			smbs[0] = server->ops->find_mid(server, buf);
 			bufs[0] = buf;
-			num_mids = 1;
+			num_smbs = 1;
 
-			if (!mids[0] || !mids[0]->receive)
-				length = standard_receive3(server, mids[0]);
+			if (!smbs[0] || !smbs[0]->receive)
+				length = standard_receive3(server, smbs[0]);
 			else
-				length = mids[0]->receive(server, mids[0]);
+				length = smbs[0]->receive(server, smbs[0]);
 		}
 
 		if (length < 0) {
-			for (i = 0; i < num_mids; i++)
-				if (mids[i])
-					release_mid(mids[i]);
+			for (i = 0; i < num_smbs; i++)
+				if (smbs[i])
+					release_mid(smbs[i]);
 			continue;
 		}
 
@@ -1380,9 +1380,9 @@ cifs_demultiplex_thread(void *p)
 
 		server->lstrp = jiffies;
 
-		for (i = 0; i < num_mids; i++) {
-			if (mids[i] != NULL) {
-				mids[i]->resp_buf_size = server->pdu_size;
+		for (i = 0; i < num_smbs; i++) {
+			if (smbs[i] != NULL) {
+				smbs[i]->resp_buf_size = server->pdu_size;
 
 				if (bufs[i] != NULL) {
 					if (server->ops->is_network_name_deleted &&
@@ -1393,10 +1393,10 @@ cifs_demultiplex_thread(void *p)
 					}
 				}
 
-				if (!mids[i]->multiRsp || mids[i]->multiEnd)
-					mids[i]->callback(mids[i]);
+				if (!smbs[i]->multiRsp || smbs[i]->multiEnd)
+					smbs[i]->callback(smbs[i]);
 
-				release_mid(mids[i]);
+				release_mid(smbs[i]);
 			} else if (server->ops->is_oplock_break &&
 				   server->ops->is_oplock_break(bufs[i],
 								server)) {
diff --git a/fs/smb/client/netmisc.c b/fs/smb/client/netmisc.c
index 9ec20601cee2..b34d2b91cf5a 100644
--- a/fs/smb/client/netmisc.c
+++ b/fs/smb/client/netmisc.c
@@ -889,22 +889,22 @@ map_smb_to_linux_error(char *buf, bool logErr)
 }
 
 int
-map_and_check_smb_error(struct mid_q_entry *mid, bool logErr)
+map_and_check_smb_error(struct smb_message *smb, bool logErr)
 {
 	int rc;
-	struct smb_hdr *smb = (struct smb_hdr *)mid->resp_buf;
+	struct smb_hdr *rhdr = (struct smb_hdr *)smb->resp_buf;
 
-	rc = map_smb_to_linux_error((char *)smb, logErr);
-	if (rc == -EACCES && !(smb->Flags2 & SMBFLG2_ERR_STATUS)) {
+	rc = map_smb_to_linux_error((char *)rhdr, logErr);
+	if (rc == -EACCES && !(rhdr->Flags2 & SMBFLG2_ERR_STATUS)) {
 		/* possible ERRBaduid */
-		__u8 class = smb->Status.DosError.ErrorClass;
-		__u16 code = le16_to_cpu(smb->Status.DosError.Error);
+		__u8 class = rhdr->Status.DosError.ErrorClass;
+		__u16 code = le16_to_cpu(rhdr->Status.DosError.Error);
 
 		/* switch can be used to handle different errors */
 		if (class == ERRSRV && code == ERRbaduid) {
 			cifs_dbg(FYI, "Server returned 0x%x, reconnecting session...\n",
 				code);
-			cifs_signal_cifsd_for_reconnect(mid->server, false);
+			cifs_signal_cifsd_for_reconnect(smb->server, false);
 		}
 	}
 
diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
index b27a182629ec..ba301c94d4ff 100644
--- a/fs/smb/client/smb1ops.c
+++ b/fs/smb/client/smb1ops.c
@@ -29,7 +29,7 @@
  */
 static int
 send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
-	       struct mid_q_entry *mid)
+	       struct smb_message *smb)
 {
 	int rc = 0;
 	struct smb_hdr *in_buf = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
@@ -41,7 +41,7 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 	put_bcc(0, in_buf);
 
 	cifs_server_lock(server);
-	rc = cifs_sign_smb(in_buf, server, &mid->sequence_number);
+	rc = cifs_sign_smb(in_buf, server, &smb->sequence_number);
 	if (rc) {
 		cifs_server_unlock(server);
 		return rc;
@@ -88,20 +88,20 @@ cifs_read_data_length(char *buf, bool in_remaining)
 	       le16_to_cpu(rsp->DataLength);
 }
 
-static struct mid_q_entry *
+static struct smb_message *
 cifs_find_mid(struct TCP_Server_Info *server, char *buffer)
 {
 	struct smb_hdr *buf = (struct smb_hdr *)buffer;
-	struct mid_q_entry *mid;
+	struct smb_message *smb;
 
 	spin_lock(&server->mid_lock);
-	list_for_each_entry(mid, &server->pending_mid_q, qhead) {
-		if (compare_mid(mid->mid, buf) &&
-		    mid->mid_state == MID_REQUEST_SUBMITTED &&
-		    le16_to_cpu(mid->command) == buf->Command) {
-			kref_get(&mid->refcount);
+	list_for_each_entry(smb, &server->pending_mid_q, qhead) {
+		if (compare_mid(smb->mid, buf) &&
+		    smb->mid_state == MID_REQUEST_SUBMITTED &&
+		    le16_to_cpu(smb->command) == buf->Command) {
+			kref_get(&smb->refcount);
 			spin_unlock(&server->mid_lock);
-			return mid;
+			return smb;
 		}
 	}
 	spin_unlock(&server->mid_lock);
@@ -135,7 +135,7 @@ cifs_get_credits_field(struct TCP_Server_Info *server, const int optype)
 }
 
 static unsigned int
-cifs_get_credits(struct mid_q_entry *mid)
+cifs_get_credits(struct smb_message *smb)
 {
 	return 1;
 }
@@ -189,7 +189,7 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
 	 * did not time out).
 	 */
 	while (cur_mid != last_mid) {
-		struct mid_q_entry *mid_entry;
+		struct smb_message *smb;
 		unsigned int num_mids;
 
 		collision = false;
@@ -197,10 +197,10 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
 			cur_mid++;
 
 		num_mids = 0;
-		list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) {
+		list_for_each_entry(smb, &server->pending_mid_q, qhead) {
 			++num_mids;
-			if (mid_entry->mid == cur_mid &&
-			    mid_entry->mid_state == MID_REQUEST_SUBMITTED) {
+			if (smb->mid == cur_mid &&
+			    smb->mid_state == MID_REQUEST_SUBMITTED) {
 				/* This mid is in use, try a different one */
 				collision = true;
 				break;
@@ -385,22 +385,22 @@ cifs_downgrade_oplock(struct TCP_Server_Info *server,
 }
 
 static bool
-cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server,
+cifs_check_trans2(struct smb_message *smb, struct TCP_Server_Info *server,
 		  char *buf, int malformed)
 {
 	if (malformed)
 		return false;
 	if (check2ndT2(buf) <= 0)
 		return false;
-	mid->multiRsp = true;
-	if (mid->resp_buf) {
+	smb->multiRsp = true;
+	if (smb->resp_buf) {
 		/* merge response - fix up 1st*/
-		malformed = coalesce_t2(buf, mid->resp_buf);
+		malformed = coalesce_t2(buf, smb->resp_buf);
 		if (malformed > 0)
 			return true;
 		/* All parts received or packet is malformed. */
-		mid->multiEnd = true;
-		dequeue_mid(mid, malformed);
+		smb->multiEnd = true;
+		dequeue_mid(smb, malformed);
 		return true;
 	}
 	if (!server->large_buf) {
@@ -408,8 +408,8 @@ cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server,
 		cifs_dbg(VFS, "1st trans2 resp needs bigbuf\n");
 	} else {
 		/* Have first buffer */
-		mid->resp_buf = buf;
-		mid->large_buf = true;
+		smb->resp_buf = buf;
+		smb->large_buf = true;
 		server->bigbuf = NULL;
 	}
 	return true;
diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c
index 93ce9fc7b4a4..f1b0546c7858 100644
--- a/fs/smb/client/smb2misc.c
+++ b/fs/smb/client/smb2misc.c
@@ -839,14 +839,14 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid,
 }
 
 int
-smb2_handle_cancelled_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server)
+smb2_handle_cancelled_mid(struct smb_message *smb, struct TCP_Server_Info *server)
 {
-	struct smb2_hdr *hdr = mid->resp_buf;
-	struct smb2_create_rsp *rsp = mid->resp_buf;
+	struct smb2_hdr *hdr = smb->resp_buf;
+	struct smb2_create_rsp *rsp = smb->resp_buf;
 	struct cifs_tcon *tcon;
 	int rc;
 
-	if ((mid->optype & CIFS_CP_CREATE_CLOSE_OP) || hdr->Command != SMB2_CREATE ||
+	if ((smb->optype & CIFS_CP_CREATE_CLOSE_OP) || hdr->Command != SMB2_CREATE ||
 	    hdr->Status != STATUS_SUCCESS)
 		return 0;
 
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 1468c16ea9b8..a7ba4a77721e 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -226,9 +226,9 @@ smb2_get_credits_field(struct TCP_Server_Info *server, const int optype)
 }
 
 static unsigned int
-smb2_get_credits(struct mid_q_entry *mid)
+smb2_get_credits(struct smb_message *smb)
 {
-	return mid->credits_received;
+	return smb->credits_received;
 }
 
 static int
@@ -389,10 +389,10 @@ smb2_revert_current_mid(struct TCP_Server_Info *server, const unsigned int val)
 	spin_unlock(&server->mid_lock);
 }
 
-static struct mid_q_entry *
+static struct smb_message *
 __smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue)
 {
-	struct mid_q_entry *mid;
+	struct smb_message *smb;
 	struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
 	__u64 wire_mid = le64_to_cpu(shdr->MessageId);
 
@@ -402,30 +402,30 @@ __smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue)
 	}
 
 	spin_lock(&server->mid_lock);
-	list_for_each_entry(mid, &server->pending_mid_q, qhead) {
-		if ((mid->mid == wire_mid) &&
-		    (mid->mid_state == MID_REQUEST_SUBMITTED) &&
-		    (mid->command == shdr->Command)) {
-			kref_get(&mid->refcount);
+	list_for_each_entry(smb, &server->pending_mid_q, qhead) {
+		if ((smb->mid == wire_mid) &&
+		    (smb->mid_state == MID_REQUEST_SUBMITTED) &&
+		    (smb->command == shdr->Command)) {
+			kref_get(&smb->refcount);
 			if (dequeue) {
-				list_del_init(&mid->qhead);
-				mid->mid_flags |= MID_DELETED;
+				list_del_init(&smb->qhead);
+				smb->mid_flags |= MID_DELETED;
 			}
 			spin_unlock(&server->mid_lock);
-			return mid;
+			return smb;
 		}
 	}
 	spin_unlock(&server->mid_lock);
 	return NULL;
 }
 
-static struct mid_q_entry *
+static struct smb_message *
 smb2_find_mid(struct TCP_Server_Info *server, char *buf)
 {
 	return __smb2_find_mid(server, buf, false);
 }
 
-static struct mid_q_entry *
+static struct smb_message *
 smb2_find_dequeue_mid(struct TCP_Server_Info *server, char *buf)
 {
 	return __smb2_find_mid(server, buf, true);
@@ -4611,7 +4611,7 @@ cifs_copy_folioq_to_iter(struct folio_queue *folioq, size_t data_size,
 }
 
 static int
-handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
+handle_read_data(struct TCP_Server_Info *server, struct smb_message *smb,
 		 char *buf, unsigned int buf_len, struct folio_queue *buffer,
 		 unsigned int buffer_len, bool is_offloaded)
 {
@@ -4620,7 +4620,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
 	unsigned int cur_off;
 	unsigned int cur_page_idx;
 	unsigned int pad_len;
-	struct cifs_io_subrequest *rdata = mid->callback_data;
+	struct cifs_io_subrequest *rdata = smb->callback_data;
 	struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
 	int length;
 	bool use_rdma_mr = false;
@@ -4658,9 +4658,9 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
 			 __func__, rdata->result);
 		/* normal error on read response */
 		if (is_offloaded)
-			mid->mid_state = MID_RESPONSE_RECEIVED;
+			smb->mid_state = MID_RESPONSE_RECEIVED;
 		else
-			dequeue_mid(mid, false);
+			dequeue_mid(smb, false);
 		return 0;
 	}
 
@@ -4685,9 +4685,9 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
 			 __func__, data_offset);
 		rdata->result = -EIO;
 		if (is_offloaded)
-			mid->mid_state = MID_RESPONSE_MALFORMED;
+			smb->mid_state = MID_RESPONSE_MALFORMED;
 		else
-			dequeue_mid(mid, rdata->result);
+			dequeue_mid(smb, rdata->result);
 		return 0;
 	}
 
@@ -4704,9 +4704,9 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
 				 __func__, data_offset);
 			rdata->result = -EIO;
 			if (is_offloaded)
-				mid->mid_state = MID_RESPONSE_MALFORMED;
+				smb->mid_state = MID_RESPONSE_MALFORMED;
 			else
-				dequeue_mid(mid, rdata->result);
+				dequeue_mid(smb, rdata->result);
 			return 0;
 		}
 
@@ -4714,9 +4714,9 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
 			/* data_len is corrupt -- discard frame */
 			rdata->result = -EIO;
 			if (is_offloaded)
-				mid->mid_state = MID_RESPONSE_MALFORMED;
+				smb->mid_state = MID_RESPONSE_MALFORMED;
 			else
-				dequeue_mid(mid, rdata->result);
+				dequeue_mid(smb, rdata->result);
 			return 0;
 		}
 
@@ -4725,9 +4725,9 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
 							 cur_off, &rdata->subreq.io_iter);
 		if (rdata->result != 0) {
 			if (is_offloaded)
-				mid->mid_state = MID_RESPONSE_MALFORMED;
+				smb->mid_state = MID_RESPONSE_MALFORMED;
 			else
-				dequeue_mid(mid, rdata->result);
+				dequeue_mid(smb, rdata->result);
 			return 0;
 		}
 		rdata->got_bytes = buffer_len;
@@ -4744,16 +4744,16 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
 		WARN_ONCE(1, "buf can not contain only a part of read data");
 		rdata->result = -EIO;
 		if (is_offloaded)
-			mid->mid_state = MID_RESPONSE_MALFORMED;
+			smb->mid_state = MID_RESPONSE_MALFORMED;
 		else
-			dequeue_mid(mid, rdata->result);
+			dequeue_mid(smb, rdata->result);
 		return 0;
 	}
 
 	if (is_offloaded)
-		mid->mid_state = MID_RESPONSE_RECEIVED;
+		smb->mid_state = MID_RESPONSE_RECEIVED;
 	else
-		dequeue_mid(mid, false);
+		dequeue_mid(smb, false);
 	return 0;
 }
 
@@ -4771,7 +4771,7 @@ static void smb2_decrypt_offload(struct work_struct *work)
 	struct smb2_decrypt_work *dw = container_of(work,
 				struct smb2_decrypt_work, decrypt);
 	int rc;
-	struct mid_q_entry *mid;
+	struct smb_message *smb;
 	struct iov_iter iter;
 
 	iov_iter_folio_queue(&iter, ITER_DEST, dw->buffer, 0, 0, dw->len);
@@ -4783,43 +4783,43 @@ static void smb2_decrypt_offload(struct work_struct *work)
 	}
 
 	dw->server->lstrp = jiffies;
-	mid = smb2_find_dequeue_mid(dw->server, dw->buf);
-	if (mid == NULL)
+	smb = smb2_find_dequeue_mid(dw->server, dw->buf);
+	if (smb == NULL)
 		cifs_dbg(FYI, "mid not found\n");
 	else {
-		mid->decrypted = true;
-		rc = handle_read_data(dw->server, mid, dw->buf,
+		smb->decrypted = true;
+		rc = handle_read_data(dw->server, smb, dw->buf,
 				      dw->server->vals->read_rsp_size,
 				      dw->buffer, dw->len,
 				      true);
 		if (rc >= 0) {
 #ifdef CONFIG_CIFS_STATS2
-			mid->when_received = jiffies;
+			smb->when_received = jiffies;
 #endif
 			if (dw->server->ops->is_network_name_deleted)
 				dw->server->ops->is_network_name_deleted(dw->buf,
 									 dw->server);
 
-			mid->callback(mid);
+			smb->callback(smb);
 		} else {
 			spin_lock(&dw->server->srv_lock);
 			if (dw->server->tcpStatus == CifsNeedReconnect) {
 				spin_lock(&dw->server->mid_lock);
-				mid->mid_state = MID_RETRY_NEEDED;
+				smb->mid_state = MID_RETRY_NEEDED;
 				spin_unlock(&dw->server->mid_lock);
 				spin_unlock(&dw->server->srv_lock);
-				mid->callback(mid);
+				smb->callback(smb);
 			} else {
 				spin_lock(&dw->server->mid_lock);
-				mid->mid_state = MID_REQUEST_SUBMITTED;
-				mid->mid_flags &= ~(MID_DELETED);
-				list_add_tail(&mid->qhead,
+				smb->mid_state = MID_REQUEST_SUBMITTED;
+				smb->mid_flags &= ~(MID_DELETED);
+				list_add_tail(&smb->qhead,
 					&dw->server->pending_mid_q);
 				spin_unlock(&dw->server->mid_lock);
 				spin_unlock(&dw->server->srv_lock);
 			}
 		}
-		release_mid(mid);
+		release_mid(smb);
 	}
 
 free_pages:
@@ -4830,7 +4830,7 @@ static void smb2_decrypt_offload(struct work_struct *work)
 
 
 static int
-receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid,
+receive_encrypted_read(struct TCP_Server_Info *server, struct smb_message **smb,
 		       int *num_mids)
 {
 	char *buf = server->smallbuf;
@@ -4906,13 +4906,13 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid,
 	if (rc)
 		goto free_pages;
 
-	*mid = smb2_find_mid(server, buf);
-	if (*mid == NULL) {
+	*smb = smb2_find_mid(server, buf);
+	if (*smb == NULL) {
 		cifs_dbg(FYI, "mid not found\n");
 	} else {
 		cifs_dbg(FYI, "mid found\n");
-		(*mid)->decrypted = true;
-		rc = handle_read_data(server, *mid, buf,
+		(*smb)->decrypted = true;
+		rc = handle_read_data(server, *smb, buf,
 				      server->vals->read_rsp_size,
 				      dw->buffer, dw->len, false);
 		if (rc >= 0) {
@@ -4935,7 +4935,7 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid,
 
 static int
 receive_encrypted_standard(struct TCP_Server_Info *server,
-			   struct mid_q_entry **mids, char **bufs,
+			   struct smb_message **mids, char **bufs,
 			   int *num_mids)
 {
 	int ret, length;
@@ -4944,7 +4944,7 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
 	unsigned int pdu_length = server->pdu_size;
 	unsigned int buf_size;
 	unsigned int next_cmd;
-	struct mid_q_entry *mid_entry;
+	struct smb_message *smb;
 	int next_is_large;
 	char *next_buffer = NULL;
 
@@ -4987,13 +4987,13 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
 		memcpy(next_buffer, buf + next_cmd, pdu_length - next_cmd);
 	}
 
-	mid_entry = smb2_find_mid(server, buf);
-	if (mid_entry == NULL)
+	smb = smb2_find_mid(server, buf);
+	if (smb == NULL)
 		cifs_dbg(FYI, "mid not found\n");
 	else {
 		cifs_dbg(FYI, "mid found\n");
-		mid_entry->decrypted = true;
-		mid_entry->resp_buf_size = server->pdu_size;
+		smb->decrypted = true;
+		smb->resp_buf_size = server->pdu_size;
 	}
 
 	if (*num_mids >= MAX_COMPOUND) {
@@ -5001,12 +5001,12 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
 		return -1;
 	}
 	bufs[*num_mids] = buf;
-	mids[(*num_mids)++] = mid_entry;
+	mids[(*num_mids)++] = smb;
 
-	if (mid_entry && mid_entry->handle)
-		ret = mid_entry->handle(server, mid_entry);
+	if (smb && smb->handle)
+		ret = smb->handle(server, smb);
 	else
-		ret = cifs_handle_standard(server, mid_entry);
+		ret = cifs_handle_standard(server, smb);
 
 	if (ret == 0 && next_cmd) {
 		pdu_length -= next_cmd;
@@ -5034,7 +5034,7 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
 
 static int
 smb3_receive_transform(struct TCP_Server_Info *server,
-		       struct mid_q_entry **mids, char **bufs, int *num_mids)
+		       struct smb_message **mids, char **bufs, int *num_mids)
 {
 	char *buf = server->smallbuf;
 	unsigned int pdu_length = server->pdu_size;
@@ -5064,11 +5064,11 @@ smb3_receive_transform(struct TCP_Server_Info *server,
 }
 
 int
-smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid)
+smb3_handle_read_data(struct TCP_Server_Info *server, struct smb_message *smb)
 {
 	char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
 
-	return handle_read_data(server, mid, buf, server->pdu_size,
+	return handle_read_data(server, smb, buf, server->pdu_size,
 				NULL, 0, false);
 }
 
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 96df4aa7a7af..645d67d04a8d 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -4089,19 +4089,19 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
  * FIXME: maybe we should consider checking that the reply matches request?
  */
 static void
-smb2_echo_callback(struct mid_q_entry *mid)
+smb2_echo_callback(struct smb_message *smb)
 {
-	struct TCP_Server_Info *server = mid->callback_data;
-	struct smb2_echo_rsp *rsp = (struct smb2_echo_rsp *)mid->resp_buf;
+	struct TCP_Server_Info *server = smb->callback_data;
+	struct smb2_echo_rsp *rsp = (struct smb2_echo_rsp *)smb->resp_buf;
 	struct cifs_credits credits = { .value = 0, .instance = 0 };
 
-	if (mid->mid_state == MID_RESPONSE_RECEIVED
-	    || mid->mid_state == MID_RESPONSE_MALFORMED) {
+	if (smb->mid_state == MID_RESPONSE_RECEIVED
+	    || smb->mid_state == MID_RESPONSE_MALFORMED) {
 		credits.value = le16_to_cpu(rsp->hdr.CreditRequest);
 		credits.instance = server->reconnect_instance;
 	}
 
-	release_mid(mid);
+	release_mid(smb);
 	add_credits(server, &credits, CIFS_ECHO_OP);
 }
 
@@ -4516,14 +4516,13 @@ smb2_new_read_req(void **buf, unsigned int *total_len,
 }
 
 static void
-smb2_readv_callback(struct mid_q_entry *mid)
+smb2_readv_callback(struct smb_message *smb)
 {
-	struct cifs_io_subrequest *rdata = mid->callback_data;
+	struct cifs_io_subrequest *rdata = smb->callback_data;
 	struct netfs_inode *ictx = netfs_inode(rdata->rreq->inode);
 	struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink);
 	struct TCP_Server_Info *server = rdata->server;
-	struct smb2_hdr *shdr =
-				(struct smb2_hdr *)rdata->iov[0].iov_base;
+	struct smb2_hdr *shdr = (struct smb2_hdr *)rdata->iov[0].iov_base;
 	struct cifs_credits credits = {
 		.value = 0,
 		.instance = 0,
@@ -4538,20 +4537,20 @@ smb2_readv_callback(struct mid_q_entry *mid)
 		rqst.rq_iter	  = rdata->subreq.io_iter;
 	}
 
-	WARN_ONCE(rdata->server != mid->server,
+	WARN_ONCE(rdata->server != smb->server,
 		  "rdata server %p != mid server %p",
-		  rdata->server, mid->server);
+		  rdata->server, smb->server);
 
 	cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%zu/%zu\n",
-		 __func__, mid->mid, mid->mid_state, rdata->result,
+		 __func__, smb->mid, smb->mid_state, rdata->result,
 		 rdata->got_bytes, rdata->subreq.len - rdata->subreq.transferred);
 
-	switch (mid->mid_state) {
+	switch (smb->mid_state) {
 	case MID_RESPONSE_RECEIVED:
 		credits.value = le16_to_cpu(shdr->CreditRequest);
 		credits.instance = server->reconnect_instance;
 		/* result already set, check signature */
-		if (server->sign && !mid->decrypted) {
+		if (server->sign && !smb->decrypted) {
 			int rc;
 
 			iov_iter_truncate(&rqst.rq_iter, rdata->got_bytes);
@@ -4641,7 +4640,7 @@ smb2_readv_callback(struct mid_q_entry *mid)
 	rdata->subreq.transferred += rdata->got_bytes;
 	trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_progress);
 	netfs_read_subreq_terminated(&rdata->subreq);
-	release_mid(mid);
+	release_mid(smb);
 	trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0,
 			      server->credits, server->in_flight,
 			      credits.value, cifs_trace_rw_credits_read_response_add);
@@ -4818,12 +4817,12 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
  * workqueue completion task.
  */
 static void
-smb2_writev_callback(struct mid_q_entry *mid)
+smb2_writev_callback(struct smb_message *smb)
 {
-	struct cifs_io_subrequest *wdata = mid->callback_data;
+	struct cifs_io_subrequest *wdata = smb->callback_data;
 	struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink);
 	struct TCP_Server_Info *server = wdata->server;
-	struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf;
+	struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)smb->resp_buf;
 	struct cifs_credits credits = {
 		.value = 0,
 		.instance = 0,
@@ -4835,16 +4834,16 @@ smb2_writev_callback(struct mid_q_entry *mid)
 	ssize_t result = 0;
 	size_t written;
 
-	WARN_ONCE(wdata->server != mid->server,
+	WARN_ONCE(wdata->server != smb->server,
 		  "wdata server %p != mid server %p",
-		  wdata->server, mid->server);
+		  wdata->server, smb->server);
 
-	switch (mid->mid_state) {
+	switch (smb->mid_state) {
 	case MID_RESPONSE_RECEIVED:
 		trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_progress);
 		credits.value = le16_to_cpu(rsp->hdr.CreditRequest);
 		credits.instance = server->reconnect_instance;
-		result = smb2_check_receive(mid, server, 0);
+		result = smb2_check_receive(smb, server, 0);
 		if (result != 0) {
 			trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_bad);
 			break;
@@ -4927,7 +4926,7 @@ smb2_writev_callback(struct mid_q_entry *mid)
 			      0, cifs_trace_rw_credits_write_response_clear);
 	wdata->credits.value = 0;
 	cifs_write_subrequest_terminated(wdata, result ?: written);
-	release_mid(mid);
+	release_mid(smb);
 	trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0,
 			      server->credits, server->in_flight,
 			      credits.value, cifs_trace_rw_credits_write_response_add);
diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h
index 035aa1624053..6f1ce0399334 100644
--- a/fs/smb/client/smb2proto.h
+++ b/fs/smb/client/smb2proto.h
@@ -30,12 +30,12 @@ extern __le16 *cifs_convert_path_to_utf16(const char *from,
 					  struct cifs_sb_info *cifs_sb);
 
 extern int smb2_verify_signature(struct smb_rqst *, struct TCP_Server_Info *);
-extern int smb2_check_receive(struct mid_q_entry *mid,
+extern int smb2_check_receive(struct smb_message *smb,
 			      struct TCP_Server_Info *server, bool log_error);
-extern struct mid_q_entry *smb2_setup_request(struct cifs_ses *ses,
+extern struct smb_message *smb2_setup_request(struct cifs_ses *ses,
 					      struct TCP_Server_Info *,
 					      struct smb_rqst *rqst);
-extern struct mid_q_entry *smb2_setup_async_request(
+extern struct smb_message *smb2_setup_async_request(
 			struct TCP_Server_Info *server, struct smb_rqst *rqst);
 extern struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server,
 						__u64 ses_id, __u32  tid);
@@ -50,7 +50,7 @@ extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode);
 extern bool smb2_is_valid_oplock_break(char *buffer,
 				       struct TCP_Server_Info *srv);
 extern int smb3_handle_read_data(struct TCP_Server_Info *server,
-				 struct mid_q_entry *mid);
+				 struct smb_message *smb);
 extern int smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
 				struct cifs_sb_info *cifs_sb, const char *path,
 				__u32 *reparse_tag);
@@ -257,7 +257,7 @@ extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
 extern int smb2_handle_cancelled_close(struct cifs_tcon *tcon,
 				       __u64 persistent_fid,
 				       __u64 volatile_fid);
-extern int smb2_handle_cancelled_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server);
+extern int smb2_handle_cancelled_mid(struct smb_message *smb, struct TCP_Server_Info *server);
 void smb2_cancelled_close_fid(struct work_struct *work);
 extern int SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
 			 u64 persistent_file_id, u64 volatile_file_id,
diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index 475b36c27f65..5348bfd5fad0 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -756,11 +756,11 @@ smb2_seq_num_into_buf(struct TCP_Server_Info *server,
 		get_next_mid(server);
 }
 
-static struct mid_q_entry *
+static struct smb_message *
 smb2_mid_entry_alloc(const struct smb2_hdr *shdr,
 		     struct TCP_Server_Info *server)
 {
-	struct mid_q_entry *temp;
+	struct smb_message *smb;
 	unsigned int credits = le16_to_cpu(shdr->CreditCharge);
 
 	if (server == NULL) {
@@ -768,36 +768,36 @@ smb2_mid_entry_alloc(const struct smb2_hdr *shdr,
 		return NULL;
 	}
 
-	temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
-	memset(temp, 0, sizeof(struct mid_q_entry));
-	kref_init(&temp->refcount);
-	temp->mid = le64_to_cpu(shdr->MessageId);
-	temp->credits = credits > 0 ? credits : 1;
-	temp->pid = current->pid;
-	temp->command = shdr->Command; /* Always LE */
-	temp->when_alloc = jiffies;
-	temp->server = server;
+	smb = mempool_alloc(&smb_message_pool, GFP_NOFS);
+	memset(smb, 0, sizeof(*smb));
+	kref_init(&smb->refcount);
+	smb->mid = le64_to_cpu(shdr->MessageId);
+	smb->credits = credits > 0 ? credits : 1;
+	smb->pid = current->pid;
+	smb->command = shdr->Command; /* Always LE */
+	smb->when_alloc = jiffies;
+	smb->server = server;
 
 	/*
 	 * The default is for the mid to be synchronous, so the
 	 * default callback just wakes up the current task.
 	 */
 	get_task_struct(current);
-	temp->creator = current;
-	temp->callback = cifs_wake_up_task;
-	temp->callback_data = current;
+	smb->creator = current;
+	smb->callback = cifs_wake_up_task;
+	smb->callback_data = current;
 
 	atomic_inc(&mid_count);
-	temp->mid_state = MID_REQUEST_ALLOCATED;
+	smb->mid_state = MID_REQUEST_ALLOCATED;
 	trace_smb3_cmd_enter(le32_to_cpu(shdr->Id.SyncId.TreeId),
 			     le64_to_cpu(shdr->SessionId),
-			     le16_to_cpu(shdr->Command), temp->mid);
-	return temp;
+			     le16_to_cpu(shdr->Command), smb->mid);
+	return smb;
 }
 
 static int
 smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server,
-		   struct smb2_hdr *shdr, struct mid_q_entry **mid)
+		   struct smb2_hdr *shdr, struct smb_message **smb)
 {
 	spin_lock(&server->srv_lock);
 	if (server->tcpStatus == CifsExiting) {
@@ -837,18 +837,18 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server,
 	}
 	spin_unlock(&ses->ses_lock);
 
-	*mid = smb2_mid_entry_alloc(shdr, server);
-	if (*mid == NULL)
+	*smb = smb2_mid_entry_alloc(shdr, server);
+	if (*smb == NULL)
 		return -ENOMEM;
 	spin_lock(&server->mid_lock);
-	list_add_tail(&(*mid)->qhead, &server->pending_mid_q);
+	list_add_tail(&(*smb)->qhead, &server->pending_mid_q);
 	spin_unlock(&server->mid_lock);
 
 	return 0;
 }
 
 int
-smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
+smb2_check_receive(struct smb_message *mid, struct TCP_Server_Info *server,
 		   bool log_error)
 {
 	unsigned int len = mid->resp_buf_size;
@@ -873,14 +873,14 @@ smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
 	return map_smb2_to_linux_error(mid->resp_buf, log_error);
 }
 
-struct mid_q_entry *
+struct smb_message *
 smb2_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *server,
 		   struct smb_rqst *rqst)
 {
 	int rc;
 	struct smb2_hdr *shdr =
 			(struct smb2_hdr *)rqst->rq_iov[0].iov_base;
-	struct mid_q_entry *mid;
+	struct smb_message *mid;
 
 	smb2_seq_num_into_buf(server, shdr);
 
@@ -900,13 +900,13 @@ smb2_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *server,
 	return mid;
 }
 
-struct mid_q_entry *
+struct smb_message *
 smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 {
 	int rc;
 	struct smb2_hdr *shdr =
 			(struct smb2_hdr *)rqst->rq_iov[0].iov_base;
-	struct mid_q_entry *mid;
+	struct smb_message *smb;
 
 	spin_lock(&server->srv_lock);
 	if (server->tcpStatus == CifsNeedNegotiate &&
@@ -918,8 +918,8 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 
 	smb2_seq_num_into_buf(server, shdr);
 
-	mid = smb2_mid_entry_alloc(shdr, server);
-	if (mid == NULL) {
+	smb = smb2_mid_entry_alloc(shdr, server);
+	if (smb == NULL) {
 		revert_current_mid_from_hdr(server, shdr);
 		return ERR_PTR(-ENOMEM);
 	}
@@ -927,11 +927,11 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 	rc = smb2_sign_rqst(rqst, server);
 	if (rc) {
 		revert_current_mid_from_hdr(server, shdr);
-		release_mid(mid);
+		release_mid(smb);
 		return ERR_PTR(rc);
 	}
 
-	return mid;
+	return smb;
 }
 
 int
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index 68c73e22c3c9..a105e0ddf81a 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -31,42 +31,42 @@
 #include "compress.h"
 
 void
-cifs_wake_up_task(struct mid_q_entry *mid)
+cifs_wake_up_task(struct smb_message *smb)
 {
-	if (mid->mid_state == MID_RESPONSE_RECEIVED)
-		mid->mid_state = MID_RESPONSE_READY;
-	wake_up_process(mid->callback_data);
+	if (smb->mid_state == MID_RESPONSE_RECEIVED)
+		smb->mid_state = MID_RESPONSE_READY;
+	wake_up_process(smb->callback_data);
 }
 
 void __release_mid(struct kref *refcount)
 {
-	struct mid_q_entry *midEntry =
-			container_of(refcount, struct mid_q_entry, refcount);
+	struct smb_message *smb =
+			container_of(refcount, struct smb_message, refcount);
 #ifdef CONFIG_CIFS_STATS2
-	__le16 command = midEntry->server->vals->lock_cmd;
-	__u16 smb_cmd = le16_to_cpu(midEntry->command);
+	__le16 command = smb->server->vals->lock_cmd;
+	__u16 smb_cmd = le16_to_cpu(smb->command);
 	unsigned long now;
 	unsigned long roundtrip_time;
 #endif
-	struct TCP_Server_Info *server = midEntry->server;
+	struct TCP_Server_Info *server = smb->server;
 
-	if (midEntry->resp_buf && (midEntry->mid_flags & MID_WAIT_CANCELLED) &&
-	    (midEntry->mid_state == MID_RESPONSE_RECEIVED ||
-	     midEntry->mid_state == MID_RESPONSE_READY) &&
+	if (smb->resp_buf && (smb->mid_flags & MID_WAIT_CANCELLED) &&
+	    (smb->mid_state == MID_RESPONSE_RECEIVED ||
+	     smb->mid_state == MID_RESPONSE_READY) &&
 	    server->ops->handle_cancelled_mid)
-		server->ops->handle_cancelled_mid(midEntry, server);
+		server->ops->handle_cancelled_mid(smb, server);
 
-	midEntry->mid_state = MID_FREE;
+	smb->mid_state = MID_FREE;
 	atomic_dec(&mid_count);
-	if (midEntry->large_buf)
-		cifs_buf_release(midEntry->resp_buf);
+	if (smb->large_buf)
+		cifs_buf_release(smb->resp_buf);
 	else
-		cifs_small_buf_release(midEntry->resp_buf);
+		cifs_small_buf_release(smb->resp_buf);
 #ifdef CONFIG_CIFS_STATS2
 	now = jiffies;
-	if (now < midEntry->when_alloc)
+	if (now < smb->when_alloc)
 		cifs_server_dbg(VFS, "Invalid mid allocation time\n");
-	roundtrip_time = now - midEntry->when_alloc;
+	roundtrip_time = now - smb->when_alloc;
 
 	if (smb_cmd < NUMBER_OF_SMB2_COMMANDS) {
 		if (atomic_read(&server->num_cmds[smb_cmd]) == 0) {
@@ -92,8 +92,8 @@ void __release_mid(struct kref *refcount)
 	 * checks
 	 */
 	if ((slow_rsp_threshold != 0) &&
-	    time_after(now, midEntry->when_alloc + (slow_rsp_threshold * HZ)) &&
-	    (midEntry->command != command)) {
+	    time_after(now, smb->when_alloc + (slow_rsp_threshold * HZ)) &&
+	    (smb->command != command)) {
 		/*
 		 * smb2slowcmd[NUMBER_OF_SMB2_COMMANDS] counts by command
 		 * NB: le16_to_cpu returns unsigned so can not be negative below
@@ -101,34 +101,35 @@ void __release_mid(struct kref *refcount)
 		if (smb_cmd < NUMBER_OF_SMB2_COMMANDS)
 			cifs_stats_inc(&server->smb2slowcmd[smb_cmd]);
 
-		trace_smb3_slow_rsp(smb_cmd, midEntry->mid, midEntry->pid,
-			       midEntry->when_sent, midEntry->when_received);
+		trace_smb3_slow_rsp(smb_cmd, smb->mid, smb->pid,
+				    smb->when_sent, smb->when_received);
 		if (cifsFYI & CIFS_TIMER) {
 			pr_debug("slow rsp: cmd %d mid %llu",
-				 midEntry->command, midEntry->mid);
+				 smb->command, smb->mid);
 			cifs_info("A: 0x%lx S: 0x%lx R: 0x%lx\n",
-				  now - midEntry->when_alloc,
-				  now - midEntry->when_sent,
-				  now - midEntry->when_received);
+				  now - smb->when_alloc,
+				  now - smb->when_sent,
+				  now - smb->when_received);
 		}
 	}
 #endif
-	put_task_struct(midEntry->creator);
+	put_task_struct(smb->creator);
 
-	mempool_free(midEntry, cifs_mid_poolp);
+	mempool_free(smb, &smb_message_pool);
 }
 
 void
-delete_mid(struct mid_q_entry *mid)
+delete_mid(struct smb_message *smb)
 {
-	spin_lock(&mid->server->mid_lock);
-	if (!(mid->mid_flags & MID_DELETED)) {
-		list_del_init(&mid->qhead);
-		mid->mid_flags |= MID_DELETED;
+	spin_lock(&smb->server->mid_lock);
+
+	if (!(smb->mid_flags & MID_DELETED)) {
+		list_del_init(&smb->qhead);
+		smb->mid_flags |= MID_DELETED;
 	}
-	spin_unlock(&mid->server->mid_lock);
+	spin_unlock(&smb->server->mid_lock);
 
-	release_mid(mid);
+	release_mid(smb);
 }
 
 /*
@@ -633,13 +634,13 @@ cifs_wait_mtu_credits(struct TCP_Server_Info *server, size_t size,
 	return 0;
 }
 
-int wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
+int wait_for_response(struct TCP_Server_Info *server, struct smb_message *smb)
 {
 	int error;
 
 	error = wait_event_state(server->response_q,
-				 midQ->mid_state != MID_REQUEST_SUBMITTED &&
-				 midQ->mid_state != MID_RESPONSE_RECEIVED,
+				 smb->mid_state != MID_REQUEST_SUBMITTED &&
+				 smb->mid_state != MID_RESPONSE_RECEIVED,
 				 (TASK_KILLABLE|TASK_FREEZABLE_UNSAFE));
 	if (error < 0)
 		return -ERESTARTSYS;
@@ -653,12 +654,12 @@ int wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
  */
 int
 cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
-		mid_receive_t *receive, mid_callback_t *callback,
-		mid_handle_t *handle, void *cbdata, const int flags,
+		mid_receive_t receive, mid_callback_t callback,
+		mid_handle_t handle, void *cbdata, const int flags,
 		const struct cifs_credits *exist_credits)
 {
 	int rc;
-	struct mid_q_entry *mid;
+	struct smb_message *smb;
 	struct cifs_credits credits = { .value = 0, .instance = 0 };
 	unsigned int instance;
 	int optype;
@@ -687,35 +688,35 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 		return -EAGAIN;
 	}
 
-	mid = server->ops->setup_async_request(server, rqst);
-	if (IS_ERR(mid)) {
+	smb = server->ops->setup_async_request(server, rqst);
+	if (IS_ERR(smb)) {
 		cifs_server_unlock(server);
 		add_credits_and_wake_if(server, &credits, optype);
-		return PTR_ERR(mid);
+		return PTR_ERR(smb);
 	}
 
-	mid->receive = receive;
-	mid->callback = callback;
-	mid->callback_data = cbdata;
-	mid->handle = handle;
-	mid->mid_state = MID_REQUEST_SUBMITTED;
+	smb->receive = receive;
+	smb->callback = callback;
+	smb->callback_data = cbdata;
+	smb->handle = handle;
+	smb->mid_state = MID_REQUEST_SUBMITTED;
 
 	/* put it on the pending_mid_q */
 	spin_lock(&server->mid_lock);
-	list_add_tail(&mid->qhead, &server->pending_mid_q);
+	list_add_tail(&smb->qhead, &server->pending_mid_q);
 	spin_unlock(&server->mid_lock);
 
 	/*
 	 * Need to store the time in mid before calling I/O. For call_async,
 	 * I/O response may come back and free the mid entry on another thread.
 	 */
-	cifs_save_when_sent(mid);
+	cifs_save_when_sent(smb);
 	rc = smb_send_rqst(server, 1, rqst, flags);
 
 	if (rc < 0) {
-		revert_current_mid(server, mid->credits);
+		revert_current_mid(server, smb->credits);
 		server->sequence_number -= 2;
-		delete_mid(mid);
+		delete_mid(smb);
 	}
 
 	cifs_server_unlock(server);
@@ -727,15 +728,15 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 	return rc;
 }
 
-int cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
+int cifs_sync_mid_result(struct smb_message *smb, struct TCP_Server_Info *server)
 {
 	int rc = 0;
 
 	cifs_dbg(FYI, "%s: cmd=%d mid=%llu state=%d\n",
-		 __func__, le16_to_cpu(mid->command), mid->mid, mid->mid_state);
+		 __func__, le16_to_cpu(smb->command), smb->mid, smb->mid_state);
 
 	spin_lock(&server->mid_lock);
-	switch (mid->mid_state) {
+	switch (smb->mid_state) {
 	case MID_RESPONSE_READY:
 		spin_unlock(&server->mid_lock);
 		return rc;
@@ -749,53 +750,53 @@ int cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server
 		rc = -EHOSTDOWN;
 		break;
 	case MID_RC:
-		rc = mid->mid_rc;
+		rc = smb->mid_rc;
 		break;
 	default:
-		if (!(mid->mid_flags & MID_DELETED)) {
-			list_del_init(&mid->qhead);
-			mid->mid_flags |= MID_DELETED;
+		if (!(smb->mid_flags & MID_DELETED)) {
+			list_del_init(&smb->qhead);
+			smb->mid_flags |= MID_DELETED;
 		}
 		spin_unlock(&server->mid_lock);
 		cifs_server_dbg(VFS, "%s: invalid mid state mid=%llu state=%d\n",
-			 __func__, mid->mid, mid->mid_state);
+			 __func__, smb->mid, smb->mid_state);
 		rc = -EIO;
 		goto sync_mid_done;
 	}
 	spin_unlock(&server->mid_lock);
 
 sync_mid_done:
-	release_mid(mid);
+	release_mid(smb);
 	return rc;
 }
 
 static void
-cifs_compound_callback(struct mid_q_entry *mid)
+cifs_compound_callback(struct smb_message *smb)
 {
-	struct TCP_Server_Info *server = mid->server;
+	struct TCP_Server_Info *server = smb->server;
 	struct cifs_credits credits = {
-		.value = server->ops->get_credits(mid),
+		.value = server->ops->get_credits(smb),
 		.instance = server->reconnect_instance,
 	};
 
-	add_credits(server, &credits, mid->optype);
+	add_credits(server, &credits, smb->optype);
 
-	if (mid->mid_state == MID_RESPONSE_RECEIVED)
-		mid->mid_state = MID_RESPONSE_READY;
+	if (smb->mid_state == MID_RESPONSE_RECEIVED)
+		smb->mid_state = MID_RESPONSE_READY;
 }
 
 static void
-cifs_compound_last_callback(struct mid_q_entry *mid)
+cifs_compound_last_callback(struct smb_message *smb)
 {
-	cifs_compound_callback(mid);
-	cifs_wake_up_task(mid);
+	cifs_compound_callback(smb);
+	cifs_wake_up_task(smb);
 }
 
 static void
-cifs_cancelled_callback(struct mid_q_entry *mid)
+cifs_cancelled_callback(struct smb_message *smb)
 {
-	cifs_compound_callback(mid);
-	release_mid(mid);
+	cifs_compound_callback(smb);
+	release_mid(smb);
 }
 
 /*
@@ -859,7 +860,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 		   int *resp_buf_type, struct kvec *resp_iov)
 {
 	int i, j, optype, rc = 0;
-	struct mid_q_entry *midQ[MAX_COMPOUND];
+	struct smb_message *smb[MAX_COMPOUND];
 	bool cancelled_mid[MAX_COMPOUND] = {false};
 	struct cifs_credits credits[MAX_COMPOUND] = {
 		{ .value = 0, .instance = 0 }
@@ -925,35 +926,35 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 	}
 
 	for (i = 0; i < num_rqst; i++) {
-		midQ[i] = server->ops->setup_request(ses, server, &rqst[i]);
-		if (IS_ERR(midQ[i])) {
+		smb[i] = server->ops->setup_request(ses, server, &rqst[i]);
+		if (IS_ERR(smb[i])) {
 			revert_current_mid(server, i);
 			for (j = 0; j < i; j++)
-				delete_mid(midQ[j]);
+				delete_mid(smb[j]);
 			cifs_server_unlock(server);
 
 			/* Update # of requests on wire to server */
 			for (j = 0; j < num_rqst; j++)
 				add_credits(server, &credits[j], optype);
-			return PTR_ERR(midQ[i]);
+			return PTR_ERR(smb[i]);
 		}
 
-		midQ[i]->mid_state = MID_REQUEST_SUBMITTED;
-		midQ[i]->optype = optype;
+		smb[i]->mid_state = MID_REQUEST_SUBMITTED;
+		smb[i]->optype = optype;
 		/*
 		 * Invoke callback for every part of the compound chain
 		 * to calculate credits properly. Wake up this thread only when
 		 * the last element is received.
 		 */
 		if (i < num_rqst - 1)
-			midQ[i]->callback = cifs_compound_callback;
+			smb[i]->callback = cifs_compound_callback;
 		else
-			midQ[i]->callback = cifs_compound_last_callback;
+			smb[i]->callback = cifs_compound_last_callback;
 	}
 	rc = smb_send_rqst(server, num_rqst, rqst, flags);
 
 	for (i = 0; i < num_rqst; i++)
-		cifs_save_when_sent(midQ[i]);
+		cifs_save_when_sent(smb[i]);
 
 	if (rc < 0) {
 		revert_current_mid(server, num_rqst);
@@ -996,20 +997,20 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 	spin_unlock(&ses->ses_lock);
 
 	for (i = 0; i < num_rqst; i++) {
-		rc = wait_for_response(server, midQ[i]);
+		rc = wait_for_response(server, smb[i]);
 		if (rc != 0)
 			break;
 	}
 	if (rc != 0) {
 		for (; i < num_rqst; i++) {
 			cifs_server_dbg(FYI, "Cancelling wait for mid %llu cmd: %d\n",
-				 midQ[i]->mid, le16_to_cpu(midQ[i]->command));
-			send_cancel(server, &rqst[i], midQ[i]);
+				 smb[i]->mid, le16_to_cpu(smb[i]->command));
+			send_cancel(server, &rqst[i], smb[i]);
 			spin_lock(&server->mid_lock);
-			midQ[i]->mid_flags |= MID_WAIT_CANCELLED;
-			if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED ||
-			    midQ[i]->mid_state == MID_RESPONSE_RECEIVED) {
-				midQ[i]->callback = cifs_cancelled_callback;
+			smb[i]->mid_flags |= MID_WAIT_CANCELLED;
+			if (smb[i]->mid_state == MID_REQUEST_SUBMITTED ||
+			    smb[i]->mid_state == MID_RESPONSE_RECEIVED) {
+				smb[i]->callback = cifs_cancelled_callback;
 				cancelled_mid[i] = true;
 				credits[i].value = 0;
 			}
@@ -1021,36 +1022,36 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 		if (rc < 0)
 			goto out;
 
-		rc = cifs_sync_mid_result(midQ[i], server);
+		rc = cifs_sync_mid_result(smb[i], server);
 		if (rc != 0) {
 			/* mark this mid as cancelled to not free it below */
 			cancelled_mid[i] = true;
 			goto out;
 		}
 
-		if (!midQ[i]->resp_buf ||
-		    midQ[i]->mid_state != MID_RESPONSE_READY) {
+		if (!smb[i]->resp_buf ||
+		    smb[i]->mid_state != MID_RESPONSE_READY) {
 			rc = -EIO;
 			cifs_dbg(FYI, "Bad MID state?\n");
 			goto out;
 		}
 
-		buf = (char *)midQ[i]->resp_buf;
+		buf = (char *)smb[i]->resp_buf;
 		resp_iov[i].iov_base = buf;
-		resp_iov[i].iov_len = midQ[i]->resp_buf_size +
+		resp_iov[i].iov_len = smb[i]->resp_buf_size +
 			HEADER_PREAMBLE_SIZE(server);
 
-		if (midQ[i]->large_buf)
+		if (smb[i]->large_buf)
 			resp_buf_type[i] = CIFS_LARGE_BUFFER;
 		else
 			resp_buf_type[i] = CIFS_SMALL_BUFFER;
 
-		rc = server->ops->check_receive(midQ[i], server,
+		rc = server->ops->check_receive(smb[i], server,
 						     flags & CIFS_LOG_ERROR);
 
 		/* mark it so buf will not be freed by delete_mid */
 		if ((flags & CIFS_NO_RSP_BUF) == 0)
-			midQ[i]->resp_buf = NULL;
+			smb[i]->resp_buf = NULL;
 
 	}
 
@@ -1080,7 +1081,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 	 */
 	for (i = 0; i < num_rqst; i++) {
 		if (!cancelled_mid[i])
-			delete_mid(midQ[i]);
+			delete_mid(smb[i]);
 	}
 
 	return rc;
@@ -1123,38 +1124,38 @@ cifs_discard_remaining_data(struct TCP_Server_Info *server)
 }
 
 static int
-__cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid,
+__cifs_readv_discard(struct TCP_Server_Info *server, struct smb_message *smb,
 		     bool malformed)
 {
 	int length;
 
 	length = cifs_discard_remaining_data(server);
-	dequeue_mid(mid, malformed);
-	mid->resp_buf = server->smallbuf;
+	dequeue_mid(smb, malformed);
+	smb->resp_buf = server->smallbuf;
 	server->smallbuf = NULL;
 	return length;
 }
 
 static int
-cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
+cifs_readv_discard(struct TCP_Server_Info *server, struct smb_message *smb)
 {
-	struct cifs_io_subrequest *rdata = mid->callback_data;
+	struct cifs_io_subrequest *rdata = smb->callback_data;
 
-	return  __cifs_readv_discard(server, mid, rdata->result);
+	return  __cifs_readv_discard(server, smb, rdata->result);
 }
 
 int
-cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
+cifs_readv_receive(struct TCP_Server_Info *server, struct smb_message *smb)
 {
 	int length, len;
 	unsigned int data_offset, data_len;
-	struct cifs_io_subrequest *rdata = mid->callback_data;
+	struct cifs_io_subrequest *rdata = smb->callback_data;
 	char *buf = server->smallbuf;
 	unsigned int buflen = server->pdu_size + HEADER_PREAMBLE_SIZE(server);
 	bool use_rdma_mr = false;
 
 	cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%zu\n",
-		 __func__, mid->mid, rdata->subreq.start, rdata->subreq.len);
+		 __func__, smb->mid, rdata->subreq.start, rdata->subreq.len);
 
 	/*
 	 * read the rest of READ_RSP header (sans Data array), or whatever we
@@ -1199,7 +1200,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 		cifs_dbg(FYI, "%s: server returned error %d\n",
 			 __func__, rdata->result);
 		/* normal error on read response */
-		return __cifs_readv_discard(server, mid, false);
+		return __cifs_readv_discard(server, smb, false);
 	}
 
 	/* Is there enough to get to the rest of the READ_RSP header? */
@@ -1208,7 +1209,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 			 __func__, server->total_read,
 			 server->vals->read_rsp_size);
 		rdata->result = -EIO;
-		return cifs_readv_discard(server, mid);
+		return cifs_readv_discard(server, smb);
 	}
 
 	data_offset = server->ops->read_data_offset(buf) +
@@ -1227,7 +1228,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 		cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
 			 __func__, data_offset);
 		rdata->result = -EIO;
-		return cifs_readv_discard(server, mid);
+		return cifs_readv_discard(server, smb);
 	}
 
 	cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
@@ -1251,7 +1252,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 	if (!use_rdma_mr && (data_offset + data_len > buflen)) {
 		/* data_len is corrupt -- discard frame */
 		rdata->result = -EIO;
-		return cifs_readv_discard(server, mid);
+		return cifs_readv_discard(server, smb);
 	}
 
 #ifdef CONFIG_CIFS_SMB_DIRECT
@@ -1270,10 +1271,10 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 
 	/* discard anything left over */
 	if (server->total_read < buflen)
-		return cifs_readv_discard(server, mid);
+		return cifs_readv_discard(server, smb);
 
-	dequeue_mid(mid, false);
-	mid->resp_buf = server->smallbuf;
+	dequeue_mid(smb, false);
+	smb->resp_buf = server->smallbuf;
 	server->smallbuf = NULL;
 	return length;
 }


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 08/31] cifs: Keep the CPU-endian command ID around
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (6 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 07/31] cifs: Rename mid_q_entry to smb_message David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 09/31] cifs: Rename SMB2_xxxx_HE to SMB2_xxxx David Howells
                   ` (26 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Because the command IDs are small integers in a sequence, the C compiler
can generate better code if they're cpu-endian.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/cifs_debug.c    |   2 +-
 fs/smb/client/cifsglob.h      |   4 +-
 fs/smb/client/cifstransport.c |   4 +-
 fs/smb/client/compress.c      |   4 +-
 fs/smb/client/smb1ops.c       |   3 +-
 fs/smb/client/smb2misc.c      |  30 +++++-----
 fs/smb/client/smb2ops.c       |  19 ++++---
 fs/smb/client/smb2pdu.c       | 103 ++++++++++++++++++----------------
 fs/smb/client/smb2transport.c |  20 +++----
 fs/smb/client/transport.c     |  12 ++--
 fs/smb/common/smb2pdu.h       |  68 +++++++++-------------
 fs/smb/server/oplock.c        |   4 +-
 fs/smb/server/smb2misc.c      |  40 ++++++-------
 fs/smb/server/smb2ops.c       |   8 +--
 fs/smb/server/smb2pdu.c       |  14 ++---
 15 files changed, 162 insertions(+), 173 deletions(-)

diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c
index 163e8954b940..cba30f339d6b 100644
--- a/fs/smb/client/cifs_debug.c
+++ b/fs/smb/client/cifs_debug.c
@@ -627,7 +627,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
 				list_for_each_entry(smb, &chan_server->pending_mid_q, qhead) {
 					seq_printf(m, "\n\t\tState: %d com: %d pid: %d cbdata: %p mid %llu",
 						   smb->mid_state,
-						   le16_to_cpu(smb->command),
+						   smb->command_id,
 						   smb->pid,
 						   smb->callback_data,
 						   smb->mid);
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 5d523099e298..60350213a02b 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -647,7 +647,7 @@ struct smb_version_values {
 	size_t		header_size;
 	size_t		max_header_size;
 	size_t		read_rsp_size;
-	__le16		lock_cmd;
+	enum smb2_command lock_cmd;
 	unsigned int	cap_unix;
 	unsigned int	cap_nt_find;
 	unsigned int	cap_large_files;
@@ -1728,8 +1728,8 @@ struct smb_message {
 	int mid_state;	/* wish this were enum but can not pass to wait_event */
 	int mid_rc;		/* rc for MID_RC */
 	unsigned int mid_flags;
-	__le16 command;		/* smb command code */
 	unsigned int optype;	/* operation type */
+	enum smb2_command command_id;	/* smb command code */
 	bool large_buf:1;	/* if valid response, is pointer to large buf */
 	bool multiRsp:1;	/* multiple trans2 responses for one request  */
 	bool multiEnd:1;	/* both received */
diff --git a/fs/smb/client/cifstransport.c b/fs/smb/client/cifstransport.c
index 20709ae52d26..a3400a757968 100644
--- a/fs/smb/client/cifstransport.c
+++ b/fs/smb/client/cifstransport.c
@@ -48,8 +48,8 @@ alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
 	kref_init(&smb->refcount);
 	smb->mid = get_mid(smb_buffer);
 	smb->pid = current->pid;
-	smb->command = cpu_to_le16(smb_buffer->Command);
-	cifs_dbg(FYI, "For smb_command %d\n", smb_buffer->Command);
+	smb->command_id = le16_to_cpu(smb_buffer->Command);
+	cifs_dbg(FYI, "For smb_command %d\n", smb->command_id);
 	/* easier to use jiffies */
 	/* when mid allocated can be before when sent */
 	smb->when_alloc = jiffies;
diff --git a/fs/smb/client/compress.c b/fs/smb/client/compress.c
index 766b4de13da7..f52710425151 100644
--- a/fs/smb/client/compress.c
+++ b/fs/smb/client/compress.c
@@ -303,7 +303,7 @@ bool should_compress(const struct cifs_tcon *tcon, const struct smb_rqst *rq)
 	if (!(tcon->share_flags & SMB2_SHAREFLAG_COMPRESS_DATA))
 		return false;
 
-	if (shdr->Command == SMB2_WRITE) {
+	if (le16_to_cpu(shdr->Command) == SMB2_WRITE_HE) {
 		const struct smb2_write_req *wreq = rq->rq_iov->iov_base;
 
 		if (le32_to_cpu(wreq->Length) < SMB_COMPRESS_MIN_LEN)
@@ -312,7 +312,7 @@ bool should_compress(const struct cifs_tcon *tcon, const struct smb_rqst *rq)
 		return is_compressible(&rq->rq_iter);
 	}
 
-	return (shdr->Command == SMB2_READ);
+	return le16_to_cpu(shdr->Command) == SMB2_READ_HE;
 }
 
 int smb_compress(struct TCP_Server_Info *server, struct smb_rqst *rq, compress_send_fn send_fn)
diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
index ba301c94d4ff..dc2daba936e2 100644
--- a/fs/smb/client/smb1ops.c
+++ b/fs/smb/client/smb1ops.c
@@ -93,12 +93,13 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buffer)
 {
 	struct smb_hdr *buf = (struct smb_hdr *)buffer;
 	struct smb_message *smb;
+	enum smb2_command command = le16_to_cpu(buf->Command);
 
 	spin_lock(&server->mid_lock);
 	list_for_each_entry(smb, &server->pending_mid_q, qhead) {
 		if (compare_mid(smb->mid, buf) &&
 		    smb->mid_state == MID_REQUEST_SUBMITTED &&
-		    le16_to_cpu(smb->command) == buf->Command) {
+		    smb->command_id == command) {
 			kref_get(&smb->refcount);
 			spin_unlock(&server->mid_lock);
 			return smb;
diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c
index f1b0546c7858..f6280e3d4e55 100644
--- a/fs/smb/client/smb2misc.c
+++ b/fs/smb/client/smb2misc.c
@@ -33,7 +33,7 @@ check_smb2_hdr(struct smb2_hdr *shdr, __u64 mid)
 			return 0;
 		else {
 			/* only one valid case where server sends us request */
-			if (shdr->Command == SMB2_OPLOCK_BREAK)
+			if (le16_to_cpu(shdr->Command) == SMB2_OPLOCK_BREAK_HE)
 				return 0;
 			else
 				cifs_dbg(VFS, "Received Request not response\n");
@@ -138,9 +138,9 @@ smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *server)
 	struct TCP_Server_Info *pserver;
 	struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
 	struct smb2_pdu *pdu = (struct smb2_pdu *)shdr;
+	enum smb2_command command;
 	int hdr_size = sizeof(struct smb2_hdr);
 	int pdu_size = sizeof(struct smb2_pdu);
-	int command;
 	__u32 calc_len; /* calculated length */
 	__u64 mid;
 
@@ -330,49 +330,49 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *shdr)
 	 * of the data buffer offset and data buffer length for the particular
 	 * command.
 	 */
-	switch (shdr->Command) {
-	case SMB2_NEGOTIATE:
+	switch (le16_to_cpu(shdr->Command)) {
+	case SMB2_NEGOTIATE_HE:
 		*off = le16_to_cpu(
 		  ((struct smb2_negotiate_rsp *)shdr)->SecurityBufferOffset);
 		*len = le16_to_cpu(
 		  ((struct smb2_negotiate_rsp *)shdr)->SecurityBufferLength);
 		break;
-	case SMB2_SESSION_SETUP:
+	case SMB2_SESSION_SETUP_HE:
 		*off = le16_to_cpu(
 		  ((struct smb2_sess_setup_rsp *)shdr)->SecurityBufferOffset);
 		*len = le16_to_cpu(
 		  ((struct smb2_sess_setup_rsp *)shdr)->SecurityBufferLength);
 		break;
-	case SMB2_CREATE:
+	case SMB2_CREATE_HE:
 		*off = le32_to_cpu(
 		    ((struct smb2_create_rsp *)shdr)->CreateContextsOffset);
 		*len = le32_to_cpu(
 		    ((struct smb2_create_rsp *)shdr)->CreateContextsLength);
 		break;
-	case SMB2_QUERY_INFO:
+	case SMB2_QUERY_INFO_HE:
 		*off = le16_to_cpu(
 		    ((struct smb2_query_info_rsp *)shdr)->OutputBufferOffset);
 		*len = le32_to_cpu(
 		    ((struct smb2_query_info_rsp *)shdr)->OutputBufferLength);
 		break;
-	case SMB2_READ:
+	case SMB2_READ_HE:
 		/* TODO: is this a bug ? */
 		*off = ((struct smb2_read_rsp *)shdr)->DataOffset;
 		*len = le32_to_cpu(((struct smb2_read_rsp *)shdr)->DataLength);
 		break;
-	case SMB2_QUERY_DIRECTORY:
+	case SMB2_QUERY_DIRECTORY_HE:
 		*off = le16_to_cpu(
 		  ((struct smb2_query_directory_rsp *)shdr)->OutputBufferOffset);
 		*len = le32_to_cpu(
 		  ((struct smb2_query_directory_rsp *)shdr)->OutputBufferLength);
 		break;
-	case SMB2_IOCTL:
+	case SMB2_IOCTL_HE:
 		*off = le32_to_cpu(
 		  ((struct smb2_ioctl_rsp *)shdr)->OutputOffset);
 		*len = le32_to_cpu(
 		  ((struct smb2_ioctl_rsp *)shdr)->OutputCount);
 		break;
-	case SMB2_CHANGE_NOTIFY:
+	case SMB2_CHANGE_NOTIFY_HE:
 		*off = le16_to_cpu(
 		  ((struct smb2_change_notify_rsp *)shdr)->OutputBufferOffset);
 		*len = le32_to_cpu(
@@ -680,7 +680,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
 
 	cifs_dbg(FYI, "Checking for oplock break\n");
 
-	if (rsp->hdr.Command != SMB2_OPLOCK_BREAK)
+	if (rsp->hdr.Command != cpu_to_le32(SMB2_OPLOCK_BREAK_HE))
 		return false;
 
 	if (rsp->StructureSize !=
@@ -846,7 +846,7 @@ smb2_handle_cancelled_mid(struct smb_message *smb, struct TCP_Server_Info *serve
 	struct cifs_tcon *tcon;
 	int rc;
 
-	if ((smb->optype & CIFS_CP_CREATE_CLOSE_OP) || hdr->Command != SMB2_CREATE ||
+	if ((smb->optype & CIFS_CP_CREATE_CLOSE_OP) || smb->command_id != SMB2_CREATE_HE ||
 	    hdr->Status != STATUS_SUCCESS)
 		return 0;
 
@@ -887,7 +887,7 @@ smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *server,
 
 	hdr = (struct smb2_hdr *)iov[0].iov_base;
 	/* neg prot are always taken */
-	if (hdr->Command == SMB2_NEGOTIATE)
+	if (le16_to_cpu(hdr->Command) == SMB2_NEGOTIATE_HE)
 		goto ok;
 
 	/*
@@ -898,7 +898,7 @@ smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *server,
 	if (server->dialect != SMB311_PROT_ID)
 		return 0;
 
-	if (hdr->Command != SMB2_SESSION_SETUP)
+	if (le16_to_cpu(hdr->Command) != SMB2_SESSION_SETUP_HE)
 		return 0;
 
 	/* skip last sess setup response */
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index a7ba4a77721e..0116bf348a76 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -394,6 +394,7 @@ __smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue)
 {
 	struct smb_message *smb;
 	struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
+	enum smb2_command command = le16_to_cpu(shdr->Command);
 	__u64 wire_mid = le64_to_cpu(shdr->MessageId);
 
 	if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
@@ -405,7 +406,7 @@ __smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue)
 	list_for_each_entry(smb, &server->pending_mid_q, qhead) {
 		if ((smb->mid == wire_mid) &&
 		    (smb->mid_state == MID_REQUEST_SUBMITTED) &&
-		    (smb->command == shdr->Command)) {
+		    (smb->command_id == command)) {
 			kref_get(&smb->refcount);
 			if (dequeue) {
 				list_del_init(&smb->qhead);
@@ -4625,7 +4626,7 @@ handle_read_data(struct TCP_Server_Info *server, struct smb_message *smb,
 	int length;
 	bool use_rdma_mr = false;
 
-	if (shdr->Command != SMB2_READ) {
+	if (le16_to_cpu(shdr->Command) != SMB2_READ_HE) {
 		cifs_server_dbg(VFS, "only big read responses are supported\n");
 		return -EOPNOTSUPP;
 	}
@@ -5714,7 +5715,7 @@ struct smb_version_values smb20_values = {
 	.header_preamble_size = 0,
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK,
+	.lock_cmd = SMB2_LOCK_HE,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
@@ -5736,7 +5737,7 @@ struct smb_version_values smb21_values = {
 	.header_preamble_size = 0,
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK,
+	.lock_cmd = SMB2_LOCK_HE,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
@@ -5757,7 +5758,7 @@ struct smb_version_values smb3any_values = {
 	.header_preamble_size = 0,
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK,
+	.lock_cmd = SMB2_LOCK_HE,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
@@ -5778,7 +5779,7 @@ struct smb_version_values smbdefault_values = {
 	.header_preamble_size = 0,
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK,
+	.lock_cmd = SMB2_LOCK_HE,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
@@ -5799,7 +5800,7 @@ struct smb_version_values smb30_values = {
 	.header_preamble_size = 0,
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK,
+	.lock_cmd = SMB2_LOCK_HE,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
@@ -5820,7 +5821,7 @@ struct smb_version_values smb302_values = {
 	.header_preamble_size = 0,
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK,
+	.lock_cmd = SMB2_LOCK_HE,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
@@ -5841,7 +5842,7 @@ struct smb_version_values smb311_values = {
 	.header_preamble_size = 0,
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK,
+	.lock_cmd = SMB2_LOCK_HE,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 645d67d04a8d..97a267ce2a62 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -92,7 +92,7 @@ int smb3_encryption_required(const struct cifs_tcon *tcon)
 }
 
 static void
-smb2_hdr_assemble(struct smb2_hdr *shdr, __le16 smb2_cmd,
+smb2_hdr_assemble(struct smb2_hdr *shdr, enum smb2_command smb2_cmd,
 		  const struct cifs_tcon *tcon,
 		  struct TCP_Server_Info *server)
 {
@@ -100,7 +100,7 @@ smb2_hdr_assemble(struct smb2_hdr *shdr, __le16 smb2_cmd,
 
 	shdr->ProtocolId = SMB2_PROTO_NUMBER;
 	shdr->StructureSize = cpu_to_le16(64);
-	shdr->Command = smb2_cmd;
+	shdr->Command = cpu_to_le16(smb2_cmd);
 
 	if (server) {
 		/* After reconnect SMB3 must set ChannelSequence on subsequent reqs */
@@ -215,7 +215,7 @@ cifs_chan_skip_or_disable(struct cifs_ses *ses,
 }
 
 static int
-smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
+smb2_reconnect(enum smb2_command smb2_command, struct cifs_tcon *tcon,
 	       struct TCP_Server_Info *server, bool from_reconnect)
 {
 	struct cifs_ses *ses;
@@ -230,7 +230,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
 	if (tcon == NULL)
 		return 0;
 
-	if (smb2_command == SMB2_TREE_CONNECT)
+	if (smb2_command == SMB2_TREE_CONNECT_HE)
 		return 0;
 
 	spin_lock(&tcon->tc_lock);
@@ -238,7 +238,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
 		/*
 		 * only tree disconnect allowed when disconnecting ...
 		 */
-		if (smb2_command != SMB2_TREE_DISCONNECT) {
+		if (smb2_command != SMB2_TREE_DISCONNECT_HE) {
 			spin_unlock(&tcon->tc_lock);
 			cifs_dbg(FYI, "can not send cmd %d while umounting\n",
 				 smb2_command);
@@ -269,12 +269,14 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
 		/*
 		 * BB Should we keep oplock break and add flush to exceptions?
 		 */
-		case SMB2_TREE_DISCONNECT:
-		case SMB2_CANCEL:
-		case SMB2_CLOSE:
-		case SMB2_OPLOCK_BREAK:
+		case SMB2_TREE_DISCONNECT_HE:
+		case SMB2_CANCEL_HE:
+		case SMB2_CLOSE_HE:
+		case SMB2_OPLOCK_BREAK_HE:
 			spin_unlock(&server->srv_lock);
 			return -EAGAIN;
+		default:
+			break;
 		}
 	}
 
@@ -462,7 +464,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
 	ses->flags &= ~CIFS_SES_FLAG_SCALE_CHANNELS;
 	spin_unlock(&ses->ses_lock);
 
-	if (smb2_command != SMB2_INTERNAL_CMD)
+	if (smb2_command != SMB2_INTERNAL_CMD_HE)
 		mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
 
 	atomic_inc(&tconInfoReconnectCount);
@@ -476,29 +478,32 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
 	 * case it and skip above?
 	 */
 	switch (smb2_command) {
-	case SMB2_FLUSH:
-	case SMB2_READ:
-	case SMB2_WRITE:
-	case SMB2_LOCK:
-	case SMB2_QUERY_DIRECTORY:
-	case SMB2_CHANGE_NOTIFY:
-	case SMB2_QUERY_INFO:
-	case SMB2_SET_INFO:
-	case SMB2_IOCTL:
+	case SMB2_FLUSH_HE:
+	case SMB2_READ_HE:
+	case SMB2_WRITE_HE:
+	case SMB2_LOCK_HE:
+	case SMB2_QUERY_DIRECTORY_HE:
+	case SMB2_CHANGE_NOTIFY_HE:
+	case SMB2_QUERY_INFO_HE:
+	case SMB2_SET_INFO_HE:
+	case SMB2_IOCTL_HE:
 		rc = -EAGAIN;
+		break;
+	default:
+		break;
 	}
 	return rc;
 }
 
 static void
-fill_small_buf(__le16 smb2_command, struct cifs_tcon *tcon,
+fill_small_buf(enum smb2_command smb2_command, struct cifs_tcon *tcon,
 	       struct TCP_Server_Info *server,
 	       void *buf,
 	       unsigned int *total_len)
 {
 	struct smb2_pdu *spdu = buf;
 	/* lookup word count ie StructureSize from table */
-	__u16 parmsize = smb2_req_struct_sizes[le16_to_cpu(smb2_command)];
+	__u16 parmsize = smb2_req_struct_sizes[smb2_command];
 
 	/*
 	 * smaller than SMALL_BUFFER_SIZE but bigger than fixed area of
@@ -517,14 +522,14 @@ fill_small_buf(__le16 smb2_command, struct cifs_tcon *tcon,
  * SMB information in the SMB header. If the return code is zero, this
  * function must have filled in request_buf pointer.
  */
-static int __smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
+static int __smb2_plain_req_init(enum smb2_command smb2_command, struct cifs_tcon *tcon,
 				 struct TCP_Server_Info *server,
 				 void **request_buf, unsigned int *total_len)
 {
 	/* BB eventually switch this to SMB2 specific small buf size */
 	switch (smb2_command) {
-	case SMB2_SET_INFO:
-	case SMB2_QUERY_INFO:
+	case SMB2_SET_INFO_HE:
+	case SMB2_QUERY_INFO_HE:
 		*request_buf = cifs_buf_get();
 		break;
 	default:
@@ -576,10 +581,10 @@ static int smb2_ioctl_req_init(u32 opcode, struct cifs_tcon *tcon,
 	if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO ||
 	    (opcode == FSCTL_QUERY_NETWORK_INTERFACE_INFO &&
 	     (tcon->ses->flags & CIFS_SES_FLAGS_PENDING_QUERY_INTERFACES)))
-		return __smb2_plain_req_init(SMB2_IOCTL, tcon, server,
+		return __smb2_plain_req_init(SMB2_IOCTL_HE, tcon, server,
 					     request_buf, total_len);
 
-	return smb2_plain_req_init(SMB2_IOCTL, tcon, server,
+	return smb2_plain_req_init(SMB2_IOCTL_HE, tcon, server,
 				   request_buf, total_len);
 }
 
@@ -1064,7 +1069,7 @@ SMB2_negotiate(const unsigned int xid,
 		return -EIO;
 	}
 
-	rc = smb2_plain_req_init(SMB2_NEGOTIATE, NULL, server,
+	rc = smb2_plain_req_init(SMB2_NEGOTIATE_HE, NULL, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -1464,7 +1469,7 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
 	unsigned int total_len;
 	bool is_binding = false;
 
-	rc = smb2_plain_req_init(SMB2_SESSION_SETUP, NULL, server,
+	rc = smb2_plain_req_init(SMB2_SESSION_SETUP_HE, NULL, server,
 				 (void **) &req,
 				 &total_len);
 	if (rc)
@@ -1979,7 +1984,7 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
 	}
 	spin_unlock(&ses->chan_lock);
 
-	rc = smb2_plain_req_init(SMB2_LOGOFF, NULL, ses->server,
+	rc = smb2_plain_req_init(SMB2_LOGOFF_HE, NULL, ses->server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -2064,7 +2069,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
 	/* SMB2 TREE_CONNECT request must be called with TreeId == 0 */
 	tcon->tid = 0;
 	atomic_set(&tcon->num_remote_opens, 0);
-	rc = smb2_plain_req_init(SMB2_TREE_CONNECT, tcon, server,
+	rc = smb2_plain_req_init(SMB2_TREE_CONNECT_HE, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc) {
 		kfree(unc_path);
@@ -2199,7 +2204,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
 
 	invalidate_all_cached_dirs(tcon);
 
-	rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT, tcon, server,
+	rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT_HE, tcon, server,
 				 (void **) &req,
 				 &total_len);
 	if (rc)
@@ -2862,7 +2867,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
 	}
 
 	/* resource #2: request */
-	rc = smb2_plain_req_init(SMB2_CREATE, tcon, server,
+	rc = smb2_plain_req_init(SMB2_CREATE_HE, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		goto err_free_path;
@@ -3016,7 +3021,7 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
 	__le16 *copy_path;
 	int rc;
 
-	rc = smb2_plain_req_init(SMB2_CREATE, tcon, server,
+	rc = smb2_plain_req_init(SMB2_CREATE_HE, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -3571,7 +3576,7 @@ SMB2_close_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
 	unsigned int total_len;
 	int rc;
 
-	rc = smb2_plain_req_init(SMB2_CLOSE, tcon, server,
+	rc = smb2_plain_req_init(SMB2_CLOSE_HE, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -3765,7 +3770,7 @@ SMB2_query_info_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
 		     len > CIFSMaxBufSize))
 		return -EINVAL;
 
-	rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, server,
+	rc = smb2_plain_req_init(SMB2_QUERY_INFO_HE, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -3966,7 +3971,7 @@ SMB2_notify_init(const unsigned int xid, struct smb_rqst *rqst,
 	unsigned int total_len;
 	int rc;
 
-	rc = smb2_plain_req_init(SMB2_CHANGE_NOTIFY, tcon, server,
+	rc = smb2_plain_req_init(SMB2_CHANGE_NOTIFY_HE, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -4203,7 +4208,7 @@ void smb2_reconnect_server(struct work_struct *work)
 	spin_unlock(&cifs_tcp_ses_lock);
 
 	list_for_each_entry_safe(tcon, tcon2, &tmp_list, rlist) {
-		rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server, true);
+		rc = smb2_reconnect(SMB2_INTERNAL_CMD_HE, tcon, server, true);
 		if (!rc) {
 			cifs_renegotiate_iosize(server, tcon);
 			cifs_reopen_persistent_handles(tcon);
@@ -4235,7 +4240,7 @@ void smb2_reconnect_server(struct work_struct *work)
 	/* now reconnect sessions for necessary channels */
 	list_for_each_entry_safe(ses, ses2, &tmp_ses_list, rlist) {
 		tcon->ses = ses;
-		rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server, true);
+		rc = smb2_reconnect(SMB2_INTERNAL_CMD_HE, tcon, server, true);
 		if (rc)
 			resched = true;
 		list_del_init(&ses->rlist);
@@ -4275,7 +4280,7 @@ SMB2_echo(struct TCP_Server_Info *server)
 	}
 	spin_unlock(&server->srv_lock);
 
-	rc = smb2_plain_req_init(SMB2_ECHO, NULL, server,
+	rc = smb2_plain_req_init(SMB2_ECHO_HE, NULL, server,
 				 (void **)&req, &total_len);
 	if (rc)
 		return rc;
@@ -4311,7 +4316,7 @@ SMB2_flush_init(const unsigned int xid, struct smb_rqst *rqst,
 	unsigned int total_len;
 	int rc;
 
-	rc = smb2_plain_req_init(SMB2_FLUSH, tcon, server,
+	rc = smb2_plain_req_init(SMB2_FLUSH_HE, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -4432,7 +4437,7 @@ smb2_new_read_req(void **buf, unsigned int *total_len,
 	struct smb2_hdr *shdr;
 	struct TCP_Server_Info *server = io_parms->server;
 
-	rc = smb2_plain_req_init(SMB2_READ, io_parms->tcon, server,
+	rc = smb2_plain_req_init(SMB2_READ_HE, io_parms->tcon, server,
 				 (void **) &req, total_len);
 	if (rc)
 		return rc;
@@ -4964,7 +4969,7 @@ smb2_async_writev(struct cifs_io_subrequest *wdata)
 	};
 	io_parms = &_io_parms;
 
-	rc = smb2_plain_req_init(SMB2_WRITE, tcon, server,
+	rc = smb2_plain_req_init(SMB2_WRITE_HE, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		goto out;
@@ -5136,7 +5141,7 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
 	if (n_vec < 1)
 		return rc;
 
-	rc = smb2_plain_req_init(SMB2_WRITE, io_parms->tcon, server,
+	rc = smb2_plain_req_init(SMB2_WRITE_HE, io_parms->tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -5369,7 +5374,7 @@ int SMB2_query_directory_init(const unsigned int xid,
 	struct kvec *iov = rqst->rq_iov;
 	int len, rc;
 
-	rc = smb2_plain_req_init(SMB2_QUERY_DIRECTORY, tcon, server,
+	rc = smb2_plain_req_init(SMB2_QUERY_DIRECTORY_HE, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -5603,7 +5608,7 @@ SMB2_set_info_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
 	unsigned int i, total_len;
 	int rc;
 
-	rc = smb2_plain_req_init(SMB2_SET_INFO, tcon, server,
+	rc = smb2_plain_req_init(SMB2_SET_INFO_HE, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -5777,7 +5782,7 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
 	server = cifs_pick_channel(ses);
 
 	cifs_dbg(FYI, "SMB2_oplock_break\n");
-	rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK, tcon, server,
+	rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK_HE, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -5863,7 +5868,7 @@ build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon,
 	if ((tcon->ses == NULL) || server == NULL)
 		return -EIO;
 
-	rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, server,
+	rc = smb2_plain_req_init(SMB2_QUERY_INFO_HE, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -6076,7 +6081,7 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
 
 	cifs_dbg(FYI, "smb2_lockv num lock %d\n", num_lock);
 
-	rc = smb2_plain_req_init(SMB2_LOCK, tcon, server,
+	rc = smb2_plain_req_init(SMB2_LOCK_HE, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -6159,7 +6164,7 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
 	struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
 
 	cifs_dbg(FYI, "SMB2_lease_break\n");
-	rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK, tcon, server,
+	rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK_HE, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index 5348bfd5fad0..806ced5d0783 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -671,7 +671,7 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 	shdr = (struct smb2_hdr *)rqst->rq_iov[0].iov_base;
 	ssr = (struct smb2_sess_setup_req *)shdr;
 
-	is_binding = shdr->Command == SMB2_SESSION_SETUP &&
+	is_binding = le16_to_cpu(shdr->Command) == SMB2_SESSION_SETUP_HE &&
 		(ssr->Flags & SMB2_SESSION_REQ_FLAG_BINDING);
 	is_signed = shdr->Flags & SMB2_FLAGS_SIGNED;
 
@@ -702,9 +702,9 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 	struct smb2_hdr *shdr =
 			(struct smb2_hdr *)rqst->rq_iov[0].iov_base;
 
-	if ((shdr->Command == SMB2_NEGOTIATE) ||
-	    (shdr->Command == SMB2_SESSION_SETUP) ||
-	    (shdr->Command == SMB2_OPLOCK_BREAK) ||
+	if (le16_to_cpu(shdr->Command) == SMB2_NEGOTIATE_HE ||
+	    le16_to_cpu(shdr->Command) == SMB2_SESSION_SETUP_HE ||
+	    le16_to_cpu(shdr->Command) == SMB2_OPLOCK_BREAK_HE ||
 	    server->ignore_signature ||
 	    (!server->session_estab))
 		return 0;
@@ -774,7 +774,7 @@ smb2_mid_entry_alloc(const struct smb2_hdr *shdr,
 	smb->mid = le64_to_cpu(shdr->MessageId);
 	smb->credits = credits > 0 ? credits : 1;
 	smb->pid = current->pid;
-	smb->command = shdr->Command; /* Always LE */
+	smb->command_id = le16_to_cpu(shdr->Command);
 	smb->when_alloc = jiffies;
 	smb->server = server;
 
@@ -812,7 +812,7 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server,
 	}
 
 	if (server->tcpStatus == CifsNeedNegotiate &&
-	   shdr->Command != SMB2_NEGOTIATE) {
+	    le16_to_cpu(shdr->Command) != SMB2_NEGOTIATE_HE) {
 		spin_unlock(&server->srv_lock);
 		return -EAGAIN;
 	}
@@ -820,8 +820,8 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server,
 
 	spin_lock(&ses->ses_lock);
 	if (ses->ses_status == SES_NEW) {
-		if ((shdr->Command != SMB2_SESSION_SETUP) &&
-		    (shdr->Command != SMB2_NEGOTIATE)) {
+		if (le16_to_cpu(shdr->Command) != SMB2_SESSION_SETUP_HE &&
+		    le16_to_cpu(shdr->Command) != SMB2_NEGOTIATE_HE) {
 			spin_unlock(&ses->ses_lock);
 			return -EAGAIN;
 		}
@@ -829,7 +829,7 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server,
 	}
 
 	if (ses->ses_status == SES_EXITING) {
-		if (shdr->Command != SMB2_LOGOFF) {
+		if (le16_to_cpu(shdr->Command) != SMB2_LOGOFF_HE) {
 			spin_unlock(&ses->ses_lock);
 			return -EAGAIN;
 		}
@@ -910,7 +910,7 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 
 	spin_lock(&server->srv_lock);
 	if (server->tcpStatus == CifsNeedNegotiate &&
-	   shdr->Command != SMB2_NEGOTIATE) {
+	    le16_to_cpu(shdr->Command) != SMB2_NEGOTIATE_HE) {
 		spin_unlock(&server->srv_lock);
 		return ERR_PTR(-EAGAIN);
 	}
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index a105e0ddf81a..d55b24d1aa77 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -43,8 +43,8 @@ void __release_mid(struct kref *refcount)
 	struct smb_message *smb =
 			container_of(refcount, struct smb_message, refcount);
 #ifdef CONFIG_CIFS_STATS2
-	__le16 command = smb->server->vals->lock_cmd;
-	__u16 smb_cmd = le16_to_cpu(smb->command);
+	enum smb2_command command = smb->server->vals->lock_cmd;
+	enum smb2_command smb_cmd = smb->command_id;
 	unsigned long now;
 	unsigned long roundtrip_time;
 #endif
@@ -93,7 +93,7 @@ void __release_mid(struct kref *refcount)
 	 */
 	if ((slow_rsp_threshold != 0) &&
 	    time_after(now, smb->when_alloc + (slow_rsp_threshold * HZ)) &&
-	    (smb->command != command)) {
+	    (smb->command_id != command)) {
 		/*
 		 * smb2slowcmd[NUMBER_OF_SMB2_COMMANDS] counts by command
 		 * NB: le16_to_cpu returns unsigned so can not be negative below
@@ -105,7 +105,7 @@ void __release_mid(struct kref *refcount)
 				    smb->when_sent, smb->when_received);
 		if (cifsFYI & CIFS_TIMER) {
 			pr_debug("slow rsp: cmd %d mid %llu",
-				 smb->command, smb->mid);
+				 smb->command_id, smb->mid);
 			cifs_info("A: 0x%lx S: 0x%lx R: 0x%lx\n",
 				  now - smb->when_alloc,
 				  now - smb->when_sent,
@@ -733,7 +733,7 @@ int cifs_sync_mid_result(struct smb_message *smb, struct TCP_Server_Info *server
 	int rc = 0;
 
 	cifs_dbg(FYI, "%s: cmd=%d mid=%llu state=%d\n",
-		 __func__, le16_to_cpu(smb->command), smb->mid, smb->mid_state);
+		 __func__, smb->command_id, smb->mid, smb->mid_state);
 
 	spin_lock(&server->mid_lock);
 	switch (smb->mid_state) {
@@ -1004,7 +1004,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 	if (rc != 0) {
 		for (; i < num_rqst; i++) {
 			cifs_server_dbg(FYI, "Cancelling wait for mid %llu cmd: %d\n",
-				 smb[i]->mid, le16_to_cpu(smb[i]->command));
+				 smb[i]->mid, smb[i]->command_id);
 			send_cancel(server, &rqst[i], smb[i]);
 			spin_lock(&server->mid_lock);
 			smb[i]->mid_flags |= MID_WAIT_CANCELLED;
diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h
index f79a5165a7cc..2f4b158518cd 100644
--- a/fs/smb/common/smb2pdu.h
+++ b/fs/smb/common/smb2pdu.h
@@ -15,49 +15,30 @@
  */
 
 /* List of commands in host endian */
-#define SMB2_NEGOTIATE_HE	0x0000
-#define SMB2_SESSION_SETUP_HE	0x0001
-#define SMB2_LOGOFF_HE		0x0002 /* trivial request/resp */
-#define SMB2_TREE_CONNECT_HE	0x0003
-#define SMB2_TREE_DISCONNECT_HE	0x0004 /* trivial req/resp */
-#define SMB2_CREATE_HE		0x0005
-#define SMB2_CLOSE_HE		0x0006
-#define SMB2_FLUSH_HE		0x0007 /* trivial resp */
-#define SMB2_READ_HE		0x0008
-#define SMB2_WRITE_HE		0x0009
-#define SMB2_LOCK_HE		0x000A
-#define SMB2_IOCTL_HE		0x000B
-#define SMB2_CANCEL_HE		0x000C
-#define SMB2_ECHO_HE		0x000D
-#define SMB2_QUERY_DIRECTORY_HE	0x000E
-#define SMB2_CHANGE_NOTIFY_HE	0x000F
-#define SMB2_QUERY_INFO_HE	0x0010
-#define SMB2_SET_INFO_HE	0x0011
-#define SMB2_OPLOCK_BREAK_HE	0x0012
-#define SMB2_SERVER_TO_CLIENT_NOTIFICATION 0x0013
-
-/* The same list in little endian */
-#define SMB2_NEGOTIATE		cpu_to_le16(SMB2_NEGOTIATE_HE)
-#define SMB2_SESSION_SETUP	cpu_to_le16(SMB2_SESSION_SETUP_HE)
-#define SMB2_LOGOFF		cpu_to_le16(SMB2_LOGOFF_HE)
-#define SMB2_TREE_CONNECT	cpu_to_le16(SMB2_TREE_CONNECT_HE)
-#define SMB2_TREE_DISCONNECT	cpu_to_le16(SMB2_TREE_DISCONNECT_HE)
-#define SMB2_CREATE		cpu_to_le16(SMB2_CREATE_HE)
-#define SMB2_CLOSE		cpu_to_le16(SMB2_CLOSE_HE)
-#define SMB2_FLUSH		cpu_to_le16(SMB2_FLUSH_HE)
-#define SMB2_READ		cpu_to_le16(SMB2_READ_HE)
-#define SMB2_WRITE		cpu_to_le16(SMB2_WRITE_HE)
-#define SMB2_LOCK		cpu_to_le16(SMB2_LOCK_HE)
-#define SMB2_IOCTL		cpu_to_le16(SMB2_IOCTL_HE)
-#define SMB2_CANCEL		cpu_to_le16(SMB2_CANCEL_HE)
-#define SMB2_ECHO		cpu_to_le16(SMB2_ECHO_HE)
-#define SMB2_QUERY_DIRECTORY	cpu_to_le16(SMB2_QUERY_DIRECTORY_HE)
-#define SMB2_CHANGE_NOTIFY	cpu_to_le16(SMB2_CHANGE_NOTIFY_HE)
-#define SMB2_QUERY_INFO		cpu_to_le16(SMB2_QUERY_INFO_HE)
-#define SMB2_SET_INFO		cpu_to_le16(SMB2_SET_INFO_HE)
-#define SMB2_OPLOCK_BREAK	cpu_to_le16(SMB2_OPLOCK_BREAK_HE)
-
-#define SMB2_INTERNAL_CMD	cpu_to_le16(0xFFFF)
+enum smb2_command {
+    SMB2_NEGOTIATE_HE			= 0x0000,
+    SMB2_SESSION_SETUP_HE		= 0x0001,
+    SMB2_LOGOFF_HE			= 0x0002, /* trivial request/resp */
+    SMB2_TREE_CONNECT_HE		= 0x0003,
+    SMB2_TREE_DISCONNECT_HE		= 0x0004, /* trivial req/resp */
+    SMB2_CREATE_HE			= 0x0005,
+    SMB2_CLOSE_HE			= 0x0006,
+    SMB2_FLUSH_HE			= 0x0007, /* trivial resp */
+    SMB2_READ_HE			= 0x0008,
+    SMB2_WRITE_HE			= 0x0009,
+    SMB2_LOCK_HE			= 0x000A,
+    SMB2_IOCTL_HE			= 0x000B,
+    SMB2_CANCEL_HE			= 0x000C,
+    SMB2_ECHO_HE			= 0x000D,
+    SMB2_QUERY_DIRECTORY_HE		= 0x000E,
+    SMB2_CHANGE_NOTIFY_HE		= 0x000F,
+    SMB2_QUERY_INFO_HE			= 0x0010,
+    SMB2_SET_INFO_HE			= 0x0011,
+    SMB2_OPLOCK_BREAK_HE		= 0x0012,
+    SMB2_SERVER_TO_CLIENT_NOTIFICATION	= 0x0013
+};
+
+#define SMB2_INTERNAL_CMD_HE		0xFFFF
 
 #define NUMBER_OF_SMB2_COMMANDS	0x0013
 
@@ -182,6 +163,7 @@ struct smb3_hdr_req {
 struct smb2_pdu {
 	struct smb2_hdr hdr;
 	__le16 StructureSize2; /* size of wct area (varies, request specific) */
+#define SMB2_STRUCT_HAS_DYNAMIC_PART	0x01
 } __packed;
 
 #define SMB2_ERROR_STRUCTURE_SIZE2	9
diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
index d7a8a580d013..dd3c046aeae3 100644
--- a/fs/smb/server/oplock.c
+++ b/fs/smb/server/oplock.c
@@ -642,7 +642,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
 	rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;
 	rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
 	rsp_hdr->CreditRequest = cpu_to_le16(0);
-	rsp_hdr->Command = SMB2_OPLOCK_BREAK;
+	rsp_hdr->Command = cpu_to_le16(SMB2_OPLOCK_BREAK_HE);
 	rsp_hdr->Flags = (SMB2_FLAGS_SERVER_TO_REDIR);
 	rsp_hdr->NextCommand = 0;
 	rsp_hdr->MessageId = cpu_to_le64(-1);
@@ -749,7 +749,7 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
 	rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;
 	rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
 	rsp_hdr->CreditRequest = cpu_to_le16(0);
-	rsp_hdr->Command = SMB2_OPLOCK_BREAK;
+	rsp_hdr->Command = cpu_to_le16(SMB2_OPLOCK_BREAK_HE);
 	rsp_hdr->Flags = (SMB2_FLAGS_SERVER_TO_REDIR);
 	rsp_hdr->NextCommand = 0;
 	rsp_hdr->MessageId = cpu_to_le64(-1);
diff --git a/fs/smb/server/smb2misc.c b/fs/smb/server/smb2misc.c
index ae501024665e..41323492f214 100644
--- a/fs/smb/server/smb2misc.c
+++ b/fs/smb/server/smb2misc.c
@@ -95,18 +95,18 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
 	 * of the data buffer offset and data buffer length for the particular
 	 * command.
 	 */
-	switch (hdr->Command) {
-	case SMB2_SESSION_SETUP:
+	switch (le16_to_cpu(hdr->Command)) {
+	case SMB2_SESSION_SETUP_HE:
 		*off = le16_to_cpu(((struct smb2_sess_setup_req *)hdr)->SecurityBufferOffset);
 		*len = le16_to_cpu(((struct smb2_sess_setup_req *)hdr)->SecurityBufferLength);
 		break;
-	case SMB2_TREE_CONNECT:
+	case SMB2_TREE_CONNECT_HE:
 		*off = max_t(unsigned short int,
 			     le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathOffset),
 			     offsetof(struct smb2_tree_connect_req, Buffer));
 		*len = le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathLength);
 		break;
-	case SMB2_CREATE:
+	case SMB2_CREATE_HE:
 	{
 		unsigned short int name_off =
 			max_t(unsigned short int,
@@ -131,23 +131,23 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
 		*len = name_len;
 		break;
 	}
-	case SMB2_QUERY_INFO:
+	case SMB2_QUERY_INFO_HE:
 		*off = max_t(unsigned int,
 			     le16_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferOffset),
 			     offsetof(struct smb2_query_info_req, Buffer));
 		*len = le32_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferLength);
 		break;
-	case SMB2_SET_INFO:
+	case SMB2_SET_INFO_HE:
 		*off = max_t(unsigned int,
 			     le16_to_cpu(((struct smb2_set_info_req *)hdr)->BufferOffset),
 			     offsetof(struct smb2_set_info_req, Buffer));
 		*len = le32_to_cpu(((struct smb2_set_info_req *)hdr)->BufferLength);
 		break;
-	case SMB2_READ:
+	case SMB2_READ_HE:
 		*off = le16_to_cpu(((struct smb2_read_req *)hdr)->ReadChannelInfoOffset);
 		*len = le16_to_cpu(((struct smb2_read_req *)hdr)->ReadChannelInfoLength);
 		break;
-	case SMB2_WRITE:
+	case SMB2_WRITE_HE:
 		if (((struct smb2_write_req *)hdr)->DataOffset ||
 		    ((struct smb2_write_req *)hdr)->Length) {
 			*off = max_t(unsigned short int,
@@ -160,13 +160,13 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
 		*off = le16_to_cpu(((struct smb2_write_req *)hdr)->WriteChannelInfoOffset);
 		*len = le16_to_cpu(((struct smb2_write_req *)hdr)->WriteChannelInfoLength);
 		break;
-	case SMB2_QUERY_DIRECTORY:
+	case SMB2_QUERY_DIRECTORY_HE:
 		*off = max_t(unsigned short int,
 			     le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameOffset),
 			     offsetof(struct smb2_query_directory_req, Buffer));
 		*len = le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameLength);
 		break;
-	case SMB2_LOCK:
+	case SMB2_LOCK_HE:
 	{
 		unsigned short lock_count;
 
@@ -177,7 +177,7 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
 		}
 		break;
 	}
-	case SMB2_IOCTL:
+	case SMB2_IOCTL_HE:
 		*off = max_t(unsigned int,
 			     le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputOffset),
 			     offsetof(struct smb2_ioctl_req, Buffer));
@@ -226,7 +226,7 @@ static int smb2_calc_size(void *buf, unsigned int *len)
 	 * regardless of number of locks. Subtract single
 	 * smb2_lock_element for correct buffer size check.
 	 */
-	if (hdr->Command == SMB2_LOCK)
+	if (le16_to_cpu(hdr->Command) == SMB2_LOCK_HE)
 		*len -= sizeof(struct smb2_lock_element);
 
 	if (has_smb2_data_area[le16_to_cpu(hdr->Command)] == false)
@@ -306,27 +306,27 @@ static int smb2_validate_credit_charge(struct ksmbd_conn *conn,
 	void *__hdr = hdr;
 	int ret = 0;
 
-	switch (hdr->Command) {
-	case SMB2_QUERY_INFO:
+	switch (le16_to_cpu(hdr->Command)) {
+	case SMB2_QUERY_INFO_HE:
 		req_len = smb2_query_info_req_len(__hdr);
 		break;
-	case SMB2_SET_INFO:
+	case SMB2_SET_INFO_HE:
 		req_len = smb2_set_info_req_len(__hdr);
 		break;
-	case SMB2_READ:
+	case SMB2_READ_HE:
 		req_len = smb2_read_req_len(__hdr);
 		break;
-	case SMB2_WRITE:
+	case SMB2_WRITE_HE:
 		req_len = smb2_write_req_len(__hdr);
 		break;
-	case SMB2_QUERY_DIRECTORY:
+	case SMB2_QUERY_DIRECTORY_HE:
 		req_len = smb2_query_dir_req_len(__hdr);
 		break;
-	case SMB2_IOCTL:
+	case SMB2_IOCTL_HE:
 		req_len = smb2_ioctl_req_len(__hdr);
 		expect_resp_len = smb2_ioctl_resp_len(__hdr);
 		break;
-	case SMB2_CANCEL:
+	case SMB2_CANCEL_HE:
 		return 0;
 	default:
 		req_len = 1;
diff --git a/fs/smb/server/smb2ops.c b/fs/smb/server/smb2ops.c
index 606aa3c5189a..c9302dd71e53 100644
--- a/fs/smb/server/smb2ops.c
+++ b/fs/smb/server/smb2ops.c
@@ -27,7 +27,7 @@ static struct smb_version_values smb21_server_values = {
 	.header_size = sizeof(struct smb2_hdr),
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK,
+	.lock_cmd = SMB2_LOCK_HE,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
@@ -53,7 +53,7 @@ static struct smb_version_values smb30_server_values = {
 	.header_size = sizeof(struct smb2_hdr),
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK,
+	.lock_cmd = SMB2_LOCK_HE,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
@@ -80,7 +80,7 @@ static struct smb_version_values smb302_server_values = {
 	.header_size = sizeof(struct smb2_hdr),
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK,
+	.lock_cmd = SMB2_LOCK_HE,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
@@ -107,7 +107,7 @@ static struct smb_version_values smb311_server_values = {
 	.header_size = sizeof(struct smb2_hdr),
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK,
+	.lock_cmd = SMB2_LOCK_HE,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index fafa86273f12..74749c60d9f6 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -181,7 +181,7 @@ bool is_smb2_neg_cmd(struct ksmbd_work *work)
 	if (hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR)
 		return false;
 
-	if (hdr->Command != SMB2_NEGOTIATE)
+	if (le16_to_cpu(hdr->Command) != SMB2_NEGOTIATE_HE)
 		return false;
 
 	return true;
@@ -262,7 +262,7 @@ int init_smb2_neg_rsp(struct ksmbd_work *work)
 	rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;
 	rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
 	rsp_hdr->CreditRequest = cpu_to_le16(2);
-	rsp_hdr->Command = SMB2_NEGOTIATE;
+	rsp_hdr->Command = cpu_to_le16(SMB2_NEGOTIATE_HE);
 	rsp_hdr->Flags = (SMB2_FLAGS_SERVER_TO_REDIR);
 	rsp_hdr->NextCommand = 0;
 	rsp_hdr->MessageId = 0;
@@ -349,7 +349,7 @@ int smb2_set_rsp_credits(struct ksmbd_work *work)
 	 * TODO: Need to adjuct CreditRequest value according to
 	 * current cpu load
 	 */
-	if (hdr->Command == SMB2_NEGOTIATE)
+	if (le16_to_cpu(hdr->Command) == SMB2_NEGOTIATE_HE)
 		aux_max = 1;
 	else
 		aux_max = conn->vals->max_credits - conn->total_credits;
@@ -389,7 +389,7 @@ static void init_chained_smb2_rsp(struct ksmbd_work *work)
 	/* Storing the current local FID which may be needed by subsequent
 	 * command in the compound request
 	 */
-	if (req->Command == SMB2_CREATE && rsp->Status == STATUS_SUCCESS) {
+	if (req->Command == cpu_to_le16(SMB2_CREATE_HE) && rsp->Status == STATUS_SUCCESS) {
 		work->compound_fid = ((struct smb2_create_rsp *)rsp)->VolatileFileId;
 		work->compound_pfid = ((struct smb2_create_rsp *)rsp)->PersistentFileId;
 		work->compound_sid = le64_to_cpu(rsp->SessionId);
@@ -572,7 +572,7 @@ int smb2_check_user_session(struct ksmbd_work *work)
 {
 	struct smb2_hdr *req_hdr = ksmbd_req_buf_next(work);
 	struct ksmbd_conn *conn = work->conn;
-	unsigned int cmd = le16_to_cpu(req_hdr->Command);
+	enum smb2_command cmd = le16_to_cpu(req_hdr->Command);
 	unsigned long long sess_id;
 
 	/*
@@ -8887,7 +8887,7 @@ void smb2_set_sign_rsp(struct ksmbd_work *work)
 	hdr->Flags |= SMB2_FLAGS_SIGNED;
 	memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE);
 
-	if (hdr->Command == SMB2_READ) {
+	if (hdr->Command == cpu_to_le16(SMB2_READ_HE)) {
 		iov = &work->iov[work->iov_idx - 1];
 		n_vec++;
 	} else {
@@ -8993,7 +8993,7 @@ void smb3_set_sign_rsp(struct ksmbd_work *work)
 	hdr->Flags |= SMB2_FLAGS_SIGNED;
 	memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE);
 
-	if (hdr->Command == SMB2_READ) {
+	if (hdr->Command == cpu_to_le16(SMB2_READ_HE)) {
 		iov = &work->iov[work->iov_idx - 1];
 		n_vec++;
 	} else {


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 09/31] cifs: Rename SMB2_xxxx_HE to SMB2_xxxx
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (7 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 08/31] cifs: Keep the CPU-endian command ID around David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 10/31] cifs: Make smb1's SendReceive() wrap cifs_send_recv() David Howells
                   ` (25 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Rename SMB2_xxxx_HE to SMB2_xxxx as the LE variants have been got rid of.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/compress.c      |   4 +-
 fs/smb/client/smb2misc.c      |  43 ++++++-----
 fs/smb/client/smb2ops.c       |  72 +++++++++---------
 fs/smb/client/smb2pdu.c       | 134 +++++++++++++++++-----------------
 fs/smb/client/smb2transport.c |  18 ++---
 fs/smb/common/smb2pdu.h       |  40 +++++-----
 fs/smb/server/connection.c    |   2 +-
 fs/smb/server/oplock.c        |   4 +-
 fs/smb/server/smb2misc.c      |  44 +++++------
 fs/smb/server/smb2ops.c       |  46 ++++++------
 fs/smb/server/smb2pdu.c       |  42 +++++------
 fs/smb/server/smb_common.c    |   2 +-
 12 files changed, 225 insertions(+), 226 deletions(-)

diff --git a/fs/smb/client/compress.c b/fs/smb/client/compress.c
index f52710425151..3caf4b89d8a5 100644
--- a/fs/smb/client/compress.c
+++ b/fs/smb/client/compress.c
@@ -303,7 +303,7 @@ bool should_compress(const struct cifs_tcon *tcon, const struct smb_rqst *rq)
 	if (!(tcon->share_flags & SMB2_SHAREFLAG_COMPRESS_DATA))
 		return false;
 
-	if (le16_to_cpu(shdr->Command) == SMB2_WRITE_HE) {
+	if (le16_to_cpu(shdr->Command) == SMB2_WRITE) {
 		const struct smb2_write_req *wreq = rq->rq_iov->iov_base;
 
 		if (le32_to_cpu(wreq->Length) < SMB_COMPRESS_MIN_LEN)
@@ -312,7 +312,7 @@ bool should_compress(const struct cifs_tcon *tcon, const struct smb_rqst *rq)
 		return is_compressible(&rq->rq_iter);
 	}
 
-	return le16_to_cpu(shdr->Command) == SMB2_READ_HE;
+	return le16_to_cpu(shdr->Command) == SMB2_READ;
 }
 
 int smb_compress(struct TCP_Server_Info *server, struct smb_rqst *rq, compress_send_fn send_fn)
diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c
index f6280e3d4e55..b8e3fe26d658 100644
--- a/fs/smb/client/smb2misc.c
+++ b/fs/smb/client/smb2misc.c
@@ -33,7 +33,7 @@ check_smb2_hdr(struct smb2_hdr *shdr, __u64 mid)
 			return 0;
 		else {
 			/* only one valid case where server sends us request */
-			if (le16_to_cpu(shdr->Command) == SMB2_OPLOCK_BREAK_HE)
+			if (le16_to_cpu(shdr->Command) == SMB2_OPLOCK_BREAK)
 				return 0;
 			else
 				cifs_dbg(VFS, "Received Request not response\n");
@@ -209,13 +209,13 @@ smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *server)
 	}
 
 	if (smb2_rsp_struct_sizes[command] != pdu->StructureSize2) {
-		if (command != SMB2_OPLOCK_BREAK_HE && (shdr->Status == 0 ||
+		if (command != SMB2_OPLOCK_BREAK && (shdr->Status == 0 ||
 		    pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2_LE)) {
 			/* error packets have 9 byte structure size */
 			cifs_dbg(VFS, "Invalid response size %u for command %d\n",
 				 le16_to_cpu(pdu->StructureSize2), command);
 			return 1;
-		} else if (command == SMB2_OPLOCK_BREAK_HE
+		} else if (command == SMB2_OPLOCK_BREAK
 			   && (shdr->Status == 0)
 			   && (le16_to_cpu(pdu->StructureSize2) != 44)
 			   && (le16_to_cpu(pdu->StructureSize2) != 36)) {
@@ -230,19 +230,19 @@ smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *server)
 
 	/* For SMB2_IOCTL, OutputOffset and OutputLength are optional, so might
 	 * be 0, and not a real miscalculation */
-	if (command == SMB2_IOCTL_HE && calc_len == 0)
+	if (command == SMB2_IOCTL && calc_len == 0)
 		return 0;
 
-	if (command == SMB2_NEGOTIATE_HE)
+	if (command == SMB2_NEGOTIATE)
 		calc_len += get_neg_ctxt_len(shdr, len, calc_len);
 
 	if (len != calc_len) {
 		/* create failed on symlink */
-		if (command == SMB2_CREATE_HE &&
+		if (command == SMB2_CREATE &&
 		    shdr->Status == STATUS_STOPPED_ON_SYMLINK)
 			return 0;
 		/* Windows 7 server returns 24 bytes more */
-		if (calc_len + 24 == len && command == SMB2_OPLOCK_BREAK_HE)
+		if (calc_len + 24 == len && command == SMB2_OPLOCK_BREAK)
 			return 0;
 		/* server can return one byte more due to implied bcc[0] */
 		if (calc_len == len + 1)
@@ -331,48 +331,48 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *shdr)
 	 * command.
 	 */
 	switch (le16_to_cpu(shdr->Command)) {
-	case SMB2_NEGOTIATE_HE:
+	case SMB2_NEGOTIATE:
 		*off = le16_to_cpu(
 		  ((struct smb2_negotiate_rsp *)shdr)->SecurityBufferOffset);
 		*len = le16_to_cpu(
 		  ((struct smb2_negotiate_rsp *)shdr)->SecurityBufferLength);
 		break;
-	case SMB2_SESSION_SETUP_HE:
+	case SMB2_SESSION_SETUP:
 		*off = le16_to_cpu(
 		  ((struct smb2_sess_setup_rsp *)shdr)->SecurityBufferOffset);
 		*len = le16_to_cpu(
 		  ((struct smb2_sess_setup_rsp *)shdr)->SecurityBufferLength);
 		break;
-	case SMB2_CREATE_HE:
+	case SMB2_CREATE:
 		*off = le32_to_cpu(
 		    ((struct smb2_create_rsp *)shdr)->CreateContextsOffset);
 		*len = le32_to_cpu(
 		    ((struct smb2_create_rsp *)shdr)->CreateContextsLength);
 		break;
-	case SMB2_QUERY_INFO_HE:
+	case SMB2_QUERY_INFO:
 		*off = le16_to_cpu(
 		    ((struct smb2_query_info_rsp *)shdr)->OutputBufferOffset);
 		*len = le32_to_cpu(
 		    ((struct smb2_query_info_rsp *)shdr)->OutputBufferLength);
 		break;
-	case SMB2_READ_HE:
+	case SMB2_READ:
 		/* TODO: is this a bug ? */
 		*off = ((struct smb2_read_rsp *)shdr)->DataOffset;
 		*len = le32_to_cpu(((struct smb2_read_rsp *)shdr)->DataLength);
 		break;
-	case SMB2_QUERY_DIRECTORY_HE:
+	case SMB2_QUERY_DIRECTORY:
 		*off = le16_to_cpu(
 		  ((struct smb2_query_directory_rsp *)shdr)->OutputBufferOffset);
 		*len = le32_to_cpu(
 		  ((struct smb2_query_directory_rsp *)shdr)->OutputBufferLength);
 		break;
-	case SMB2_IOCTL_HE:
+	case SMB2_IOCTL:
 		*off = le32_to_cpu(
 		  ((struct smb2_ioctl_rsp *)shdr)->OutputOffset);
 		*len = le32_to_cpu(
 		  ((struct smb2_ioctl_rsp *)shdr)->OutputCount);
 		break;
-	case SMB2_CHANGE_NOTIFY_HE:
+	case SMB2_CHANGE_NOTIFY:
 		*off = le16_to_cpu(
 		  ((struct smb2_change_notify_rsp *)shdr)->OutputBufferOffset);
 		*len = le32_to_cpu(
@@ -680,11 +680,10 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
 
 	cifs_dbg(FYI, "Checking for oplock break\n");
 
-	if (rsp->hdr.Command != cpu_to_le32(SMB2_OPLOCK_BREAK_HE))
+	if (rsp->hdr.Command != cpu_to_le32(SMB2_OPLOCK_BREAK))
 		return false;
 
-	if (rsp->StructureSize !=
-				smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) {
+	if (rsp->StructureSize != smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK]) {
 		if (le16_to_cpu(rsp->StructureSize) == 44)
 			return smb2_is_valid_lease_break(buffer, server);
 		else
@@ -830,7 +829,7 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid,
 			    netfs_trace_tcon_ref_get_cancelled_close);
 	spin_unlock(&cifs_tcp_ses_lock);
 
-	rc = __smb2_handle_cancelled_cmd(tcon, SMB2_CLOSE_HE, 0,
+	rc = __smb2_handle_cancelled_cmd(tcon, SMB2_CLOSE, 0,
 					 persistent_fid, volatile_fid);
 	if (rc)
 		cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_cancelled_close);
@@ -846,7 +845,7 @@ smb2_handle_cancelled_mid(struct smb_message *smb, struct TCP_Server_Info *serve
 	struct cifs_tcon *tcon;
 	int rc;
 
-	if ((smb->optype & CIFS_CP_CREATE_CLOSE_OP) || smb->command_id != SMB2_CREATE_HE ||
+	if ((smb->optype & CIFS_CP_CREATE_CLOSE_OP) || smb->command_id != SMB2_CREATE ||
 	    hdr->Status != STATUS_SUCCESS)
 		return 0;
 
@@ -887,7 +886,7 @@ smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *server,
 
 	hdr = (struct smb2_hdr *)iov[0].iov_base;
 	/* neg prot are always taken */
-	if (le16_to_cpu(hdr->Command) == SMB2_NEGOTIATE_HE)
+	if (le16_to_cpu(hdr->Command) == SMB2_NEGOTIATE)
 		goto ok;
 
 	/*
@@ -898,7 +897,7 @@ smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *server,
 	if (server->dialect != SMB311_PROT_ID)
 		return 0;
 
-	if (le16_to_cpu(hdr->Command) != SMB2_SESSION_SETUP_HE)
+	if (le16_to_cpu(hdr->Command) != SMB2_SESSION_SETUP)
 		return 0;
 
 	/* skip last sess setup response */
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 0116bf348a76..36c506577b0e 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -1405,47 +1405,47 @@ smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
 		   atomic_read(&tcon->num_local_opens),
 		   atomic_read(&tcon->num_remote_opens));
 	seq_printf(m, "\nTreeConnects: %d total %d failed",
-		   atomic_read(&sent[SMB2_TREE_CONNECT_HE]),
-		   atomic_read(&failed[SMB2_TREE_CONNECT_HE]));
+		   atomic_read(&sent[SMB2_TREE_CONNECT]),
+		   atomic_read(&failed[SMB2_TREE_CONNECT]));
 	seq_printf(m, "\nTreeDisconnects: %d total %d failed",
-		   atomic_read(&sent[SMB2_TREE_DISCONNECT_HE]),
-		   atomic_read(&failed[SMB2_TREE_DISCONNECT_HE]));
+		   atomic_read(&sent[SMB2_TREE_DISCONNECT]),
+		   atomic_read(&failed[SMB2_TREE_DISCONNECT]));
 	seq_printf(m, "\nCreates: %d total %d failed",
-		   atomic_read(&sent[SMB2_CREATE_HE]),
-		   atomic_read(&failed[SMB2_CREATE_HE]));
+		   atomic_read(&sent[SMB2_CREATE]),
+		   atomic_read(&failed[SMB2_CREATE]));
 	seq_printf(m, "\nCloses: %d total %d failed",
-		   atomic_read(&sent[SMB2_CLOSE_HE]),
-		   atomic_read(&failed[SMB2_CLOSE_HE]));
+		   atomic_read(&sent[SMB2_CLOSE]),
+		   atomic_read(&failed[SMB2_CLOSE]));
 	seq_printf(m, "\nFlushes: %d total %d failed",
-		   atomic_read(&sent[SMB2_FLUSH_HE]),
-		   atomic_read(&failed[SMB2_FLUSH_HE]));
+		   atomic_read(&sent[SMB2_FLUSH]),
+		   atomic_read(&failed[SMB2_FLUSH]));
 	seq_printf(m, "\nReads: %d total %d failed",
-		   atomic_read(&sent[SMB2_READ_HE]),
-		   atomic_read(&failed[SMB2_READ_HE]));
+		   atomic_read(&sent[SMB2_READ]),
+		   atomic_read(&failed[SMB2_READ]));
 	seq_printf(m, "\nWrites: %d total %d failed",
-		   atomic_read(&sent[SMB2_WRITE_HE]),
-		   atomic_read(&failed[SMB2_WRITE_HE]));
+		   atomic_read(&sent[SMB2_WRITE]),
+		   atomic_read(&failed[SMB2_WRITE]));
 	seq_printf(m, "\nLocks: %d total %d failed",
-		   atomic_read(&sent[SMB2_LOCK_HE]),
-		   atomic_read(&failed[SMB2_LOCK_HE]));
+		   atomic_read(&sent[SMB2_LOCK]),
+		   atomic_read(&failed[SMB2_LOCK]));
 	seq_printf(m, "\nIOCTLs: %d total %d failed",
-		   atomic_read(&sent[SMB2_IOCTL_HE]),
-		   atomic_read(&failed[SMB2_IOCTL_HE]));
+		   atomic_read(&sent[SMB2_IOCTL]),
+		   atomic_read(&failed[SMB2_IOCTL]));
 	seq_printf(m, "\nQueryDirectories: %d total %d failed",
-		   atomic_read(&sent[SMB2_QUERY_DIRECTORY_HE]),
-		   atomic_read(&failed[SMB2_QUERY_DIRECTORY_HE]));
+		   atomic_read(&sent[SMB2_QUERY_DIRECTORY]),
+		   atomic_read(&failed[SMB2_QUERY_DIRECTORY]));
 	seq_printf(m, "\nChangeNotifies: %d total %d failed",
-		   atomic_read(&sent[SMB2_CHANGE_NOTIFY_HE]),
-		   atomic_read(&failed[SMB2_CHANGE_NOTIFY_HE]));
+		   atomic_read(&sent[SMB2_CHANGE_NOTIFY]),
+		   atomic_read(&failed[SMB2_CHANGE_NOTIFY]));
 	seq_printf(m, "\nQueryInfos: %d total %d failed",
-		   atomic_read(&sent[SMB2_QUERY_INFO_HE]),
-		   atomic_read(&failed[SMB2_QUERY_INFO_HE]));
+		   atomic_read(&sent[SMB2_QUERY_INFO]),
+		   atomic_read(&failed[SMB2_QUERY_INFO]));
 	seq_printf(m, "\nSetInfos: %d total %d failed",
-		   atomic_read(&sent[SMB2_SET_INFO_HE]),
-		   atomic_read(&failed[SMB2_SET_INFO_HE]));
+		   atomic_read(&sent[SMB2_SET_INFO]),
+		   atomic_read(&failed[SMB2_SET_INFO]));
 	seq_printf(m, "\nOplockBreaks: %d sent %d failed",
-		   atomic_read(&sent[SMB2_OPLOCK_BREAK_HE]),
-		   atomic_read(&failed[SMB2_OPLOCK_BREAK_HE]));
+		   atomic_read(&sent[SMB2_OPLOCK_BREAK]),
+		   atomic_read(&failed[SMB2_OPLOCK_BREAK]));
 }
 
 static void
@@ -4626,7 +4626,7 @@ handle_read_data(struct TCP_Server_Info *server, struct smb_message *smb,
 	int length;
 	bool use_rdma_mr = false;
 
-	if (le16_to_cpu(shdr->Command) != SMB2_READ_HE) {
+	if (le16_to_cpu(shdr->Command) != SMB2_READ) {
 		cifs_server_dbg(VFS, "only big read responses are supported\n");
 		return -EOPNOTSUPP;
 	}
@@ -5715,7 +5715,7 @@ struct smb_version_values smb20_values = {
 	.header_preamble_size = 0,
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK_HE,
+	.lock_cmd = SMB2_LOCK,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
@@ -5737,7 +5737,7 @@ struct smb_version_values smb21_values = {
 	.header_preamble_size = 0,
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK_HE,
+	.lock_cmd = SMB2_LOCK,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
@@ -5758,7 +5758,7 @@ struct smb_version_values smb3any_values = {
 	.header_preamble_size = 0,
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK_HE,
+	.lock_cmd = SMB2_LOCK,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
@@ -5779,7 +5779,7 @@ struct smb_version_values smbdefault_values = {
 	.header_preamble_size = 0,
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK_HE,
+	.lock_cmd = SMB2_LOCK,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
@@ -5800,7 +5800,7 @@ struct smb_version_values smb30_values = {
 	.header_preamble_size = 0,
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK_HE,
+	.lock_cmd = SMB2_LOCK,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
@@ -5821,7 +5821,7 @@ struct smb_version_values smb302_values = {
 	.header_preamble_size = 0,
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK_HE,
+	.lock_cmd = SMB2_LOCK,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
@@ -5842,7 +5842,7 @@ struct smb_version_values smb311_values = {
 	.header_preamble_size = 0,
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK_HE,
+	.lock_cmd = SMB2_LOCK,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 97a267ce2a62..8554a4aa001d 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -230,7 +230,7 @@ smb2_reconnect(enum smb2_command smb2_command, struct cifs_tcon *tcon,
 	if (tcon == NULL)
 		return 0;
 
-	if (smb2_command == SMB2_TREE_CONNECT_HE)
+	if (smb2_command == SMB2_TREE_CONNECT)
 		return 0;
 
 	spin_lock(&tcon->tc_lock);
@@ -238,7 +238,7 @@ smb2_reconnect(enum smb2_command smb2_command, struct cifs_tcon *tcon,
 		/*
 		 * only tree disconnect allowed when disconnecting ...
 		 */
-		if (smb2_command != SMB2_TREE_DISCONNECT_HE) {
+		if (smb2_command != SMB2_TREE_DISCONNECT) {
 			spin_unlock(&tcon->tc_lock);
 			cifs_dbg(FYI, "can not send cmd %d while umounting\n",
 				 smb2_command);
@@ -269,10 +269,10 @@ smb2_reconnect(enum smb2_command smb2_command, struct cifs_tcon *tcon,
 		/*
 		 * BB Should we keep oplock break and add flush to exceptions?
 		 */
-		case SMB2_TREE_DISCONNECT_HE:
-		case SMB2_CANCEL_HE:
-		case SMB2_CLOSE_HE:
-		case SMB2_OPLOCK_BREAK_HE:
+		case SMB2_TREE_DISCONNECT:
+		case SMB2_CANCEL:
+		case SMB2_CLOSE:
+		case SMB2_OPLOCK_BREAK:
 			spin_unlock(&server->srv_lock);
 			return -EAGAIN;
 		default:
@@ -464,7 +464,7 @@ smb2_reconnect(enum smb2_command smb2_command, struct cifs_tcon *tcon,
 	ses->flags &= ~CIFS_SES_FLAG_SCALE_CHANNELS;
 	spin_unlock(&ses->ses_lock);
 
-	if (smb2_command != SMB2_INTERNAL_CMD_HE)
+	if (smb2_command != SMB2_INTERNAL_CMD)
 		mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
 
 	atomic_inc(&tconInfoReconnectCount);
@@ -478,15 +478,15 @@ smb2_reconnect(enum smb2_command smb2_command, struct cifs_tcon *tcon,
 	 * case it and skip above?
 	 */
 	switch (smb2_command) {
-	case SMB2_FLUSH_HE:
-	case SMB2_READ_HE:
-	case SMB2_WRITE_HE:
-	case SMB2_LOCK_HE:
-	case SMB2_QUERY_DIRECTORY_HE:
-	case SMB2_CHANGE_NOTIFY_HE:
-	case SMB2_QUERY_INFO_HE:
-	case SMB2_SET_INFO_HE:
-	case SMB2_IOCTL_HE:
+	case SMB2_FLUSH:
+	case SMB2_READ:
+	case SMB2_WRITE:
+	case SMB2_LOCK:
+	case SMB2_QUERY_DIRECTORY:
+	case SMB2_CHANGE_NOTIFY:
+	case SMB2_QUERY_INFO:
+	case SMB2_SET_INFO:
+	case SMB2_IOCTL:
 		rc = -EAGAIN;
 		break;
 	default:
@@ -528,8 +528,8 @@ static int __smb2_plain_req_init(enum smb2_command smb2_command, struct cifs_tco
 {
 	/* BB eventually switch this to SMB2 specific small buf size */
 	switch (smb2_command) {
-	case SMB2_SET_INFO_HE:
-	case SMB2_QUERY_INFO_HE:
+	case SMB2_SET_INFO:
+	case SMB2_QUERY_INFO:
 		*request_buf = cifs_buf_get();
 		break;
 	default:
@@ -581,10 +581,10 @@ static int smb2_ioctl_req_init(u32 opcode, struct cifs_tcon *tcon,
 	if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO ||
 	    (opcode == FSCTL_QUERY_NETWORK_INTERFACE_INFO &&
 	     (tcon->ses->flags & CIFS_SES_FLAGS_PENDING_QUERY_INTERFACES)))
-		return __smb2_plain_req_init(SMB2_IOCTL_HE, tcon, server,
+		return __smb2_plain_req_init(SMB2_IOCTL, tcon, server,
 					     request_buf, total_len);
 
-	return smb2_plain_req_init(SMB2_IOCTL_HE, tcon, server,
+	return smb2_plain_req_init(SMB2_IOCTL, tcon, server,
 				   request_buf, total_len);
 }
 
@@ -1069,7 +1069,7 @@ SMB2_negotiate(const unsigned int xid,
 		return -EIO;
 	}
 
-	rc = smb2_plain_req_init(SMB2_NEGOTIATE_HE, NULL, server,
+	rc = smb2_plain_req_init(SMB2_NEGOTIATE, NULL, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -1469,7 +1469,7 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
 	unsigned int total_len;
 	bool is_binding = false;
 
-	rc = smb2_plain_req_init(SMB2_SESSION_SETUP_HE, NULL, server,
+	rc = smb2_plain_req_init(SMB2_SESSION_SETUP, NULL, server,
 				 (void **) &req,
 				 &total_len);
 	if (rc)
@@ -1984,7 +1984,7 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
 	}
 	spin_unlock(&ses->chan_lock);
 
-	rc = smb2_plain_req_init(SMB2_LOGOFF_HE, NULL, ses->server,
+	rc = smb2_plain_req_init(SMB2_LOGOFF, NULL, ses->server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -2069,7 +2069,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
 	/* SMB2 TREE_CONNECT request must be called with TreeId == 0 */
 	tcon->tid = 0;
 	atomic_set(&tcon->num_remote_opens, 0);
-	rc = smb2_plain_req_init(SMB2_TREE_CONNECT_HE, tcon, server,
+	rc = smb2_plain_req_init(SMB2_TREE_CONNECT, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc) {
 		kfree(unc_path);
@@ -2119,7 +2119,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
 	rsp = (struct smb2_tree_connect_rsp *)rsp_iov.iov_base;
 	trace_smb3_tcon(xid, tcon->tid, ses->Suid, tree, rc);
 	if ((rc != 0) || (rsp == NULL)) {
-		cifs_stats_fail_inc(tcon, SMB2_TREE_CONNECT_HE);
+		cifs_stats_fail_inc(tcon, SMB2_TREE_CONNECT);
 		tcon->need_reconnect = true;
 		goto tcon_error_exit;
 	}
@@ -2204,7 +2204,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
 
 	invalidate_all_cached_dirs(tcon);
 
-	rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT_HE, tcon, server,
+	rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT, tcon, server,
 				 (void **) &req,
 				 &total_len);
 	if (rc)
@@ -2226,7 +2226,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
 			    &rqst, &resp_buf_type, flags, &rsp_iov);
 	cifs_small_buf_release(req);
 	if (rc) {
-		cifs_stats_fail_inc(tcon, SMB2_TREE_DISCONNECT_HE);
+		cifs_stats_fail_inc(tcon, SMB2_TREE_DISCONNECT);
 		trace_smb3_tdis_err(xid, tcon->tid, ses->Suid, rc);
 	}
 	trace_smb3_tdis_done(xid, tcon->tid, ses->Suid);
@@ -2867,7 +2867,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
 	}
 
 	/* resource #2: request */
-	rc = smb2_plain_req_init(SMB2_CREATE_HE, tcon, server,
+	rc = smb2_plain_req_init(SMB2_CREATE, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		goto err_free_path;
@@ -2965,7 +2965,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
 	rc = cifs_send_recv(xid, ses, server,
 			    &rqst, &resp_buftype, flags, &rsp_iov);
 	if (rc) {
-		cifs_stats_fail_inc(tcon, SMB2_CREATE_HE);
+		cifs_stats_fail_inc(tcon, SMB2_CREATE);
 		trace_smb3_posix_mkdir_err(xid, tcon->tid, ses->Suid,
 					   CREATE_NOT_FILE,
 					   FILE_WRITE_ATTRIBUTES, rc);
@@ -3021,7 +3021,7 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
 	__le16 *copy_path;
 	int rc;
 
-	rc = smb2_plain_req_init(SMB2_CREATE_HE, tcon, server,
+	rc = smb2_plain_req_init(SMB2_CREATE, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -3244,7 +3244,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
 	rsp = (struct smb2_create_rsp *)rsp_iov.iov_base;
 
 	if (rc != 0) {
-		cifs_stats_fail_inc(tcon, SMB2_CREATE_HE);
+		cifs_stats_fail_inc(tcon, SMB2_CREATE);
 		if (err_iov && rsp) {
 			*err_iov = rsp_iov;
 			*buftype = resp_buftype;
@@ -3473,17 +3473,17 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
 				ses->Suid, 0, opcode, rc);
 
 	if ((rc != 0) && (rc != -EINVAL) && (rc != -E2BIG)) {
-		cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
+		cifs_stats_fail_inc(tcon, SMB2_IOCTL);
 		goto ioctl_exit;
 	} else if (rc == -EINVAL) {
 		if ((opcode != FSCTL_SRV_COPYCHUNK_WRITE) &&
 		    (opcode != FSCTL_SRV_COPYCHUNK)) {
-			cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
+			cifs_stats_fail_inc(tcon, SMB2_IOCTL);
 			goto ioctl_exit;
 		}
 	} else if (rc == -E2BIG) {
 		if (opcode != FSCTL_QUERY_ALLOCATED_RANGES) {
-			cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
+			cifs_stats_fail_inc(tcon, SMB2_IOCTL);
 			goto ioctl_exit;
 		}
 	}
@@ -3576,7 +3576,7 @@ SMB2_close_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
 	unsigned int total_len;
 	int rc;
 
-	rc = smb2_plain_req_init(SMB2_CLOSE_HE, tcon, server,
+	rc = smb2_plain_req_init(SMB2_CLOSE, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -3655,7 +3655,7 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
 	rsp = (struct smb2_close_rsp *)rsp_iov.iov_base;
 
 	if (rc != 0) {
-		cifs_stats_fail_inc(tcon, SMB2_CLOSE_HE);
+		cifs_stats_fail_inc(tcon, SMB2_CLOSE);
 		trace_smb3_close_err(xid, persistent_fid, tcon->tid, ses->Suid,
 				     rc);
 		goto close_exit;
@@ -3770,7 +3770,7 @@ SMB2_query_info_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
 		     len > CIFSMaxBufSize))
 		return -EINVAL;
 
-	rc = smb2_plain_req_init(SMB2_QUERY_INFO_HE, tcon, server,
+	rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -3860,7 +3860,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
 	rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
 
 	if (rc) {
-		cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
+		cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO);
 		trace_smb3_query_info_err(xid, persistent_fid, tcon->tid,
 				ses->Suid, info_class, (__u32)info_type, rc);
 		goto qinf_exit;
@@ -3971,7 +3971,7 @@ SMB2_notify_init(const unsigned int xid, struct smb_rqst *rqst,
 	unsigned int total_len;
 	int rc;
 
-	rc = smb2_plain_req_init(SMB2_CHANGE_NOTIFY_HE, tcon, server,
+	rc = smb2_plain_req_init(SMB2_CHANGE_NOTIFY, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -4046,7 +4046,7 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
 			    &rqst, &resp_buftype, flags, &rsp_iov);
 
 	if (rc != 0) {
-		cifs_stats_fail_inc(tcon, SMB2_CHANGE_NOTIFY_HE);
+		cifs_stats_fail_inc(tcon, SMB2_CHANGE_NOTIFY);
 		trace_smb3_notify_err(xid, persistent_fid, tcon->tid, ses->Suid,
 				(u8)watch_tree, completion_filter, rc);
 	} else {
@@ -4208,7 +4208,7 @@ void smb2_reconnect_server(struct work_struct *work)
 	spin_unlock(&cifs_tcp_ses_lock);
 
 	list_for_each_entry_safe(tcon, tcon2, &tmp_list, rlist) {
-		rc = smb2_reconnect(SMB2_INTERNAL_CMD_HE, tcon, server, true);
+		rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server, true);
 		if (!rc) {
 			cifs_renegotiate_iosize(server, tcon);
 			cifs_reopen_persistent_handles(tcon);
@@ -4240,7 +4240,7 @@ void smb2_reconnect_server(struct work_struct *work)
 	/* now reconnect sessions for necessary channels */
 	list_for_each_entry_safe(ses, ses2, &tmp_ses_list, rlist) {
 		tcon->ses = ses;
-		rc = smb2_reconnect(SMB2_INTERNAL_CMD_HE, tcon, server, true);
+		rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server, true);
 		if (rc)
 			resched = true;
 		list_del_init(&ses->rlist);
@@ -4280,7 +4280,7 @@ SMB2_echo(struct TCP_Server_Info *server)
 	}
 	spin_unlock(&server->srv_lock);
 
-	rc = smb2_plain_req_init(SMB2_ECHO_HE, NULL, server,
+	rc = smb2_plain_req_init(SMB2_ECHO, NULL, server,
 				 (void **)&req, &total_len);
 	if (rc)
 		return rc;
@@ -4316,7 +4316,7 @@ SMB2_flush_init(const unsigned int xid, struct smb_rqst *rqst,
 	unsigned int total_len;
 	int rc;
 
-	rc = smb2_plain_req_init(SMB2_FLUSH_HE, tcon, server,
+	rc = smb2_plain_req_init(SMB2_FLUSH, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -4375,7 +4375,7 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
 			    &rqst, &resp_buftype, flags, &rsp_iov);
 
 	if (rc != 0) {
-		cifs_stats_fail_inc(tcon, SMB2_FLUSH_HE);
+		cifs_stats_fail_inc(tcon, SMB2_FLUSH);
 		trace_smb3_flush_err(xid, persistent_fid, tcon->tid, ses->Suid,
 				     rc);
 	} else
@@ -4437,7 +4437,7 @@ smb2_new_read_req(void **buf, unsigned int *total_len,
 	struct smb2_hdr *shdr;
 	struct TCP_Server_Info *server = io_parms->server;
 
-	rc = smb2_plain_req_init(SMB2_READ_HE, io_parms->tcon, server,
+	rc = smb2_plain_req_init(SMB2_READ, io_parms->tcon, server,
 				 (void **) &req, total_len);
 	if (rc)
 		return rc;
@@ -4606,7 +4606,7 @@ smb2_readv_callback(struct smb_message *smb)
 	}
 #endif
 	if (rdata->result && rdata->result != -ENODATA) {
-		cifs_stats_fail_inc(tcon, SMB2_READ_HE);
+		cifs_stats_fail_inc(tcon, SMB2_READ);
 		trace_smb3_read_err(rdata->rreq->debug_id,
 				    rdata->subreq.debug_index,
 				    rdata->xid,
@@ -4720,7 +4720,7 @@ smb2_async_readv(struct cifs_io_subrequest *rdata)
 			     smb3_handle_read_data, rdata, flags,
 			     &rdata->credits);
 	if (rc) {
-		cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE);
+		cifs_stats_fail_inc(io_parms.tcon, SMB2_READ);
 		trace_smb3_read_err(rdata->rreq->debug_id,
 				    subreq->debug_index,
 				    rdata->xid, io_parms.persistent_fid,
@@ -4773,7 +4773,7 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
 
 	if (rc) {
 		if (rc != -ENODATA) {
-			cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE);
+			cifs_stats_fail_inc(io_parms->tcon, SMB2_READ);
 			cifs_dbg(VFS, "Send error in read = %d\n", rc);
 			trace_smb3_read_err(0, 0, xid,
 					    req->PersistentFileId,
@@ -4908,7 +4908,7 @@ smb2_writev_callback(struct smb_message *smb)
 	}
 #endif
 	if (result) {
-		cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
+		cifs_stats_fail_inc(tcon, SMB2_WRITE);
 		trace_smb3_write_err(wdata->rreq->debug_id,
 				     wdata->subreq.debug_index,
 				     wdata->xid,
@@ -4969,7 +4969,7 @@ smb2_async_writev(struct cifs_io_subrequest *wdata)
 	};
 	io_parms = &_io_parms;
 
-	rc = smb2_plain_req_init(SMB2_WRITE_HE, tcon, server,
+	rc = smb2_plain_req_init(SMB2_WRITE, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		goto out;
@@ -5089,7 +5089,7 @@ smb2_async_writev(struct cifs_io_subrequest *wdata)
 				     io_parms->offset,
 				     io_parms->length,
 				     rc);
-		cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
+		cifs_stats_fail_inc(tcon, SMB2_WRITE);
 	}
 
 async_writev_out:
@@ -5141,7 +5141,7 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
 	if (n_vec < 1)
 		return rc;
 
-	rc = smb2_plain_req_init(SMB2_WRITE_HE, io_parms->tcon, server,
+	rc = smb2_plain_req_init(SMB2_WRITE, io_parms->tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -5188,7 +5188,7 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
 				     io_parms->tcon->tid,
 				     io_parms->tcon->ses->Suid,
 				     io_parms->offset, io_parms->length, rc);
-		cifs_stats_fail_inc(io_parms->tcon, SMB2_WRITE_HE);
+		cifs_stats_fail_inc(io_parms->tcon, SMB2_WRITE);
 		cifs_dbg(VFS, "Send error in write = %d\n", rc);
 	} else {
 		*nbytes = le32_to_cpu(rsp->DataLength);
@@ -5374,7 +5374,7 @@ int SMB2_query_directory_init(const unsigned int xid,
 	struct kvec *iov = rqst->rq_iov;
 	int len, rc;
 
-	rc = smb2_plain_req_init(SMB2_QUERY_DIRECTORY_HE, tcon, server,
+	rc = smb2_plain_req_init(SMB2_QUERY_DIRECTORY, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -5568,7 +5568,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
 		} else {
 			trace_smb3_query_dir_err(xid, persistent_fid, tcon->tid,
 				tcon->ses->Suid, index, 0, rc);
-			cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE);
+			cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY);
 		}
 		goto qdir_exit;
 	}
@@ -5608,7 +5608,7 @@ SMB2_set_info_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
 	unsigned int i, total_len;
 	int rc;
 
-	rc = smb2_plain_req_init(SMB2_SET_INFO_HE, tcon, server,
+	rc = smb2_plain_req_init(SMB2_SET_INFO, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -5704,7 +5704,7 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
 	rsp = (struct smb2_set_info_rsp *)rsp_iov.iov_base;
 
 	if (rc != 0) {
-		cifs_stats_fail_inc(tcon, SMB2_SET_INFO_HE);
+		cifs_stats_fail_inc(tcon, SMB2_SET_INFO);
 		trace_smb3_set_info_err(xid, persistent_fid, tcon->tid,
 				ses->Suid, info_class, (__u32)info_type, rc);
 	}
@@ -5782,7 +5782,7 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
 	server = cifs_pick_channel(ses);
 
 	cifs_dbg(FYI, "SMB2_oplock_break\n");
-	rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK_HE, tcon, server,
+	rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -5811,7 +5811,7 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
 			    &rqst, &resp_buf_type, flags, &rsp_iov);
 	cifs_small_buf_release(req);
 	if (rc) {
-		cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE);
+		cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK);
 		cifs_dbg(FYI, "Send error in Oplock Break = %d\n", rc);
 	}
 
@@ -5868,7 +5868,7 @@ build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon,
 	if ((tcon->ses == NULL) || server == NULL)
 		return -EIO;
 
-	rc = smb2_plain_req_init(SMB2_QUERY_INFO_HE, tcon, server,
+	rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -5935,7 +5935,7 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
 			    &rqst, &resp_buftype, flags, &rsp_iov);
 	free_qfs_info_req(&iov);
 	if (rc) {
-		cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
+		cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO);
 		goto posix_qfsinf_exit;
 	}
 	rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
@@ -6016,7 +6016,7 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
 			    &rqst, &resp_buftype, flags, &rsp_iov);
 	free_qfs_info_req(&iov);
 	if (rc) {
-		cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
+		cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO);
 		goto qfsattr_exit;
 	}
 	rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
@@ -6081,7 +6081,7 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
 
 	cifs_dbg(FYI, "smb2_lockv num lock %d\n", num_lock);
 
-	rc = smb2_plain_req_init(SMB2_LOCK_HE, tcon, server,
+	rc = smb2_plain_req_init(SMB2_LOCK, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -6117,7 +6117,7 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
 	cifs_small_buf_release(req);
 	if (rc) {
 		cifs_dbg(FYI, "Send error in smb2_lockv = %d\n", rc);
-		cifs_stats_fail_inc(tcon, SMB2_LOCK_HE);
+		cifs_stats_fail_inc(tcon, SMB2_LOCK);
 		trace_smb3_lock_err(xid, persist_fid, tcon->tid,
 				    tcon->ses->Suid, rc);
 	}
@@ -6164,7 +6164,7 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
 	struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
 
 	cifs_dbg(FYI, "SMB2_lease_break\n");
-	rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK_HE, tcon, server,
+	rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK, tcon, server,
 				 (void **) &req, &total_len);
 	if (rc)
 		return rc;
@@ -6195,7 +6195,7 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
 	please_key_low = (__u64 *)lease_key;
 	please_key_high = (__u64 *)(lease_key+8);
 	if (rc) {
-		cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE);
+		cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK);
 		trace_smb3_lease_err(le32_to_cpu(lease_state), tcon->tid,
 			ses->Suid, *please_key_low, *please_key_high, rc);
 		cifs_dbg(FYI, "Send error in Lease Break = %d\n", rc);
diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index 806ced5d0783..fcf0999e77aa 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -671,7 +671,7 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 	shdr = (struct smb2_hdr *)rqst->rq_iov[0].iov_base;
 	ssr = (struct smb2_sess_setup_req *)shdr;
 
-	is_binding = le16_to_cpu(shdr->Command) == SMB2_SESSION_SETUP_HE &&
+	is_binding = le16_to_cpu(shdr->Command) == SMB2_SESSION_SETUP &&
 		(ssr->Flags & SMB2_SESSION_REQ_FLAG_BINDING);
 	is_signed = shdr->Flags & SMB2_FLAGS_SIGNED;
 
@@ -702,9 +702,9 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 	struct smb2_hdr *shdr =
 			(struct smb2_hdr *)rqst->rq_iov[0].iov_base;
 
-	if (le16_to_cpu(shdr->Command) == SMB2_NEGOTIATE_HE ||
-	    le16_to_cpu(shdr->Command) == SMB2_SESSION_SETUP_HE ||
-	    le16_to_cpu(shdr->Command) == SMB2_OPLOCK_BREAK_HE ||
+	if (le16_to_cpu(shdr->Command) == SMB2_NEGOTIATE ||
+	    le16_to_cpu(shdr->Command) == SMB2_SESSION_SETUP ||
+	    le16_to_cpu(shdr->Command) == SMB2_OPLOCK_BREAK ||
 	    server->ignore_signature ||
 	    (!server->session_estab))
 		return 0;
@@ -812,7 +812,7 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server,
 	}
 
 	if (server->tcpStatus == CifsNeedNegotiate &&
-	    le16_to_cpu(shdr->Command) != SMB2_NEGOTIATE_HE) {
+	    le16_to_cpu(shdr->Command) != SMB2_NEGOTIATE) {
 		spin_unlock(&server->srv_lock);
 		return -EAGAIN;
 	}
@@ -820,8 +820,8 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server,
 
 	spin_lock(&ses->ses_lock);
 	if (ses->ses_status == SES_NEW) {
-		if (le16_to_cpu(shdr->Command) != SMB2_SESSION_SETUP_HE &&
-		    le16_to_cpu(shdr->Command) != SMB2_NEGOTIATE_HE) {
+		if (le16_to_cpu(shdr->Command) != SMB2_SESSION_SETUP &&
+		    le16_to_cpu(shdr->Command) != SMB2_NEGOTIATE) {
 			spin_unlock(&ses->ses_lock);
 			return -EAGAIN;
 		}
@@ -829,7 +829,7 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server,
 	}
 
 	if (ses->ses_status == SES_EXITING) {
-		if (le16_to_cpu(shdr->Command) != SMB2_LOGOFF_HE) {
+		if (le16_to_cpu(shdr->Command) != SMB2_LOGOFF) {
 			spin_unlock(&ses->ses_lock);
 			return -EAGAIN;
 		}
@@ -910,7 +910,7 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 
 	spin_lock(&server->srv_lock);
 	if (server->tcpStatus == CifsNeedNegotiate &&
-	    le16_to_cpu(shdr->Command) != SMB2_NEGOTIATE_HE) {
+	    le16_to_cpu(shdr->Command) != SMB2_NEGOTIATE) {
 		spin_unlock(&server->srv_lock);
 		return ERR_PTR(-EAGAIN);
 	}
diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h
index 2f4b158518cd..7da40d229ab5 100644
--- a/fs/smb/common/smb2pdu.h
+++ b/fs/smb/common/smb2pdu.h
@@ -16,29 +16,29 @@
 
 /* List of commands in host endian */
 enum smb2_command {
-    SMB2_NEGOTIATE_HE			= 0x0000,
-    SMB2_SESSION_SETUP_HE		= 0x0001,
-    SMB2_LOGOFF_HE			= 0x0002, /* trivial request/resp */
-    SMB2_TREE_CONNECT_HE		= 0x0003,
-    SMB2_TREE_DISCONNECT_HE		= 0x0004, /* trivial req/resp */
-    SMB2_CREATE_HE			= 0x0005,
-    SMB2_CLOSE_HE			= 0x0006,
-    SMB2_FLUSH_HE			= 0x0007, /* trivial resp */
-    SMB2_READ_HE			= 0x0008,
-    SMB2_WRITE_HE			= 0x0009,
-    SMB2_LOCK_HE			= 0x000A,
-    SMB2_IOCTL_HE			= 0x000B,
-    SMB2_CANCEL_HE			= 0x000C,
-    SMB2_ECHO_HE			= 0x000D,
-    SMB2_QUERY_DIRECTORY_HE		= 0x000E,
-    SMB2_CHANGE_NOTIFY_HE		= 0x000F,
-    SMB2_QUERY_INFO_HE			= 0x0010,
-    SMB2_SET_INFO_HE			= 0x0011,
-    SMB2_OPLOCK_BREAK_HE		= 0x0012,
+    SMB2_NEGOTIATE		= 0x0000,
+    SMB2_SESSION_SETUP		= 0x0001,
+    SMB2_LOGOFF			= 0x0002, /* trivial request/resp */
+    SMB2_TREE_CONNECT		= 0x0003,
+    SMB2_TREE_DISCONNECT	= 0x0004, /* trivial req/resp */
+    SMB2_CREATE			= 0x0005,
+    SMB2_CLOSE			= 0x0006,
+    SMB2_FLUSH			= 0x0007, /* trivial resp */
+    SMB2_READ			= 0x0008,
+    SMB2_WRITE			= 0x0009,
+    SMB2_LOCK			= 0x000A,
+    SMB2_IOCTL			= 0x000B,
+    SMB2_CANCEL			= 0x000C,
+    SMB2_ECHO			= 0x000D,
+    SMB2_QUERY_DIRECTORY	= 0x000E,
+    SMB2_CHANGE_NOTIFY		= 0x000F,
+    SMB2_QUERY_INFO		= 0x0010,
+    SMB2_SET_INFO		= 0x0011,
+    SMB2_OPLOCK_BREAK		= 0x0012,
     SMB2_SERVER_TO_CLIENT_NOTIFICATION	= 0x0013
 };
 
-#define SMB2_INTERNAL_CMD_HE		0xFFFF
+#define SMB2_INTERNAL_CMD	0xFFFF
 
 #define NUMBER_OF_SMB2_COMMANDS	0x0013
 
diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c
index 3f04a2977ba8..b9914c88f5c5 100644
--- a/fs/smb/server/connection.c
+++ b/fs/smb/server/connection.c
@@ -118,7 +118,7 @@ void ksmbd_conn_enqueue_request(struct ksmbd_work *work)
 	struct ksmbd_conn *conn = work->conn;
 	struct list_head *requests_queue = NULL;
 
-	if (conn->ops->get_cmd_val(work) != SMB2_CANCEL_HE)
+	if (conn->ops->get_cmd_val(work) != SMB2_CANCEL)
 		requests_queue = &conn->requests;
 
 	atomic_inc(&conn->req_running);
diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
index dd3c046aeae3..d99842336c62 100644
--- a/fs/smb/server/oplock.c
+++ b/fs/smb/server/oplock.c
@@ -642,7 +642,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
 	rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;
 	rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
 	rsp_hdr->CreditRequest = cpu_to_le16(0);
-	rsp_hdr->Command = cpu_to_le16(SMB2_OPLOCK_BREAK_HE);
+	rsp_hdr->Command = cpu_to_le16(SMB2_OPLOCK_BREAK);
 	rsp_hdr->Flags = (SMB2_FLAGS_SERVER_TO_REDIR);
 	rsp_hdr->NextCommand = 0;
 	rsp_hdr->MessageId = cpu_to_le64(-1);
@@ -749,7 +749,7 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
 	rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;
 	rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
 	rsp_hdr->CreditRequest = cpu_to_le16(0);
-	rsp_hdr->Command = cpu_to_le16(SMB2_OPLOCK_BREAK_HE);
+	rsp_hdr->Command = cpu_to_le16(SMB2_OPLOCK_BREAK);
 	rsp_hdr->Flags = (SMB2_FLAGS_SERVER_TO_REDIR);
 	rsp_hdr->NextCommand = 0;
 	rsp_hdr->MessageId = cpu_to_le64(-1);
diff --git a/fs/smb/server/smb2misc.c b/fs/smb/server/smb2misc.c
index 41323492f214..faa0346ca21c 100644
--- a/fs/smb/server/smb2misc.c
+++ b/fs/smb/server/smb2misc.c
@@ -96,17 +96,17 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
 	 * command.
 	 */
 	switch (le16_to_cpu(hdr->Command)) {
-	case SMB2_SESSION_SETUP_HE:
+	case SMB2_SESSION_SETUP:
 		*off = le16_to_cpu(((struct smb2_sess_setup_req *)hdr)->SecurityBufferOffset);
 		*len = le16_to_cpu(((struct smb2_sess_setup_req *)hdr)->SecurityBufferLength);
 		break;
-	case SMB2_TREE_CONNECT_HE:
+	case SMB2_TREE_CONNECT:
 		*off = max_t(unsigned short int,
 			     le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathOffset),
 			     offsetof(struct smb2_tree_connect_req, Buffer));
 		*len = le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathLength);
 		break;
-	case SMB2_CREATE_HE:
+	case SMB2_CREATE:
 	{
 		unsigned short int name_off =
 			max_t(unsigned short int,
@@ -131,23 +131,23 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
 		*len = name_len;
 		break;
 	}
-	case SMB2_QUERY_INFO_HE:
+	case SMB2_QUERY_INFO:
 		*off = max_t(unsigned int,
 			     le16_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferOffset),
 			     offsetof(struct smb2_query_info_req, Buffer));
 		*len = le32_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferLength);
 		break;
-	case SMB2_SET_INFO_HE:
+	case SMB2_SET_INFO:
 		*off = max_t(unsigned int,
 			     le16_to_cpu(((struct smb2_set_info_req *)hdr)->BufferOffset),
 			     offsetof(struct smb2_set_info_req, Buffer));
 		*len = le32_to_cpu(((struct smb2_set_info_req *)hdr)->BufferLength);
 		break;
-	case SMB2_READ_HE:
+	case SMB2_READ:
 		*off = le16_to_cpu(((struct smb2_read_req *)hdr)->ReadChannelInfoOffset);
 		*len = le16_to_cpu(((struct smb2_read_req *)hdr)->ReadChannelInfoLength);
 		break;
-	case SMB2_WRITE_HE:
+	case SMB2_WRITE:
 		if (((struct smb2_write_req *)hdr)->DataOffset ||
 		    ((struct smb2_write_req *)hdr)->Length) {
 			*off = max_t(unsigned short int,
@@ -160,13 +160,13 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
 		*off = le16_to_cpu(((struct smb2_write_req *)hdr)->WriteChannelInfoOffset);
 		*len = le16_to_cpu(((struct smb2_write_req *)hdr)->WriteChannelInfoLength);
 		break;
-	case SMB2_QUERY_DIRECTORY_HE:
+	case SMB2_QUERY_DIRECTORY:
 		*off = max_t(unsigned short int,
 			     le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameOffset),
 			     offsetof(struct smb2_query_directory_req, Buffer));
 		*len = le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameLength);
 		break;
-	case SMB2_LOCK_HE:
+	case SMB2_LOCK:
 	{
 		unsigned short lock_count;
 
@@ -177,7 +177,7 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
 		}
 		break;
 	}
-	case SMB2_IOCTL_HE:
+	case SMB2_IOCTL:
 		*off = max_t(unsigned int,
 			     le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputOffset),
 			     offsetof(struct smb2_ioctl_req, Buffer));
@@ -226,7 +226,7 @@ static int smb2_calc_size(void *buf, unsigned int *len)
 	 * regardless of number of locks. Subtract single
 	 * smb2_lock_element for correct buffer size check.
 	 */
-	if (le16_to_cpu(hdr->Command) == SMB2_LOCK_HE)
+	if (le16_to_cpu(hdr->Command) == SMB2_LOCK)
 		*len -= sizeof(struct smb2_lock_element);
 
 	if (has_smb2_data_area[le16_to_cpu(hdr->Command)] == false)
@@ -307,26 +307,26 @@ static int smb2_validate_credit_charge(struct ksmbd_conn *conn,
 	int ret = 0;
 
 	switch (le16_to_cpu(hdr->Command)) {
-	case SMB2_QUERY_INFO_HE:
+	case SMB2_QUERY_INFO:
 		req_len = smb2_query_info_req_len(__hdr);
 		break;
-	case SMB2_SET_INFO_HE:
+	case SMB2_SET_INFO:
 		req_len = smb2_set_info_req_len(__hdr);
 		break;
-	case SMB2_READ_HE:
+	case SMB2_READ:
 		req_len = smb2_read_req_len(__hdr);
 		break;
-	case SMB2_WRITE_HE:
+	case SMB2_WRITE:
 		req_len = smb2_write_req_len(__hdr);
 		break;
-	case SMB2_QUERY_DIRECTORY_HE:
+	case SMB2_QUERY_DIRECTORY:
 		req_len = smb2_query_dir_req_len(__hdr);
 		break;
-	case SMB2_IOCTL_HE:
+	case SMB2_IOCTL:
 		req_len = smb2_ioctl_req_len(__hdr);
 		expect_resp_len = smb2_ioctl_resp_len(__hdr);
 		break;
-	case SMB2_CANCEL_HE:
+	case SMB2_CANCEL:
 		return 0;
 	default:
 		req_len = 1;
@@ -401,7 +401,7 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
 	}
 
 	if (smb2_req_struct_sizes[command] != pdu->StructureSize2) {
-		if (!(command == SMB2_OPLOCK_BREAK_HE &&
+		if (!(command == SMB2_OPLOCK_BREAK &&
 		    (le16_to_cpu(pdu->StructureSize2) == OP_BREAK_STRUCT_SIZE_20 ||
 		    le16_to_cpu(pdu->StructureSize2) == OP_BREAK_STRUCT_SIZE_21))) {
 			/* special case for SMB2.1 lease break message */
@@ -414,7 +414,7 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
 
 	req_struct_size = le16_to_cpu(pdu->StructureSize2) +
 		__SMB2_HEADER_STRUCTURE_SIZE;
-	if (command == SMB2_LOCK_HE)
+	if (command == SMB2_LOCK)
 		req_struct_size -= sizeof(struct smb2_lock_element);
 
 	if (req_struct_size > len + 1)
@@ -439,7 +439,7 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
 		 * SMB2 NEGOTIATE request will be validated when message
 		 * handling proceeds.
 		 */
-		if (command == SMB2_NEGOTIATE_HE)
+		if (command == SMB2_NEGOTIATE)
 			goto validate_credit;
 
 		/*
@@ -469,5 +469,5 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
 
 int smb2_negotiate_request(struct ksmbd_work *work)
 {
-	return ksmbd_smb_negotiate_common(work, SMB2_NEGOTIATE_HE);
+	return ksmbd_smb_negotiate_common(work, SMB2_NEGOTIATE);
 }
diff --git a/fs/smb/server/smb2ops.c b/fs/smb/server/smb2ops.c
index c9302dd71e53..a528f53b9be6 100644
--- a/fs/smb/server/smb2ops.c
+++ b/fs/smb/server/smb2ops.c
@@ -27,7 +27,7 @@ static struct smb_version_values smb21_server_values = {
 	.header_size = sizeof(struct smb2_hdr),
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK_HE,
+	.lock_cmd = SMB2_LOCK,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
@@ -53,7 +53,7 @@ static struct smb_version_values smb30_server_values = {
 	.header_size = sizeof(struct smb2_hdr),
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK_HE,
+	.lock_cmd = SMB2_LOCK,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
@@ -80,7 +80,7 @@ static struct smb_version_values smb302_server_values = {
 	.header_size = sizeof(struct smb2_hdr),
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK_HE,
+	.lock_cmd = SMB2_LOCK,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
@@ -107,7 +107,7 @@ static struct smb_version_values smb311_server_values = {
 	.header_size = sizeof(struct smb2_hdr),
 	.max_header_size = MAX_SMB2_HDR_SIZE,
 	.read_rsp_size = sizeof(struct smb2_read_rsp),
-	.lock_cmd = SMB2_LOCK_HE,
+	.lock_cmd = SMB2_LOCK,
 	.cap_unix = 0,
 	.cap_nt_find = SMB2_NT_FIND,
 	.cap_large_files = SMB2_LARGE_FILES,
@@ -169,25 +169,25 @@ static struct smb_version_ops smb3_11_server_ops = {
 };
 
 static struct smb_version_cmds smb2_0_server_cmds[NUMBER_OF_SMB2_COMMANDS] = {
-	[SMB2_NEGOTIATE_HE]	=	{ .proc = smb2_negotiate_request, },
-	[SMB2_SESSION_SETUP_HE] =	{ .proc = smb2_sess_setup, },
-	[SMB2_TREE_CONNECT_HE]  =	{ .proc = smb2_tree_connect,},
-	[SMB2_TREE_DISCONNECT_HE]  =	{ .proc = smb2_tree_disconnect,},
-	[SMB2_LOGOFF_HE]	=	{ .proc = smb2_session_logoff,},
-	[SMB2_CREATE_HE]	=	{ .proc = smb2_open},
-	[SMB2_QUERY_INFO_HE]	=	{ .proc = smb2_query_info},
-	[SMB2_QUERY_DIRECTORY_HE] =	{ .proc = smb2_query_dir},
-	[SMB2_CLOSE_HE]		=	{ .proc = smb2_close},
-	[SMB2_ECHO_HE]		=	{ .proc = smb2_echo},
-	[SMB2_SET_INFO_HE]      =       { .proc = smb2_set_info},
-	[SMB2_READ_HE]		=	{ .proc = smb2_read},
-	[SMB2_WRITE_HE]		=	{ .proc = smb2_write},
-	[SMB2_FLUSH_HE]		=	{ .proc = smb2_flush},
-	[SMB2_CANCEL_HE]	=	{ .proc = smb2_cancel},
-	[SMB2_LOCK_HE]		=	{ .proc = smb2_lock},
-	[SMB2_IOCTL_HE]		=	{ .proc = smb2_ioctl},
-	[SMB2_OPLOCK_BREAK_HE]	=	{ .proc = smb2_oplock_break},
-	[SMB2_CHANGE_NOTIFY_HE]	=	{ .proc = smb2_notify},
+	[SMB2_NEGOTIATE]	=	{ .proc = smb2_negotiate_request, },
+	[SMB2_SESSION_SETUP]	=	{ .proc = smb2_sess_setup, },
+	[SMB2_TREE_CONNECT]	=	{ .proc = smb2_tree_connect,},
+	[SMB2_TREE_DISCONNECT]  =	{ .proc = smb2_tree_disconnect,},
+	[SMB2_LOGOFF]		=	{ .proc = smb2_session_logoff,},
+	[SMB2_CREATE]		=	{ .proc = smb2_open},
+	[SMB2_QUERY_INFO]	=	{ .proc = smb2_query_info},
+	[SMB2_QUERY_DIRECTORY]	=	{ .proc = smb2_query_dir},
+	[SMB2_CLOSE]		=	{ .proc = smb2_close},
+	[SMB2_ECHO]		=	{ .proc = smb2_echo},
+	[SMB2_SET_INFO]		=       { .proc = smb2_set_info},
+	[SMB2_READ]		=	{ .proc = smb2_read},
+	[SMB2_WRITE]		=	{ .proc = smb2_write},
+	[SMB2_FLUSH]		=	{ .proc = smb2_flush},
+	[SMB2_CANCEL]		=	{ .proc = smb2_cancel},
+	[SMB2_LOCK]		=	{ .proc = smb2_lock},
+	[SMB2_IOCTL]		=	{ .proc = smb2_ioctl},
+	[SMB2_OPLOCK_BREAK]	=	{ .proc = smb2_oplock_break},
+	[SMB2_CHANGE_NOTIFY]	=	{ .proc = smb2_notify},
 };
 
 /**
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 74749c60d9f6..1ed2bcba649f 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -94,9 +94,9 @@ int smb2_get_ksmbd_tcon(struct ksmbd_work *work)
 	unsigned int cmd = le16_to_cpu(req_hdr->Command);
 	unsigned int tree_id;
 
-	if (cmd == SMB2_TREE_CONNECT_HE ||
-	    cmd ==  SMB2_CANCEL_HE ||
-	    cmd ==  SMB2_LOGOFF_HE) {
+	if (cmd == SMB2_TREE_CONNECT ||
+	    cmd == SMB2_CANCEL ||
+	    cmd == SMB2_LOGOFF) {
 		ksmbd_debug(SMB, "skip to check tree connect request\n");
 		return 0;
 	}
@@ -181,7 +181,7 @@ bool is_smb2_neg_cmd(struct ksmbd_work *work)
 	if (hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR)
 		return false;
 
-	if (le16_to_cpu(hdr->Command) != SMB2_NEGOTIATE_HE)
+	if (le16_to_cpu(hdr->Command) != SMB2_NEGOTIATE)
 		return false;
 
 	return true;
@@ -262,7 +262,7 @@ int init_smb2_neg_rsp(struct ksmbd_work *work)
 	rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;
 	rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
 	rsp_hdr->CreditRequest = cpu_to_le16(2);
-	rsp_hdr->Command = cpu_to_le16(SMB2_NEGOTIATE_HE);
+	rsp_hdr->Command = cpu_to_le16(SMB2_NEGOTIATE);
 	rsp_hdr->Flags = (SMB2_FLAGS_SERVER_TO_REDIR);
 	rsp_hdr->NextCommand = 0;
 	rsp_hdr->MessageId = 0;
@@ -349,7 +349,7 @@ int smb2_set_rsp_credits(struct ksmbd_work *work)
 	 * TODO: Need to adjuct CreditRequest value according to
 	 * current cpu load
 	 */
-	if (le16_to_cpu(hdr->Command) == SMB2_NEGOTIATE_HE)
+	if (le16_to_cpu(hdr->Command) == SMB2_NEGOTIATE)
 		aux_max = 1;
 	else
 		aux_max = conn->vals->max_credits - conn->total_credits;
@@ -389,7 +389,7 @@ static void init_chained_smb2_rsp(struct ksmbd_work *work)
 	/* Storing the current local FID which may be needed by subsequent
 	 * command in the compound request
 	 */
-	if (req->Command == cpu_to_le16(SMB2_CREATE_HE) && rsp->Status == STATUS_SUCCESS) {
+	if (req->Command == cpu_to_le16(SMB2_CREATE) && rsp->Status == STATUS_SUCCESS) {
 		work->compound_fid = ((struct smb2_create_rsp *)rsp)->VolatileFileId;
 		work->compound_pfid = ((struct smb2_create_rsp *)rsp)->PersistentFileId;
 		work->compound_sid = le64_to_cpu(rsp->SessionId);
@@ -532,10 +532,10 @@ int smb2_allocate_rsp_buf(struct ksmbd_work *work)
 	size_t sz = small_sz;
 	int cmd = le16_to_cpu(hdr->Command);
 
-	if (cmd == SMB2_IOCTL_HE || cmd == SMB2_QUERY_DIRECTORY_HE)
+	if (cmd == SMB2_IOCTL || cmd == SMB2_QUERY_DIRECTORY)
 		sz = large_sz;
 
-	if (cmd == SMB2_QUERY_INFO_HE) {
+	if (cmd == SMB2_QUERY_INFO) {
 		struct smb2_query_info_req *req;
 
 		if (get_rfc1002_len(work->request_buf) <
@@ -580,8 +580,8 @@ int smb2_check_user_session(struct ksmbd_work *work)
 	 * require a session id, so no need to validate user session's for
 	 * these commands.
 	 */
-	if (cmd == SMB2_ECHO_HE || cmd == SMB2_NEGOTIATE_HE ||
-	    cmd == SMB2_SESSION_SETUP_HE)
+	if (cmd == SMB2_ECHO || cmd == SMB2_NEGOTIATE ||
+	    cmd == SMB2_SESSION_SETUP)
 		return 0;
 
 	if (!ksmbd_conn_good(conn))
@@ -8819,9 +8819,9 @@ bool smb2_is_sign_req(struct ksmbd_work *work, unsigned int command)
 	struct smb2_hdr *rcv_hdr2 = smb2_get_msg(work->request_buf);
 
 	if ((rcv_hdr2->Flags & SMB2_FLAGS_SIGNED) &&
-	    command != SMB2_NEGOTIATE_HE &&
-	    command != SMB2_SESSION_SETUP_HE &&
-	    command != SMB2_OPLOCK_BREAK_HE)
+	    command != SMB2_NEGOTIATE &&
+	    command != SMB2_SESSION_SETUP &&
+	    command != SMB2_OPLOCK_BREAK)
 		return true;
 
 	return false;
@@ -8887,7 +8887,7 @@ void smb2_set_sign_rsp(struct ksmbd_work *work)
 	hdr->Flags |= SMB2_FLAGS_SIGNED;
 	memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE);
 
-	if (hdr->Command == cpu_to_le16(SMB2_READ_HE)) {
+	if (hdr->Command == cpu_to_le16(SMB2_READ)) {
 		iov = &work->iov[work->iov_idx - 1];
 		n_vec++;
 	} else {
@@ -8928,7 +8928,7 @@ int smb3_check_sign_req(struct ksmbd_work *work)
 		len = get_rfc1002_len(work->request_buf) -
 			work->next_smb2_rcv_hdr_off;
 
-	if (le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
+	if (le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP) {
 		signing_key = work->sess->smb3signingkey;
 	} else {
 		chann = lookup_chann_list(work->sess, conn);
@@ -8977,7 +8977,7 @@ void smb3_set_sign_rsp(struct ksmbd_work *work)
 	hdr = ksmbd_resp_buf_curr(work);
 
 	if (conn->binding == false &&
-	    le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
+	    le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP) {
 		signing_key = work->sess->smb3signingkey;
 	} else {
 		chann = lookup_chann_list(work->sess, work->conn);
@@ -8993,7 +8993,7 @@ void smb3_set_sign_rsp(struct ksmbd_work *work)
 	hdr->Flags |= SMB2_FLAGS_SIGNED;
 	memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE);
 
-	if (hdr->Command == cpu_to_le16(SMB2_READ_HE)) {
+	if (hdr->Command == cpu_to_le16(SMB2_READ)) {
 		iov = &work->iov[work->iov_idx - 1];
 		n_vec++;
 	} else {
@@ -9021,12 +9021,12 @@ void smb3_preauth_hash_rsp(struct ksmbd_work *work)
 
 	WORK_BUFFERS(work, req, rsp);
 
-	if (le16_to_cpu(req->Command) == SMB2_NEGOTIATE_HE &&
+	if (le16_to_cpu(req->Command) == SMB2_NEGOTIATE &&
 	    conn->preauth_info)
 		ksmbd_gen_preauth_integrity_hash(conn, work->response_buf,
 						 conn->preauth_info->Preauth_HashValue);
 
-	if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP_HE && sess) {
+	if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP && sess) {
 		__u8 *hash_value;
 
 		if (conn->binding) {
@@ -9149,7 +9149,7 @@ bool smb3_11_final_sess_setup_resp(struct ksmbd_work *work)
 	if (work->next_smb2_rcv_hdr_off)
 		rsp = ksmbd_resp_buf_next(work);
 
-	if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP_HE &&
+	if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP &&
 	    sess->user && !user_guest(sess->user) &&
 	    rsp->Status == STATUS_SUCCESS)
 		return true;
diff --git a/fs/smb/server/smb_common.c b/fs/smb/server/smb_common.c
index 425c756bcfb8..0e6250483776 100644
--- a/fs/smb/server/smb_common.c
+++ b/fs/smb/server/smb_common.c
@@ -596,7 +596,7 @@ int ksmbd_smb_negotiate_common(struct ksmbd_work *work, unsigned int command)
 		ksmbd_negotiate_smb_dialect(work->request_buf);
 	ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect);
 
-	if (command == SMB2_NEGOTIATE_HE) {
+	if (command == SMB2_NEGOTIATE) {
 		ret = smb2_handle_negotiate(work);
 		return ret;
 	}


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 10/31] cifs: Make smb1's SendReceive() wrap cifs_send_recv()
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (8 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 09/31] cifs: Rename SMB2_xxxx_HE to SMB2_xxxx David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 11/31] cifs: Fix SMB1 to not require separate kvec for the rfc1002 header David Howells
                   ` (24 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Make the smb1 transport's SendReceive() simply wrap cifs_send_recv() as
does SendReceive2().  This will then allow that to pick up the transport
changes there.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/cifstransport.c | 85 +++++------------------------------
 1 file changed, 11 insertions(+), 74 deletions(-)

diff --git a/fs/smb/client/cifstransport.c b/fs/smb/client/cifstransport.c
index a3400a757968..f7fed73bc508 100644
--- a/fs/smb/client/cifstransport.c
+++ b/fs/smb/client/cifstransport.c
@@ -270,13 +270,13 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
 	    int *pbytes_returned, const int flags)
 {
-	int rc = 0;
-	struct smb_message *smb;
 	unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
+	struct TCP_Server_Info *server;
+	struct kvec resp_iov = {};
 	struct kvec iov = { .iov_base = in_buf, .iov_len = len };
 	struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
-	struct cifs_credits credits = { .value = 1, .instance = 0 };
-	struct TCP_Server_Info *server;
+	int resp_buf_type;
+	int rc = 0;
 
 	if (ses == NULL) {
 		cifs_dbg(VFS, "Null smb session\n");
@@ -305,78 +305,15 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 		return -EIO;
 	}
 
-	rc = wait_for_free_request(server, flags, &credits.instance);
-	if (rc)
-		return rc;
-
-	/* make sure that we sign in the same order that we send on this socket
-	   and avoid races inside tcp sendmsg code that could cause corruption
-	   of smb data */
-
-	cifs_server_lock(server);
-
-	rc = allocate_mid(ses, in_buf, &smb);
-	if (rc) {
-		cifs_server_unlock(server);
-		/* Update # of requests on wire to server */
-		add_credits(server, &credits, 0);
-		return rc;
-	}
-
-	rc = cifs_sign_smb(in_buf, server, &smb->sequence_number);
-	if (rc) {
-		cifs_server_unlock(server);
-		goto out;
-	}
-
-	smb->mid_state = MID_REQUEST_SUBMITTED;
-
-	rc = smb_send(server, in_buf, len);
-	cifs_save_when_sent(smb);
-
-	if (rc < 0)
-		server->sequence_number -= 2;
-
-	cifs_server_unlock(server);
-
+	rc = cifs_send_recv(xid, ses, ses->server,
+			    &rqst, &resp_buf_type, flags, &resp_iov);
 	if (rc < 0)
-		goto out;
-
-	rc = wait_for_response(server, smb);
-	if (rc != 0) {
-		send_cancel(server, &rqst, smb);
-		spin_lock(&server->mid_lock);
-		if (smb->mid_state == MID_REQUEST_SUBMITTED ||
-		    smb->mid_state == MID_RESPONSE_RECEIVED) {
-			/* no longer considered to be "in-flight" */
-			smb->callback = release_mid;
-			spin_unlock(&server->mid_lock);
-			add_credits(server, &credits, 0);
-			return rc;
-		}
-		spin_unlock(&server->mid_lock);
-	}
-
-	rc = cifs_sync_mid_result(smb, server);
-	if (rc != 0) {
-		add_credits(server, &credits, 0);
 		return rc;
-	}
-
-	if (!smb->resp_buf || !out_buf ||
-	    smb->mid_state != MID_RESPONSE_READY) {
-		rc = -EIO;
-		cifs_server_dbg(VFS, "Bad MID state?\n");
-		goto out;
-	}
-
-	*pbytes_returned = get_rfc1002_length(smb->resp_buf);
-	memcpy(out_buf, smb->resp_buf, *pbytes_returned + 4);
-	rc = cifs_check_receive(smb, server, 0);
-out:
-	delete_mid(smb);
-	add_credits(server, &credits, 0);
-
+	
+	*pbytes_returned = resp_iov.iov_len;
+	if (resp_iov.iov_len)
+		memcpy(out_buf, resp_iov.iov_base, resp_iov.iov_len);
+	free_rsp_buf(resp_buf_type, resp_iov.iov_base);
 	return rc;
 }
 


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 11/31] cifs: Fix SMB1 to not require separate kvec for the rfc1002 header
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (9 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 10/31] cifs: Make smb1's SendReceive() wrap cifs_send_recv() David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 12/31] cifs: Replace SendReceiveBlockingLock() with SendReceive() plus flags David Howells
                   ` (23 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Fix SMB1 to not require separate kvec for the rfc1002 header, which seems
to be something intended to make the signing algorithm simpler, but at the
expense of additional complexity everywhere else.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/cifsencrypt.c   | 77 +++++++--------------------------
 fs/smb/client/cifsproto.h     |  5 ---
 fs/smb/client/cifssmb.c       | 28 ++++++------
 fs/smb/client/cifstransport.c | 81 +++++++----------------------------
 fs/smb/client/smb1ops.c       | 11 +++--
 fs/smb/client/transport.c     | 27 ++++++------
 6 files changed, 65 insertions(+), 164 deletions(-)

diff --git a/fs/smb/client/cifsencrypt.c b/fs/smb/client/cifsencrypt.c
index 35892df7335c..a1f17604b4c6 100644
--- a/fs/smb/client/cifsencrypt.c
+++ b/fs/smb/client/cifsencrypt.c
@@ -58,38 +58,25 @@ int __cifs_calc_signature(struct smb_rqst *rqst,
 			  struct TCP_Server_Info *server, char *signature,
 			  struct shash_desc *shash)
 {
-	int i;
+	struct iov_iter iter;
 	ssize_t rc;
-	struct kvec *iov = rqst->rq_iov;
-	int n_vec = rqst->rq_nvec;
-
-	/* iov[0] is actual data and not the rfc1002 length for SMB2+ */
-	if (!is_smb1(server)) {
-		if (iov[0].iov_len <= 4)
-			return -EIO;
-		i = 0;
-	} else {
-		if (n_vec < 2 || iov[0].iov_len != 4)
-			return -EIO;
-		i = 1; /* skip rfc1002 length */
-	}
+	size_t size = 0;
 
-	for (; i < n_vec; i++) {
-		if (iov[i].iov_len == 0)
-			continue;
-		if (iov[i].iov_base == NULL) {
-			cifs_dbg(VFS, "null iovec entry\n");
-			return -EIO;
-		}
+	for (int i = 0; i < rqst->rq_nvec; i++)
+		size += rqst->rq_iov[i].iov_len;
 
-		rc = crypto_shash_update(shash,
-					 iov[i].iov_base, iov[i].iov_len);
-		if (rc) {
-			cifs_dbg(VFS, "%s: Could not update with payload\n",
-				 __func__);
-			return rc;
-		}
-	}
+	iov_iter_kvec(&iter, ITER_SOURCE, rqst->rq_iov, rqst->rq_nvec, size);
+
+	/* Skip the rfc1002 length for SMB1 */
+	if (is_smb1(server))
+		iov_iter_advance(&iter, 4);
+
+	if (iov_iter_count(&iter) <= 4)
+		return -EIO;
+
+	rc = cifs_shash_iter(&iter, iov_iter_count(&iter), shash);
+	if (rc < 0)
+		return rc;
 
 	rc = cifs_shash_iter(&rqst->rq_iter, iov_iter_count(&rqst->rq_iter), shash);
 	if (rc < 0)
@@ -145,10 +132,6 @@ int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
 	char smb_signature[20];
 	struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 
-	if (rqst->rq_iov[0].iov_len != 4 ||
-	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
-		return -EIO;
-
 	if ((cifs_pdu == NULL) || (server == NULL))
 		return -EINVAL;
 
@@ -181,30 +164,6 @@ int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
 	return rc;
 }
 
-int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
-		   __u32 *pexpected_response_sequence)
-{
-	struct smb_rqst rqst = { .rq_iov = iov,
-				 .rq_nvec = n_vec };
-
-	return cifs_sign_rqst(&rqst, server, pexpected_response_sequence);
-}
-
-/* must be called with server->srv_mutex held */
-int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
-		  __u32 *pexpected_response_sequence_number)
-{
-	struct kvec iov[2];
-
-	iov[0].iov_base = cifs_pdu;
-	iov[0].iov_len = 4;
-	iov[1].iov_base = (char *)cifs_pdu + 4;
-	iov[1].iov_len = be32_to_cpu(cifs_pdu->smb_buf_length);
-
-	return cifs_sign_smbv(iov, 2, server,
-			      pexpected_response_sequence_number);
-}
-
 int cifs_verify_signature(struct smb_rqst *rqst,
 			  struct TCP_Server_Info *server,
 			  __u32 expected_sequence_number)
@@ -214,10 +173,6 @@ int cifs_verify_signature(struct smb_rqst *rqst,
 	char what_we_think_sig_should_be[20];
 	struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 
-	if (rqst->rq_iov[0].iov_len != 4 ||
-	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
-		return -EIO;
-
 	if (cifs_pdu == NULL || server == NULL)
 		return -EINVAL;
 
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index 1126feb4ba5f..2b89469187d8 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -29,8 +29,6 @@ extern void cifs_buf_release(void *);
 extern struct smb_hdr *cifs_small_buf_get(void);
 extern void cifs_small_buf_release(void *);
 extern void free_rsp_buf(int, void *);
-extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *,
-			unsigned int /* length */);
 extern int smb_send_kvec(struct TCP_Server_Info *server,
 			 struct msghdr *msg,
 			 size_t *sent);
@@ -556,9 +554,6 @@ extern void tconInfoFree(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace)
 
 extern int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
 		   __u32 *pexpected_response_sequence_number);
-extern int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
-			  __u32 *);
-extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *);
 extern int cifs_verify_signature(struct smb_rqst *rqst,
 				 struct TCP_Server_Info *server,
 				__u32 expected_sequence_number);
diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
index 879fa0ad6e44..66d8e2ad8cde 100644
--- a/fs/smb/client/cifssmb.c
+++ b/fs/smb/client/cifssmb.c
@@ -591,9 +591,11 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
 {
 	ECHO_REQ *smb;
 	int rc = 0;
-	struct kvec iov[2];
-	struct smb_rqst rqst = { .rq_iov = iov,
-				 .rq_nvec = 2 };
+	struct kvec iov[1];
+	struct smb_rqst rqst = {
+		.rq_iov = iov,
+		.rq_nvec = ARRAY_SIZE(iov),
+	};
 
 	cifs_dbg(FYI, "In echo request\n");
 
@@ -612,10 +614,8 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
 	smb->Data[0] = 'a';
 	inc_rfc1001_len(smb, 3);
 
-	iov[0].iov_len = 4;
+	iov[0].iov_len = 4 + get_rfc1002_length(smb);
 	iov[0].iov_base = smb;
-	iov[1].iov_len = get_rfc1002_length(smb);
-	iov[1].iov_base = (char *)smb + 4;
 
 	rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
 			     server, CIFS_NON_BLOCKING | CIFS_ECHO_OP, NULL);
@@ -1392,7 +1392,7 @@ cifs_async_readv(struct cifs_io_subrequest *rdata)
 	int wct;
 	struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink);
 	struct smb_rqst rqst = { .rq_iov = rdata->iov,
-				 .rq_nvec = 2 };
+				 .rq_nvec = 1 };
 
 	cifs_dbg(FYI, "%s: offset=%llu bytes=%zu\n",
 		 __func__, rdata->subreq.start, rdata->subreq.len);
@@ -1433,9 +1433,7 @@ cifs_async_readv(struct cifs_io_subrequest *rdata)
 
 	/* 4 for RFC1001 length + 1 for BCC */
 	rdata->iov[0].iov_base = smb;
-	rdata->iov[0].iov_len = 4;
-	rdata->iov[1].iov_base = (char *)smb + 4;
-	rdata->iov[1].iov_len = get_rfc1002_length(smb);
+	rdata->iov[0].iov_len = 4 + get_rfc1002_length(smb);
 
 	rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
 			     cifs_readv_callback, NULL, rdata, 0, NULL);
@@ -1764,7 +1762,7 @@ cifs_async_writev(struct cifs_io_subrequest *wdata)
 	WRITE_REQ *req = NULL;
 	int wct;
 	struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink);
-	struct kvec iov[2];
+	struct kvec iov[1];
 	struct smb_rqst rqst = { };
 
 	if (tcon->ses->capabilities & CAP_LARGE_FILES) {
@@ -1798,13 +1796,11 @@ cifs_async_writev(struct cifs_io_subrequest *wdata)
 	    cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
 
 	/* 4 for RFC1001 length + 1 for BCC */
-	iov[0].iov_len = 4;
 	iov[0].iov_base = req;
-	iov[1].iov_len = get_rfc1002_length(req) + 1;
-	iov[1].iov_base = (char *)req + 4;
+	iov[0].iov_len = 4 + get_rfc1002_length(req) + 1;
 
 	rqst.rq_iov = iov;
-	rqst.rq_nvec = 2;
+	rqst.rq_nvec = 1;
 	rqst.rq_iter = wdata->subreq.io_iter;
 
 	cifs_dbg(FYI, "async write at %llu %zu bytes\n",
@@ -1822,7 +1818,7 @@ cifs_async_writev(struct cifs_io_subrequest *wdata)
 				(struct smb_com_writex_req *)req;
 		inc_rfc1001_len(&reqw->hdr, wdata->subreq.len + 5);
 		put_bcc(wdata->subreq.len + 5, &reqw->hdr);
-		iov[1].iov_len += 4; /* pad bigger by four bytes */
+		iov[0].iov_len += 4; /* pad bigger by four bytes */
 	}
 
 	rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
diff --git a/fs/smb/client/cifstransport.c b/fs/smb/client/cifstransport.c
index f7fed73bc508..e5b75d9b9281 100644
--- a/fs/smb/client/cifstransport.c
+++ b/fs/smb/client/cifstransport.c
@@ -69,22 +69,6 @@ alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
 	return smb;
 }
 
-int
-smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
-	 unsigned int smb_buf_length)
-{
-	struct kvec iov[2];
-	struct smb_rqst rqst = { .rq_iov = iov,
-				 .rq_nvec = 2 };
-
-	iov[0].iov_base = smb_buffer;
-	iov[0].iov_len = 4;
-	iov[1].iov_base = (char *)smb_buffer + 4;
-	iov[1].iov_len = smb_buf_length;
-
-	return __smb_send_rqst(server, 1, &rqst);
-}
-
 static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
 			struct smb_message **ppmidQ)
 {
@@ -124,10 +108,6 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 	struct smb_message *smb;
 
-	if (rqst->rq_iov[0].iov_len != 4 ||
-	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
-		return ERR_PTR(-EIO);
-
 	/* enable signing if server requires it */
 	if (server->sign)
 		hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
@@ -176,21 +156,19 @@ int
 cifs_check_receive(struct smb_message *smb, struct TCP_Server_Info *server,
 		   bool log_error)
 {
-	unsigned int len = get_rfc1002_length(smb->resp_buf) + 4;
+	unsigned int len = get_rfc1002_length(smb->resp_buf);
 
 	dump_smb(smb->resp_buf, min_t(u32, 92, len));
 
 	/* convert the length into a more usable form */
 	if (server->sign) {
-		struct kvec iov[2];
+		struct kvec iov[1];
 		int rc = 0;
 		struct smb_rqst rqst = { .rq_iov = iov,
-					 .rq_nvec = 2 };
+					 .rq_nvec = 1 };
 
 		iov[0].iov_base = smb->resp_buf;
-		iov[0].iov_len = 4;
-		iov[1].iov_base = (char *)smb->resp_buf + 4;
-		iov[1].iov_len = len - 4;
+		iov[0].iov_len = len;
 		/* FIXME: add code to kill session */
 		rc = cifs_verify_signature(&rqst, server,
 					   smb->sequence_number);
@@ -211,10 +189,6 @@ cifs_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *ignored,
 	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 	struct smb_message *smb;
 
-	if (rqst->rq_iov[0].iov_len != 4 ||
-	    rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
-		return ERR_PTR(-EIO);
-
 	rc = allocate_mid(ses, hdr, &smb);
 	if (rc)
 		return ERR_PTR(rc);
@@ -231,38 +205,13 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 	     struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
 	     const int flags, struct kvec *resp_iov)
 {
-	struct smb_rqst rqst;
-	struct kvec s_iov[CIFS_MAX_IOV_SIZE], *new_iov;
-	int rc;
+	struct smb_rqst rqst = {
+		.rq_iov  = iov,
+		.rq_nvec = n_vec,
+	};
 
-	if (n_vec + 1 > CIFS_MAX_IOV_SIZE) {
-		new_iov = kmalloc_array(n_vec + 1, sizeof(struct kvec),
-					GFP_KERNEL);
-		if (!new_iov) {
-			/* otherwise cifs_send_recv below sets resp_buf_type */
-			*resp_buf_type = CIFS_NO_BUFFER;
-			return -ENOMEM;
-		}
-	} else
-		new_iov = s_iov;
-
-	/* 1st iov is a RFC1001 length followed by the rest of the packet */
-	memcpy(new_iov + 1, iov, (sizeof(struct kvec) * n_vec));
-
-	new_iov[0].iov_base = new_iov[1].iov_base;
-	new_iov[0].iov_len = 4;
-	new_iov[1].iov_base += 4;
-	new_iov[1].iov_len -= 4;
-
-	memset(&rqst, 0, sizeof(struct smb_rqst));
-	rqst.rq_iov = new_iov;
-	rqst.rq_nvec = n_vec + 1;
-
-	rc = cifs_send_recv(xid, ses, ses->server,
-			    &rqst, resp_buf_type, flags, resp_iov);
-	if (n_vec + 1 > CIFS_MAX_IOV_SIZE)
-		kfree(new_iov);
-	return rc;
+	return cifs_send_recv(xid, ses, ses->server,
+			      &rqst, resp_buf_type, flags, resp_iov);
 }
 
 int
@@ -273,7 +222,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 	unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
 	struct TCP_Server_Info *server;
 	struct kvec resp_iov = {};
-	struct kvec iov = { .iov_base = in_buf, .iov_len = len };
+	struct kvec iov = { .iov_base = in_buf, .iov_len = len + 4 };
 	struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
 	int resp_buf_type;
 	int rc = 0;
@@ -309,7 +258,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 			    &rqst, &resp_buf_type, flags, &resp_iov);
 	if (rc < 0)
 		return rc;
-	
+
 	*pbytes_returned = resp_iov.iov_len;
 	if (resp_iov.iov_len)
 		memcpy(out_buf, resp_iov.iov_base, resp_iov.iov_len);
@@ -352,7 +301,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 	struct smb_message *smb;
 	struct cifs_ses *ses;
 	unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
-	struct kvec iov = { .iov_base = in_buf, .iov_len = len };
+	struct kvec iov = { .iov_base = in_buf, .iov_len = len + 4 };
 	struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
 	unsigned int instance;
 	struct TCP_Server_Info *server;
@@ -402,7 +351,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 		return rc;
 	}
 
-	rc = cifs_sign_smb(in_buf, server, &smb->sequence_number);
+	rc = cifs_sign_rqst(&rqst, server, &smb->sequence_number);
 	if (rc) {
 		delete_mid(smb);
 		cifs_server_unlock(server);
@@ -410,7 +359,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 	}
 
 	smb->mid_state = MID_REQUEST_SUBMITTED;
-	rc = smb_send(server, in_buf, len);
+	rc = __smb_send_rqst(server, 1, &rqst);
 	cifs_save_when_sent(smb);
 
 	if (rc < 0)
diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
index dc2daba936e2..401450eadf2c 100644
--- a/fs/smb/client/smb1ops.c
+++ b/fs/smb/client/smb1ops.c
@@ -31,8 +31,10 @@ static int
 send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 	       struct smb_message *smb)
 {
-	int rc = 0;
 	struct smb_hdr *in_buf = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
+	struct kvec iov[1];
+	struct smb_rqst crqst = { .rq_iov = iov, .rq_nvec = 1 };
+	int rc = 0;
 
 	/* -4 for RFC1001 length and +2 for BCC field */
 	in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4  + 2);
@@ -40,8 +42,11 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 	in_buf->WordCount = 0;
 	put_bcc(0, in_buf);
 
+	iov[0].iov_base = in_buf;
+	iov[0].iov_len  = sizeof(struct smb_hdr) + 2;
+
 	cifs_server_lock(server);
-	rc = cifs_sign_smb(in_buf, server, &smb->sequence_number);
+	rc = cifs_sign_rqst(&crqst, server, &smb->sequence_number);
 	if (rc) {
 		cifs_server_unlock(server);
 		return rc;
@@ -53,7 +58,7 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 	 * after signing here.
 	 */
 	--server->sequence_number;
-	rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
+	rc = __smb_send_rqst(server, 1, &crqst);
 	if (rc < 0)
 		server->sequence_number--;
 
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index d55b24d1aa77..db9ce9e84406 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -1036,23 +1036,24 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 			goto out;
 		}
 
-		buf = (char *)smb[i]->resp_buf;
-		resp_iov[i].iov_base = buf;
-		resp_iov[i].iov_len = smb[i]->resp_buf_size +
-			HEADER_PREAMBLE_SIZE(server);
-
-		if (smb[i]->large_buf)
-			resp_buf_type[i] = CIFS_LARGE_BUFFER;
-		else
-			resp_buf_type[i] = CIFS_SMALL_BUFFER;
-
 		rc = server->ops->check_receive(smb[i], server,
 						     flags & CIFS_LOG_ERROR);
 
-		/* mark it so buf will not be freed by delete_mid */
-		if ((flags & CIFS_NO_RSP_BUF) == 0)
-			smb[i]->resp_buf = NULL;
+		if (resp_iov) {
+			buf = (char *)smb[i]->resp_buf;
+			resp_iov[i].iov_base = buf;
+			resp_iov[i].iov_len = smb[i]->resp_buf_size +
+				HEADER_PREAMBLE_SIZE(server);
 
+			if (smb[i]->large_buf)
+				resp_buf_type[i] = CIFS_LARGE_BUFFER;
+			else
+				resp_buf_type[i] = CIFS_SMALL_BUFFER;
+
+			/* mark it so buf will not be freed by delete_mid */
+			if ((flags & CIFS_NO_RSP_BUF) == 0)
+				smb[i]->resp_buf = NULL;
+		}
 	}
 
 	/*


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 12/31] cifs: Replace SendReceiveBlockingLock() with SendReceive() plus flags
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (10 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 11/31] cifs: Fix SMB1 to not require separate kvec for the rfc1002 header David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 13/31] cifs: Institute message managing struct David Howells
                   ` (22 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Replace the smb1 transport's SendReceiveBlockingLock() with SendReceive()
plus a couple of flags.  This will then allow that to pick up the transport
changes there.

The first flag, CIFS_INTERRUPTIBLE_WAIT, is added to indicate that the wait
should be interruptible and the second, CIFS_WINDOWS_LOCK, indicates that
we need to send a Lock command with unlock type rather than a Cancel.

send_lock_cancel() is then called from cifs_lock_cancel() which is called from
the main transport loop in compound_send_recv().

[!] I *think* the error code handling is probably right.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/cifsglob.h      |   8 +-
 fs/smb/client/cifsproto.h     |  12 +-
 fs/smb/client/cifssmb.c       |  18 +--
 fs/smb/client/cifstransport.c | 210 +---------------------------------
 fs/smb/client/smb1ops.c       |  45 +++++++-
 fs/smb/client/transport.c     |  10 +-
 6 files changed, 75 insertions(+), 228 deletions(-)

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 60350213a02b..091d92ed670a 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -312,8 +312,9 @@ struct cifs_open_parms;
 struct cifs_credits;
 
 struct smb_version_operations {
-	int (*send_cancel)(struct TCP_Server_Info *, struct smb_rqst *,
-			   struct smb_message *smb);
+	int (*send_cancel)(struct cifs_ses *ses, struct TCP_Server_Info *server,
+			   struct smb_rqst *rqst, struct smb_message *smb,
+			   unsigned int xid);
 	bool (*compare_fids)(struct cifsFileInfo *, struct cifsFileInfo *);
 	/* setup request: allocate mid, sign message */
 	struct smb_message *(*setup_request)(struct cifs_ses *,
@@ -1713,6 +1714,7 @@ struct smb_message {
 	__u16 credits_received;	/* number of credits from the response */
 	__u32 pid;		/* process id */
 	__u32 sequence_number;  /* for CIFS signing */
+	unsigned int sr_flags;	/* Flags passed to send_recv() */
 	unsigned long when_alloc;  /* when mid was created */
 #ifdef CONFIG_CIFS_STATS2
 	unsigned long when_sent; /* time when smb send finished */
@@ -1922,6 +1924,8 @@ static inline bool is_replayable_error(int error)
 #define   CIFS_TRANSFORM_REQ      0x0800 /* transform request before sending */
 #define   CIFS_NO_SRV_RSP         0x1000 /* there is no server response */
 #define   CIFS_COMPRESS_REQ       0x4000 /* compress request before sending */
+#define   CIFS_INTERRUPTIBLE_WAIT 0x8000 /* Interruptible wait (e.g. lock request) */
+#define   CIFS_WINDOWS_LOCK       0x10000 /* We're trying to get a Windows lock */
 
 /* Security Flags: indicate type of session setup needed */
 #define   CIFSSEC_MAY_SIGN	0x00001
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index 2b89469187d8..3249fe473aa1 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -131,11 +131,12 @@ extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server,
 				 struct cifs_credits *credits);
 
 static inline int
-send_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
-	    struct smb_message *smb)
+send_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
+	    struct smb_rqst *rqst, struct smb_message *smb,
+	    unsigned int xid)
 {
 	return server->ops->send_cancel ?
-				server->ops->send_cancel(server, rqst, smb) : 0;
+		server->ops->send_cancel(ses, server, rqst, smb, xid) : 0;
 }
 
 int wait_for_response(struct TCP_Server_Info *server, struct smb_message *smb);
@@ -143,11 +144,6 @@ extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
 			struct kvec *, int /* nvec to send */,
 			int * /* type of buf returned */, const int flags,
 			struct kvec * /* resp vec */);
-extern int SendReceiveBlockingLock(const unsigned int xid,
-			struct cifs_tcon *ptcon,
-			struct smb_hdr *in_buf,
-			struct smb_hdr *out_buf,
-			int *bytes_returned);
 
 void smb2_query_server_interfaces(struct work_struct *work);
 void
diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
index 66d8e2ad8cde..a7a9f63f8c21 100644
--- a/fs/smb/client/cifssmb.c
+++ b/fs/smb/client/cifssmb.c
@@ -1997,7 +1997,7 @@ CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
 	LOCK_REQ *pSMB = NULL;
 /*	LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
 	int bytes_returned;
-	int flags = 0;
+	int flags = CIFS_WINDOWS_LOCK | CIFS_INTERRUPTIBLE_WAIT;
 	__u16 count;
 
 	cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
@@ -2041,8 +2041,9 @@ CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
 	pSMB->ByteCount = cpu_to_le16(count);
 
 	if (waitFlag)
-		rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
-			(struct smb_hdr *) pSMB, &bytes_returned);
+		rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+				 (struct smb_hdr *) pSMB, &bytes_returned,
+				 flags);
 	else
 		rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
 	cifs_small_buf_release(pSMB);
@@ -2066,7 +2067,7 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
 	struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
 	struct cifs_posix_lock *parm_data;
 	int rc = 0;
-	int timeout = 0;
+	int sr_flags = CIFS_INTERRUPTIBLE_WAIT;
 	int bytes_returned = 0;
 	int resp_buf_type = 0;
 	__u16 params, param_offset, offset, byte_count, count;
@@ -2111,7 +2112,7 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
 
 	parm_data->lock_type = cpu_to_le16(lock_type);
 	if (waitFlag) {
-		timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
+		sr_flags |= CIFS_BLOCKING_OP; /* blocking operation, no timeout */
 		parm_data->lock_flags = cpu_to_le16(1);
 		pSMB->Timeout = cpu_to_le32(-1);
 	} else
@@ -2128,13 +2129,14 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
 	inc_rfc1001_len(pSMB, byte_count);
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	if (waitFlag) {
-		rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
-			(struct smb_hdr *) pSMBr, &bytes_returned);
+		rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+				 (struct smb_hdr *) pSMBr, &bytes_returned,
+				 sr_flags);
 	} else {
 		iov[0].iov_base = (char *)pSMB;
 		iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
 		rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
-				&resp_buf_type, timeout, &rsp_iov);
+				&resp_buf_type, sr_flags, &rsp_iov);
 		pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
 	}
 	cifs_small_buf_release(pSMB);
diff --git a/fs/smb/client/cifstransport.c b/fs/smb/client/cifstransport.c
index e5b75d9b9281..b5f652ad9e59 100644
--- a/fs/smb/client/cifstransport.c
+++ b/fs/smb/client/cifstransport.c
@@ -227,23 +227,6 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 	int resp_buf_type;
 	int rc = 0;
 
-	if (ses == NULL) {
-		cifs_dbg(VFS, "Null smb session\n");
-		return -EIO;
-	}
-	server = ses->server;
-	if (server == NULL) {
-		cifs_dbg(VFS, "Null tcp session\n");
-		return -EIO;
-	}
-
-	spin_lock(&server->srv_lock);
-	if (server->tcpStatus == CifsExiting) {
-		spin_unlock(&server->srv_lock);
-		return -ENOENT;
-	}
-	spin_unlock(&server->srv_lock);
-
 	/* Ensure that we do not send more than 50 overlapping requests
 	   to the same server. We may make this configurable later or
 	   use ses->maxReq */
@@ -259,194 +242,11 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 	if (rc < 0)
 		return rc;
 
-	*pbytes_returned = resp_iov.iov_len;
-	if (resp_iov.iov_len)
-		memcpy(out_buf, resp_iov.iov_base, resp_iov.iov_len);
-	free_rsp_buf(resp_buf_type, resp_iov.iov_base);
-	return rc;
-}
-
-/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
-   blocking lock to return. */
-
-static int
-send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon,
-			struct smb_hdr *in_buf,
-			struct smb_hdr *out_buf)
-{
-	int bytes_returned;
-	struct cifs_ses *ses = tcon->ses;
-	LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
-
-	/* We just modify the current in_buf to change
-	   the type of lock from LOCKING_ANDX_SHARED_LOCK
-	   or LOCKING_ANDX_EXCLUSIVE_LOCK to
-	   LOCKING_ANDX_CANCEL_LOCK. */
-
-	pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
-	pSMB->Timeout = 0;
-	pSMB->hdr.Mid = get_next_mid(ses->server);
-
-	return SendReceive(xid, ses, in_buf, out_buf,
-			&bytes_returned, 0);
-}
-
-int
-SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
-	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
-	    int *pbytes_returned)
-{
-	int rc = 0;
-	int rstart = 0;
-	struct smb_message *smb;
-	struct cifs_ses *ses;
-	unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
-	struct kvec iov = { .iov_base = in_buf, .iov_len = len + 4 };
-	struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
-	unsigned int instance;
-	struct TCP_Server_Info *server;
-
-	if (tcon == NULL || tcon->ses == NULL) {
-		cifs_dbg(VFS, "Null smb session\n");
-		return -EIO;
-	}
-	ses = tcon->ses;
-	server = ses->server;
-
-	if (server == NULL) {
-		cifs_dbg(VFS, "Null tcp session\n");
-		return -EIO;
-	}
-
-	spin_lock(&server->srv_lock);
-	if (server->tcpStatus == CifsExiting) {
-		spin_unlock(&server->srv_lock);
-		return -ENOENT;
-	}
-	spin_unlock(&server->srv_lock);
-
-	/* Ensure that we do not send more than 50 overlapping requests
-	   to the same server. We may make this configurable later or
-	   use ses->maxReq */
-
-	if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
-		cifs_tcon_dbg(VFS, "Invalid length, greater than maximum frame, %d\n",
-			      len);
-		return -EIO;
-	}
-
-	rc = wait_for_free_request(server, CIFS_BLOCKING_OP, &instance);
-	if (rc)
-		return rc;
-
-	/* make sure that we sign in the same order that we send on this socket
-	   and avoid races inside tcp sendmsg code that could cause corruption
-	   of smb data */
-
-	cifs_server_lock(server);
-
-	rc = allocate_mid(ses, in_buf, &smb);
-	if (rc) {
-		cifs_server_unlock(server);
-		return rc;
-	}
-
-	rc = cifs_sign_rqst(&rqst, server, &smb->sequence_number);
-	if (rc) {
-		delete_mid(smb);
-		cifs_server_unlock(server);
-		return rc;
-	}
-
-	smb->mid_state = MID_REQUEST_SUBMITTED;
-	rc = __smb_send_rqst(server, 1, &rqst);
-	cifs_save_when_sent(smb);
-
-	if (rc < 0)
-		server->sequence_number -= 2;
-
-	cifs_server_unlock(server);
-
-	if (rc < 0) {
-		delete_mid(smb);
-		return rc;
-	}
-
-	/* Wait for a reply - allow signals to interrupt. */
-	rc = wait_event_interruptible(server->response_q,
-		(!(smb->mid_state == MID_REQUEST_SUBMITTED ||
-		   smb->mid_state == MID_RESPONSE_RECEIVED)) ||
-		((server->tcpStatus != CifsGood) &&
-		 (server->tcpStatus != CifsNew)));
-
-	/* Were we interrupted by a signal ? */
-	spin_lock(&server->srv_lock);
-	if ((rc == -ERESTARTSYS) &&
-		(smb->mid_state == MID_REQUEST_SUBMITTED ||
-		 smb->mid_state == MID_RESPONSE_RECEIVED) &&
-		((server->tcpStatus == CifsGood) ||
-		 (server->tcpStatus == CifsNew))) {
-		spin_unlock(&server->srv_lock);
-
-		if (in_buf->Command == SMB_COM_TRANSACTION2) {
-			/* POSIX lock. We send a NT_CANCEL SMB to cause the
-			   blocking lock to return. */
-			rc = send_cancel(server, &rqst, smb);
-			if (rc) {
-				delete_mid(smb);
-				return rc;
-			}
-		} else {
-			/* Windows lock. We send a LOCKINGX_CANCEL_LOCK
-			   to cause the blocking lock to return. */
-
-			rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
-
-			/* If we get -ENOLCK back the lock may have
-			   already been removed. Don't exit in this case. */
-			if (rc && rc != -ENOLCK) {
-				delete_mid(smb);
-				return rc;
-			}
-		}
-
-		rc = wait_for_response(server, smb);
-		if (rc) {
-			send_cancel(server, &rqst, smb);
-			spin_lock(&server->mid_lock);
-			if (smb->mid_state == MID_REQUEST_SUBMITTED ||
-			    smb->mid_state == MID_RESPONSE_RECEIVED) {
-				/* no longer considered to be "in-flight" */
-				smb->callback = release_mid;
-				spin_unlock(&server->mid_lock);
-				return rc;
-			}
-			spin_unlock(&server->mid_lock);
-		}
-
-		/* We got the response - restart system call. */
-		rstart = 1;
-		spin_lock(&server->srv_lock);
+	if (out_buf) {
+		*pbytes_returned = resp_iov.iov_len;
+		if (resp_iov.iov_len)
+			memcpy(out_buf, resp_iov.iov_base, resp_iov.iov_len);
 	}
-	spin_unlock(&server->srv_lock);
-
-	rc = cifs_sync_mid_result(smb, server);
-	if (rc != 0)
-		return rc;
-
-	/* rcvd frame is ok */
-	if (out_buf == NULL || smb->mid_state != MID_RESPONSE_READY) {
-		rc = -EIO;
-		cifs_tcon_dbg(VFS, "Bad MID state?\n");
-		goto out;
-	}
-
-	*pbytes_returned = get_rfc1002_length(smb->resp_buf);
-	memcpy(out_buf, smb->resp_buf, *pbytes_returned + 4);
-	rc = cifs_check_receive(smb, server, 0);
-out:
-	delete_mid(smb);
-	if (rstart && rc == -EACCES)
-		return -ERESTARTSYS;
+	free_rsp_buf(resp_buf_type, resp_iov.iov_base);
 	return rc;
 }
diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
index 401450eadf2c..d2094b8872ac 100644
--- a/fs/smb/client/smb1ops.c
+++ b/fs/smb/client/smb1ops.c
@@ -28,8 +28,9 @@
  * SMB_COM_NT_CANCEL request and then sends it.
  */
 static int
-send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
-	       struct smb_message *smb)
+send_nt_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
+	       struct smb_rqst *rqst, struct smb_message *smb,
+	       unsigned int xid)
 {
 	struct smb_hdr *in_buf = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 	struct kvec iov[1];
@@ -70,6 +71,44 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 	return rc;
 }
 
+/*
+ * Send a LOCKINGX_CANCEL_LOCK to cause the Windows blocking lock to
+ * return.
+ */
+static int
+send_lock_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
+		 struct smb_rqst *rqst, struct smb_message *smb,
+		 unsigned int xid)
+{
+	struct smb_hdr *in_buf = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
+	LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
+	int rc;
+
+	/* We just modify the current in_buf to change
+	 * the type of lock from LOCKING_ANDX_SHARED_LOCK
+	 * or LOCKING_ANDX_EXCLUSIVE_LOCK to
+	 * LOCKING_ANDX_CANCEL_LOCK. */
+
+	pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
+	pSMB->Timeout = 0;
+	pSMB->hdr.Mid = get_next_mid(ses->server);
+
+	rc = SendReceive(xid, ses, in_buf, NULL, NULL, 0);
+	if (rc == -ENOLCK)
+		rc = 0; /* If we get back -ENOLCK, it probably means we managed
+			 * to cancel the lock command before it took effect. */
+	return rc;
+}
+
+static int cifs_send_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
+			    struct smb_rqst *rqst, struct smb_message *smb,
+			    unsigned int xid)
+{
+	if (smb->sr_flags & CIFS_WINDOWS_LOCK)
+		return send_lock_cancel(ses, server, rqst, smb, xid);
+	return send_nt_cancel(ses, server, rqst, smb, xid);
+}
+
 static bool
 cifs_compare_fids(struct cifsFileInfo *ob1, struct cifsFileInfo *ob2)
 {
@@ -1324,7 +1363,7 @@ cifs_is_network_name_deleted(char *buf, struct TCP_Server_Info *server)
 }
 
 struct smb_version_operations smb1_operations = {
-	.send_cancel = send_nt_cancel,
+	.send_cancel = cifs_send_cancel,
 	.compare_fids = cifs_compare_fids,
 	.setup_request = cifs_setup_request,
 	.setup_async_request = cifs_setup_async_request,
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index db9ce9e84406..9282a3276318 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -636,12 +636,16 @@ cifs_wait_mtu_credits(struct TCP_Server_Info *server, size_t size,
 
 int wait_for_response(struct TCP_Server_Info *server, struct smb_message *smb)
 {
+	unsigned int sleep_state = TASK_KILLABLE;
 	int error;
 
+	if (smb->sr_flags & CIFS_INTERRUPTIBLE_WAIT)
+		sleep_state = TASK_INTERRUPTIBLE;
+
 	error = wait_event_state(server->response_q,
 				 smb->mid_state != MID_REQUEST_SUBMITTED &&
 				 smb->mid_state != MID_RESPONSE_RECEIVED,
-				 (TASK_KILLABLE|TASK_FREEZABLE_UNSAFE));
+				 (sleep_state | TASK_FREEZABLE_UNSAFE));
 	if (error < 0)
 		return -ERESTARTSYS;
 
@@ -695,6 +699,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 		return PTR_ERR(smb);
 	}
 
+	smb->sr_flags = flags;
 	smb->receive = receive;
 	smb->callback = callback;
 	smb->callback_data = cbdata;
@@ -939,6 +944,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 			return PTR_ERR(smb[i]);
 		}
 
+		smb[i]->sr_flags = flags;
 		smb[i]->mid_state = MID_REQUEST_SUBMITTED;
 		smb[i]->optype = optype;
 		/*
@@ -1005,7 +1011,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 		for (; i < num_rqst; i++) {
 			cifs_server_dbg(FYI, "Cancelling wait for mid %llu cmd: %d\n",
 				 smb[i]->mid, smb[i]->command_id);
-			send_cancel(server, &rqst[i], smb[i]);
+			send_cancel(ses, server, &rqst[i], smb[i], xid);
 			spin_lock(&server->mid_lock);
 			smb[i]->mid_flags |= MID_WAIT_CANCELLED;
 			if (smb[i]->mid_state == MID_REQUEST_SUBMITTED ||


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 13/31] cifs: Institute message managing struct
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (11 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 12/31] cifs: Replace SendReceiveBlockingLock() with SendReceive() plus flags David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 14/31] cifs: Split crypt_message() into encrypt and decrypt variants David Howells
                   ` (21 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Turn the smb_message struct into a message handling struct to aid in
building an SMB message, queuing them and holding the resources and
buffers.  It has absorbed the mid_q_struct and now other fields are added.

The idea is that the smb_message struct will be allocated and filled in
much higher up (typically in the PDU encoding code) and passed down to the
transport.

In particular, the following fields:

 (*) ->next: This is used to link together messages into compounds and then
     walk through the message list.

 (*) ->credits: The credit requirements for the message.

 (*) ->request: Pointer to the smb_hdr struct for the request.

 (*) ->command_id: The ID of the command in CPU endian form (better for
     if- and switch-statements).

 (*) ->total_len: The total length of the request message, not including
     rfc1002 or transform headers.

 (*) ->response: Pointer to the smb_hdr struct for the response.

 (*) ->rqst, ->resp_buf_type, ->resp_iov: The old request info stuff.

Functions are provided to get and put refs upon the struct and also to drop
all the refs on a compound string of structs.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/cifsglob.h      | 101 ++++++++++++++++++++++++----------
 fs/smb/client/cifsproto.h     |  10 +++-
 fs/smb/client/cifstransport.c |   2 +-
 fs/smb/client/connect.c       |   6 +-
 fs/smb/client/smb1ops.c       |   2 +-
 fs/smb/client/smb2ops.c       |   2 +-
 fs/smb/client/smb2transport.c |   4 +-
 fs/smb/client/transport.c     |  46 ++++++++++++++--
 8 files changed, 130 insertions(+), 43 deletions(-)

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 091d92ed670a..90dafae1e9ab 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -1704,38 +1704,81 @@ typedef void (*mid_callback_t)(struct smb_message *smb);
 typedef int (*mid_handle_t)(struct TCP_Server_Info *server,
 			    struct smb_message *smb);
 
-/* one of these for every pending CIFS request to the server */
+/*
+ * Definition of an SMB request message to be transmitted.  These may be
+ * chained together and will automatically be turned into compound messages if
+ * they are.
+ *
+ *	+-----------------------+
+ *	| NetBIOS/padding	|
+ *	+-----------------------+ <--- smb->request + pre_offset
+ *	| (Transform header)	|
+ *	+-----------------------+ <--- smb->request
+ *	| SMB2 Header		| }				 }
+ *	+-----------------------+ } header_size			 }
+ *	| Req/Rsp struct	| }				 }
+ *	+-----------------------+ <--- smb->request + ext_offset } protocol_size
+ *	|			|				 }
+ *	| Extra protocol data	|				 }
+ *	|			|				 }
+ *	+-----------------------+ <--- smb->request + smb->data_offset
+ *	|			|
+ *	| Data Payload		|  data_size
+ *	|			|
+ *	+-----------------------+
+ *
+ *
+ * If the data is to be RDMA'd, it will be kept separate from the protocol.
+ */
 struct smb_message {
-	struct list_head qhead;	/* mids waiting on reply from this server */
-	struct kref refcount;
-	struct TCP_Server_Info *server;	/* server corresponding to this mid */
-	__u64 mid;		/* multiplex id */
-	__u16 credits;		/* number of credits consumed by this mid */
-	__u16 credits_received;	/* number of credits from the response */
-	__u32 pid;		/* process id */
-	__u32 sequence_number;  /* for CIFS signing */
-	unsigned int sr_flags;	/* Flags passed to send_recv() */
-	unsigned long when_alloc;  /* when mid was created */
+	struct smb_message	*next;		/* Next message in compound */
+	struct cifs_credits	credits;	/* Credit requirements for this message */
+	void			*request;	/* Pointer to request message body */
+	refcount_t		ref;
+	bool			sensitive;	/* Request contains sensitive data */
+	bool			cancelled;	/* T if cancelled */
+	unsigned int		sr_flags;	/* Flags passed to send_recv() */
+
+	/* Queue state */
+	struct list_head	qhead;		/* mids waiting on reply from this server */
+	struct TCP_Server_Info	*server;	/* server corresponding to this mid */
+	__u64			mid;		/* multiplex id */
+	__u16			credits_consumed; /* number of credits consumed by this op */
+	__u16			credits_received; /* number of credits from the response */
+	__u32			pid;		/* process id */
+	__u32			sequence_number;  /* for CIFS signing */
+	unsigned long		when_alloc;	/* when mid was created */
 #ifdef CONFIG_CIFS_STATS2
-	unsigned long when_sent; /* time when smb send finished */
-	unsigned long when_received; /* when demux complete (taken off wire) */
+	unsigned long		when_sent;	/* time when smb send finished */
+	unsigned long		when_received;	/* when demux complete (taken off wire) */
 #endif
-	mid_receive_t receive; /* call receive callback */
-	mid_callback_t callback; /* call completion callback */
-	mid_handle_t handle; /* call handle mid callback */
-	void *callback_data;	  /* general purpose pointer for callback */
-	struct task_struct *creator;
-	void *resp_buf;		/* pointer to received SMB header */
-	unsigned int resp_buf_size;
-	int mid_state;	/* wish this were enum but can not pass to wait_event */
-	int mid_rc;		/* rc for MID_RC */
-	unsigned int mid_flags;
-	unsigned int optype;	/* operation type */
-	enum smb2_command command_id;	/* smb command code */
-	bool large_buf:1;	/* if valid response, is pointer to large buf */
-	bool multiRsp:1;	/* multiple trans2 responses for one request  */
-	bool multiEnd:1;	/* both received */
-	bool decrypted:1;	/* decrypted entry */
+	mid_receive_t		receive;	/* call receive callback */
+	mid_callback_t		callback;	/* call completion callback */
+	mid_handle_t		handle;		/* call handle mid callback */
+	void			*callback_data;	/* general purpose pointer for callback */
+	struct task_struct	*creator;
+	void			*resp_buf;	/* pointer to received SMB header */
+	unsigned int		resp_buf_size;
+	int			mid_state;	/* wish this were enum but can not pass to wait_event */
+	int			mid_rc;		/* rc for MID_RC */
+	unsigned int		mid_flags;
+	unsigned int		optype;		/* operation type */
+	bool			large_buf:1;	/* if valid response, is pointer to large buf */
+	bool			multiRsp:1;	/* multiple trans2 responses for one request  */
+	bool			multiEnd:1;	/* both received */
+	bool			decrypted:1;	/* decrypted entry */
+
+	/* Request details */
+	enum smb2_command	command_id;	/* Command ID */
+	s16			pre_offset;	/* Offset of pre-headers from ->body (negative) */
+	unsigned int		total_len;	/* Total length of from hdr_offset onwards */
+	/* Response */
+	void			*response;	/* Protocol part of response */
+	u32			response_len;	/* Size of response */
+	/* Compat with old code */
+	struct smb_rqst		rqst;
+	int			*resp_buf_type;
+	struct kvec		*resp_iov;
 };
 
 struct close_cancelled_open {
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index 3249fe473aa1..6f27fb6ef5dc 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -82,7 +82,7 @@ extern char *cifs_build_path_to_root(struct smb3_fs_context *ctx,
 extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
 char *cifs_build_devname(char *nodename, const char *prepath);
 extern void delete_mid(struct smb_message *smb);
-void __release_mid(struct kref *refcount);
+void __release_mid(struct smb_message *smb);
 extern void cifs_wake_up_task(struct smb_message *smb);
 extern int cifs_handle_standard(struct TCP_Server_Info *server,
 				struct smb_message *smb);
@@ -755,7 +755,8 @@ static inline bool dfs_src_pathname_equal(const char *s1, const char *s2)
 
 static inline void release_mid(struct smb_message *smb)
 {
-	kref_put(&smb->refcount, __release_mid);
+	if (refcount_dec_and_test(&smb->ref))
+		__release_mid(smb);
 }
 
 static inline void cifs_free_open_info(struct cifs_open_info_data *data)
@@ -765,4 +766,9 @@ static inline void cifs_free_open_info(struct cifs_open_info_data *data)
 	memset(data, 0, sizeof(*data));
 }
 
+struct smb_message *smb_message_alloc(enum smb2_command cmd, gfp_t gfp);
+void smb_get_message(struct smb_message *smb);
+void smb_put_message(struct smb_message *smb);
+void smb_put_messages(struct smb_message *smb);
+
 #endif			/* _CIFSPROTO_H */
diff --git a/fs/smb/client/cifstransport.c b/fs/smb/client/cifstransport.c
index b5f652ad9e59..a2db95faeb17 100644
--- a/fs/smb/client/cifstransport.c
+++ b/fs/smb/client/cifstransport.c
@@ -45,7 +45,7 @@ alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
 
 	smb = mempool_alloc(&smb_message_pool, GFP_NOFS);
 	memset(smb, 0, sizeof(struct smb_message));
-	kref_init(&smb->refcount);
+	refcount_set(&smb->ref, 1);
 	smb->mid = get_mid(smb_buffer);
 	smb->pid = current->pid;
 	smb->command_id = le16_to_cpu(smb_buffer->Command);
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index 9abaca4c8eba..d26e2a6d7674 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -323,7 +323,7 @@ cifs_abort_connection(struct TCP_Server_Info *server)
 	cifs_dbg(FYI, "%s: moving mids to private list\n", __func__);
 	spin_lock(&server->mid_lock);
 	list_for_each_entry_safe(smb, nsmb, &server->pending_mid_q, qhead) {
-		kref_get(&smb->refcount);
+		smb_get_message(smb);
 		if (smb->mid_state == MID_REQUEST_SUBMITTED)
 			smb->mid_state = MID_RETRY_NEEDED;
 		list_move(&smb->qhead, &retry_list);
@@ -886,7 +886,7 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
 			 */
 			spin_lock(&server->mid_lock);
 			list_for_each_entry_safe(smb, nsmb, &server->pending_mid_q, qhead) {
-				kref_get(&smb->refcount);
+				smb_get_message(smb);
 				list_move(&smb->qhead, &dispose_list);
 				smb->mid_flags |= MID_DELETED;
 			}
@@ -1105,7 +1105,7 @@ clean_demultiplex_info(struct TCP_Server_Info *server)
 		list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
 			smb = list_entry(tmp, struct smb_message, qhead);
 			cifs_dbg(FYI, "Clearing mid %llu\n", smb->mid);
-			kref_get(&smb->refcount);
+			smb_get_message(smb);
 			smb->mid_state = MID_SHUTDOWN;
 			list_move(&smb->qhead, &dispose_list);
 			smb->mid_flags |= MID_DELETED;
diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
index d2094b8872ac..cc5b3c531c77 100644
--- a/fs/smb/client/smb1ops.c
+++ b/fs/smb/client/smb1ops.c
@@ -144,7 +144,7 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buffer)
 		if (compare_mid(smb->mid, buf) &&
 		    smb->mid_state == MID_REQUEST_SUBMITTED &&
 		    smb->command_id == command) {
-			kref_get(&smb->refcount);
+			smb_get_message(smb);
 			spin_unlock(&server->mid_lock);
 			return smb;
 		}
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 36c506577b0e..7b714e50f681 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -407,7 +407,7 @@ __smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue)
 		if ((smb->mid == wire_mid) &&
 		    (smb->mid_state == MID_REQUEST_SUBMITTED) &&
 		    (smb->command_id == command)) {
-			kref_get(&smb->refcount);
+			smb_get_message(smb);
 			if (dequeue) {
 				list_del_init(&smb->qhead);
 				smb->mid_flags |= MID_DELETED;
diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index fcf0999e77aa..b217bc0e8e5b 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -770,9 +770,9 @@ smb2_mid_entry_alloc(const struct smb2_hdr *shdr,
 
 	smb = mempool_alloc(&smb_message_pool, GFP_NOFS);
 	memset(smb, 0, sizeof(*smb));
-	kref_init(&smb->refcount);
+	refcount_set(&smb->ref, 1);
 	smb->mid = le64_to_cpu(shdr->MessageId);
-	smb->credits = credits > 0 ? credits : 1;
+	smb->credits_consumed = credits > 0 ? credits : 1;
 	smb->pid = current->pid;
 	smb->command_id = le16_to_cpu(shdr->Command);
 	smb->when_alloc = jiffies;
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index 9282a3276318..288351c27fc4 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -30,6 +30,46 @@
 #include "smbdirect.h"
 #include "compress.h"
 
+struct smb_message *smb_message_alloc(enum smb2_command cmd, gfp_t gfp)
+{
+	struct smb_message *smb;
+
+	smb = mempool_alloc(&smb_message_pool, gfp);
+	if (smb) {
+		memset(smb, 0, sizeof(*smb));
+		refcount_set(&smb->ref, 1);
+		smb->command_id = cmd;
+	}
+	return smb;
+}
+
+void smb_get_message(struct smb_message *smb)
+{
+	refcount_inc(&smb->ref);
+}
+
+/*
+ * Drop a ref on a message.  This does not touch the chained messages.
+ */
+void smb_put_message(struct smb_message *smb)
+{
+	if (refcount_dec_and_test(&smb->ref))
+		mempool_free(smb, &smb_message_pool);
+}
+
+/*
+ * Dispose of a chain of compound messages.
+ */
+void smb_put_messages(struct smb_message *smb)
+{
+	struct smb_message *next;
+
+	for (; smb; smb = next) {
+		next = smb->next;
+		smb_put_message(smb);
+	}
+}
+
 void
 cifs_wake_up_task(struct smb_message *smb)
 {
@@ -38,10 +78,8 @@ cifs_wake_up_task(struct smb_message *smb)
 	wake_up_process(smb->callback_data);
 }
 
-void __release_mid(struct kref *refcount)
+void __release_mid(struct smb_message *smb)
 {
-	struct smb_message *smb =
-			container_of(refcount, struct smb_message, refcount);
 #ifdef CONFIG_CIFS_STATS2
 	enum smb2_command command = smb->server->vals->lock_cmd;
 	enum smb2_command smb_cmd = smb->command_id;
@@ -719,7 +757,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 	rc = smb_send_rqst(server, 1, rqst, flags);
 
 	if (rc < 0) {
-		revert_current_mid(server, smb->credits);
+		revert_current_mid(server, smb->credits_consumed);
 		server->sequence_number -= 2;
 		delete_mid(smb);
 	}


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 14/31] cifs: Split crypt_message() into encrypt and decrypt variants
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (12 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 13/31] cifs: Institute message managing struct David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 15/31] cifs: Use netfs_alloc/free_folioq_buffer() David Howells
                   ` (20 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Split crypt_message() into encrypt and decrypt variants so that the encrypt
variant can be substantially changed.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/smb2ops.c | 100 ++++++++++++++++++++++++++++++++++------
 1 file changed, 85 insertions(+), 15 deletions(-)

diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 7b714e50f681..0ad4a2a012a0 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -4297,16 +4297,17 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key)
 
 	return -EAGAIN;
 }
+
 /*
- * Encrypt or decrypt @rqst message. @rqst[0] has the following format:
+ * Encrypt @rqst message. @rqst[0] has the following format:
  * iov[0]   - transform header (associate data),
  * iov[1-N] - SMB2 header and pages - data to encrypt.
  * On success return encrypted data in iov[1-N] and pages, leave iov[0]
  * untouched.
  */
 static int
-crypt_message(struct TCP_Server_Info *server, int num_rqst,
-	      struct smb_rqst *rqst, int enc, struct crypto_aead *tfm)
+encrypt_message(struct TCP_Server_Info *server, int num_rqst,
+		struct smb_rqst *rqst, struct crypto_aead *tfm)
 {
 	struct smb2_transform_hdr *tr_hdr =
 		(struct smb2_transform_hdr *)rqst[0].rq_iov[0].iov_base;
@@ -4321,10 +4322,10 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
 	void *creq;
 	size_t sensitive_size;
 
-	rc = smb2_get_enc_key(server, le64_to_cpu(tr_hdr->SessionId), enc, key);
+	rc = smb2_get_enc_key(server, le64_to_cpu(tr_hdr->SessionId), 1, key);
 	if (rc) {
-		cifs_server_dbg(FYI, "%s: Could not get %scryption key. sid: 0x%llx\n", __func__,
-			 enc ? "en" : "de", le64_to_cpu(tr_hdr->SessionId));
+		cifs_server_dbg(FYI, "%s: Could not get encryption key. sid: 0x%llx\n",
+				__func__, le64_to_cpu(tr_hdr->SessionId));
 		return rc;
 	}
 
@@ -4350,11 +4351,6 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
 	if (IS_ERR(creq))
 		return PTR_ERR(creq);
 
-	if (!enc) {
-		memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE);
-		crypt_len += SMB2_SIGNATURE_SIZE;
-	}
-
 	if ((server->cipher_type == SMB2_ENCRYPTION_AES128_GCM) ||
 	    (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM))
 		memcpy(iv, (char *)tr_hdr->Nonce, SMB3_AES_GCM_NONCE);
@@ -4367,15 +4363,89 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
 	aead_request_set_crypt(req, sg, sg, crypt_len, iv);
 	aead_request_set_ad(req, assoc_data_len);
 
-	rc = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req);
+	rc = crypto_aead_encrypt(req);
 
-	if (!rc && enc)
+	if (!rc)
 		memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE);
 
 	kvfree_sensitive(creq, sensitive_size);
 	return rc;
 }
 
+/*
+ * Decrypt @rqst message. @rqst[0] has the following format:
+ * iov[0]   - transform header (associate data),
+ * iov[1-N] - SMB2 header and pages - data to decrypt.
+ * On success return encrypted data in iov[1-N] and pages, leave iov[0]
+ * untouched.
+ */
+static int
+decrypt_message(struct TCP_Server_Info *server, int num_rqst,
+		struct smb_rqst *rqst, struct crypto_aead *tfm)
+{
+	struct smb2_transform_hdr *tr_hdr =
+		(struct smb2_transform_hdr *)rqst[0].rq_iov[0].iov_base;
+	unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
+	int rc = 0;
+	struct scatterlist *sg;
+	u8 sign[SMB2_SIGNATURE_SIZE] = {};
+	u8 key[SMB3_ENC_DEC_KEY_SIZE];
+	struct aead_request *req;
+	u8 *iv;
+	unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
+	void *creq;
+	size_t sensitive_size;
+
+	rc = smb2_get_enc_key(server, le64_to_cpu(tr_hdr->SessionId), 0, key);
+	if (rc) {
+		cifs_server_dbg(FYI, "%s: Could not get decryption key. sid: 0x%llx\n",
+				__func__, le64_to_cpu(tr_hdr->SessionId));
+		return rc;
+	}
+
+	if ((server->cipher_type == SMB2_ENCRYPTION_AES256_CCM) ||
+		(server->cipher_type == SMB2_ENCRYPTION_AES256_GCM))
+		rc = crypto_aead_setkey(tfm, key, SMB3_GCM256_CRYPTKEY_SIZE);
+	else
+		rc = crypto_aead_setkey(tfm, key, SMB3_GCM128_CRYPTKEY_SIZE);
+
+	if (rc) {
+		cifs_server_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc);
+		return rc;
+	}
+
+	rc = crypto_aead_setauthsize(tfm, SMB2_SIGNATURE_SIZE);
+	if (rc) {
+		cifs_server_dbg(VFS, "%s: Failed to set authsize %d\n", __func__, rc);
+		return rc;
+	}
+
+	creq = smb2_get_aead_req(tfm, rqst, num_rqst, sign, &iv, &req, &sg,
+				 &sensitive_size);
+	if (IS_ERR(creq))
+		return PTR_ERR(creq);
+
+	memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE);
+	crypt_len += SMB2_SIGNATURE_SIZE;
+
+	if ((server->cipher_type == SMB2_ENCRYPTION_AES128_GCM) ||
+	    (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM))
+		memcpy(iv, (char *)tr_hdr->Nonce, SMB3_AES_GCM_NONCE);
+	else {
+		iv[0] = 3;
+		memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES_CCM_NONCE);
+	}
+
+	aead_request_set_tfm(req, tfm);
+	aead_request_set_crypt(req, sg, sg, crypt_len, iv);
+	aead_request_set_ad(req, assoc_data_len);
+
+	rc = crypto_aead_decrypt(req);
+
+	kvfree_sensitive(creq, sensitive_size);
+	return rc;
+}
+
 /*
  * Clear a read buffer, discarding the folios which have the 1st mark set.
  */
@@ -4509,7 +4579,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst,
 	/* fill the 1st iov with a transform header */
 	fill_transform_hdr(tr_hdr, orig_len, old_rq, server->cipher_type);
 
-	rc = crypt_message(server, num_rqst, new_rq, 1, server->secmech.enc);
+	rc = encrypt_message(server, num_rqst, new_rq, server->secmech.enc);
 	cifs_dbg(FYI, "Encrypt message returned %d\n", rc);
 	if (rc)
 		goto err_free;
@@ -4571,7 +4641,7 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
 		tfm = server->secmech.dec;
 	}
 
-	rc = crypt_message(server, 1, &rqst, 0, tfm);
+	rc = decrypt_message(server, 1, &rqst, tfm);
 	cifs_dbg(FYI, "Decrypt message returned %d\n", rc);
 
 	if (is_offloaded)


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 15/31] cifs: Use netfs_alloc/free_folioq_buffer()
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (13 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 14/31] cifs: Split crypt_message() into encrypt and decrypt variants David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 16/31] cifs: Rewrite base TCP transmission David Howells
                   ` (19 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Use netfs_alloc/free_folioq_buffer() rather than doing its own version.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com> (RDMA, smbdirect)
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/smb2ops.c | 73 ++++++-----------------------------------
 1 file changed, 10 insertions(+), 63 deletions(-)

diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 0ad4a2a012a0..161cef316346 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -4446,61 +4446,6 @@ decrypt_message(struct TCP_Server_Info *server, int num_rqst,
 	return rc;
 }
 
-/*
- * Clear a read buffer, discarding the folios which have the 1st mark set.
- */
-static void cifs_clear_folioq_buffer(struct folio_queue *buffer)
-{
-	struct folio_queue *folioq;
-
-	while ((folioq = buffer)) {
-		for (int s = 0; s < folioq_count(folioq); s++)
-			if (folioq_is_marked(folioq, s))
-				folio_put(folioq_folio(folioq, s));
-		buffer = folioq->next;
-		kfree(folioq);
-	}
-}
-
-/*
- * Allocate buffer space into a folio queue.
- */
-static struct folio_queue *cifs_alloc_folioq_buffer(ssize_t size)
-{
-	struct folio_queue *buffer = NULL, *tail = NULL, *p;
-	struct folio *folio;
-	unsigned int slot;
-
-	do {
-		if (!tail || folioq_full(tail)) {
-			p = kmalloc(sizeof(*p), GFP_NOFS);
-			if (!p)
-				goto nomem;
-			folioq_init(p, 0);
-			if (tail) {
-				tail->next = p;
-				p->prev = tail;
-			} else {
-				buffer = p;
-			}
-			tail = p;
-		}
-
-		folio = folio_alloc(GFP_KERNEL|__GFP_HIGHMEM, 0);
-		if (!folio)
-			goto nomem;
-
-		slot = folioq_append_mark(tail, folio);
-		size -= folioq_folio_size(tail, slot);
-	} while (size > 0);
-
-	return buffer;
-
-nomem:
-	cifs_clear_folioq_buffer(buffer);
-	return NULL;
-}
-
 /*
  * Copy data from an iterator to the folios in a folio queue buffer.
  */
@@ -4526,7 +4471,7 @@ void
 smb3_free_compound_rqst(int num_rqst, struct smb_rqst *rqst)
 {
 	for (int i = 0; i < num_rqst; i++)
-		cifs_clear_folioq_buffer(rqst[i].rq_buffer);
+		netfs_free_folioq_buffer(rqst[i].rq_buffer);
 }
 
 /*
@@ -4561,8 +4506,10 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst,
 		new->rq_nvec = old->rq_nvec;
 
 		if (size > 0) {
-			buffer = cifs_alloc_folioq_buffer(size);
-			if (!buffer)
+			size_t cur_size = 0;
+			rc = netfs_alloc_folioq_buffer(NULL, &buffer, &cur_size,
+						       size, GFP_NOFS);
+			if (rc < 0)
 				goto err_free;
 
 			new->rq_buffer = buffer;
@@ -4894,7 +4841,7 @@ static void smb2_decrypt_offload(struct work_struct *work)
 	}
 
 free_pages:
-	cifs_clear_folioq_buffer(dw->buffer);
+	netfs_free_folioq_buffer(dw->buffer);
 	cifs_small_buf_release(dw->buf);
 	kfree(dw);
 }
@@ -4932,9 +4879,9 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct smb_message **smb,
 	dw->len = len;
 	len = round_up(dw->len, PAGE_SIZE);
 
-	rc = -ENOMEM;
-	dw->buffer = cifs_alloc_folioq_buffer(len);
-	if (!dw->buffer)
+	size_t cur_size = 0;
+	rc = netfs_alloc_folioq_buffer(NULL, &dw->buffer, &cur_size, len, GFP_NOFS);
+	if (rc < 0)
 		goto discard_data;
 
 	iov_iter_folio_queue(&iter, ITER_DEST, dw->buffer, 0, 0, len);
@@ -4995,7 +4942,7 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct smb_message **smb,
 	}
 
 free_pages:
-	cifs_clear_folioq_buffer(dw->buffer);
+	netfs_free_folioq_buffer(dw->buffer);
 free_dw:
 	kfree(dw);
 	return rc;


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 16/31] cifs: Rewrite base TCP transmission
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (14 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 15/31] cifs: Use netfs_alloc/free_folioq_buffer() David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-07  5:40   ` Stefan Metzmacher
                     ` (2 more replies)
  2025-08-06 20:36 ` [RFC PATCH 17/31] cifs: Rework smb2 decryption David Howells
                   ` (18 subsequent siblings)
  34 siblings, 3 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

[!] NOTE: This patch is not fully complete: RDMA is untested and compression
is currently disabled

Rewrite the base TCP transmission in cifs to copy all the content in a
(compound) message into a buffer of pages in a bvecq chain.  In future, the
pages in this bvecq chain will be allocated from the netmem allocator so
that the advance DMA/IOMMU handling will be done.

This list of pages can then be attached to an ITER_BVEC_QUEUE-type iov_iter
and passed in a single call to sendmsg() with MSG_SPLICE_PAGES, thereby
avoiding the need to copy the data in the TCP stack.

The encryption code can also be simplified as it only needs to encrypt the
data stored in those pages, with the bonus that the content in the pages is
correctly aligned for the encryption in place such that it does not need to
copy the data whilst encrypting it.

It could be arranged for the data to be held in contiguous pages if
possible and if necessary such that crypto can be offloaded to devices that
only permit a single contiguous buffer.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/netfs/buffer.c         |   3 +-
 fs/smb/client/cifsglob.h  |   7 +-
 fs/smb/client/cifsproto.h |   5 +-
 fs/smb/client/smb1ops.c   |   5 +-
 fs/smb/client/smb2ops.c   | 193 ++++++++++++-------------
 fs/smb/client/smbdirect.c |  88 ++----------
 fs/smb/client/smbdirect.h |   5 +-
 fs/smb/client/transport.c | 291 +++++++++++++++++++++++++++-----------
 8 files changed, 330 insertions(+), 267 deletions(-)

diff --git a/fs/netfs/buffer.c b/fs/netfs/buffer.c
index 1e4ed2746e95..84d5ddc2a2c0 100644
--- a/fs/netfs/buffer.c
+++ b/fs/netfs/buffer.c
@@ -93,7 +93,8 @@ void netfs_free_bvecq_buffer(struct bvecq *bq)
 
 	for (; bq; bq = next) {
 		for (int seg = 0; seg < bq->nr_segs; seg++)
-			__free_page(bq->bv[seg].bv_page);
+			if (bq->bv[seg].bv_page)
+				__free_page(bq->bv[seg].bv_page);
 		next = bq->next;
 		kfree(bq);
 	}
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 90dafae1e9ab..ae06c2b5a9c8 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -594,8 +594,10 @@ struct smb_version_operations {
 	long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t,
 			  loff_t);
 	/* init transform (compress/encrypt) request */
-	int (*init_transform_rq)(struct TCP_Server_Info *, int num_rqst,
-				 struct smb_rqst *, struct smb_rqst *);
+	int (*init_transform_rq)(struct TCP_Server_Info *server,
+				 int num_rqst, const struct smb_rqst *rqst,
+				 struct smb2_transform_hdr *tr_hdr,
+				 struct iov_iter *iter);
 	int (*is_transform_hdr)(void *buf);
 	int (*receive_transform)(struct TCP_Server_Info *,
 				 struct smb_message **smb, char **, int *);
@@ -1356,7 +1358,6 @@ struct tcon_link {
 };
 
 extern struct tcon_link *cifs_sb_tlink(struct cifs_sb_info *cifs_sb);
-extern void smb3_free_compound_rqst(int num_rqst, struct smb_rqst *rqst);
 
 static inline struct cifs_tcon *
 tlink_tcon(struct tcon_link *tlink)
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index 6f27fb6ef5dc..76cb047b2715 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -32,6 +32,8 @@ extern void free_rsp_buf(int, void *);
 extern int smb_send_kvec(struct TCP_Server_Info *server,
 			 struct msghdr *msg,
 			 size_t *sent);
+int smb_sendmsg(struct TCP_Server_Info *server, struct msghdr *smb_msg,
+		size_t *sent);
 extern unsigned int _get_xid(void);
 extern void _free_xid(unsigned int);
 #define get_xid()							\
@@ -120,8 +122,7 @@ extern struct smb_message *cifs_setup_request(struct cifs_ses *,
 				struct smb_rqst *);
 extern struct smb_message *cifs_setup_async_request(struct TCP_Server_Info *,
 						struct smb_rqst *);
-int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
-		    struct smb_rqst *rqst);
+int __smb_send_rqst(struct TCP_Server_Info *server, struct iov_iter *iter);
 extern int cifs_check_receive(struct smb_message *msg,
 			struct TCP_Server_Info *server, bool log_error);
 int wait_for_free_request(struct TCP_Server_Info *server, const int flags,
diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
index cc5b3c531c77..185210b7fd03 100644
--- a/fs/smb/client/smb1ops.c
+++ b/fs/smb/client/smb1ops.c
@@ -32,6 +32,7 @@ send_nt_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
 	       struct smb_rqst *rqst, struct smb_message *smb,
 	       unsigned int xid)
 {
+	struct iov_iter iter;
 	struct smb_hdr *in_buf = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 	struct kvec iov[1];
 	struct smb_rqst crqst = { .rq_iov = iov, .rq_nvec = 1 };
@@ -53,13 +54,15 @@ send_nt_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
 		return rc;
 	}
 
+	iov_iter_kvec(&iter, ITER_SOURCE, iov, 1, iov[0].iov_len);
+
 	/*
 	 * The response to this call was already factored into the sequence
 	 * number when the call went out, so we must adjust it back downward
 	 * after signing here.
 	 */
 	--server->sequence_number;
-	rc = __smb_send_rqst(server, 1, &crqst);
+	rc = __smb_send_rqst(server, &iter);
 	if (rc < 0)
 		server->sequence_number--;
 
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 161cef316346..baa54e746f0f 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -4169,21 +4169,21 @@ smb2_dir_needs_close(struct cifsFileInfo *cfile)
 
 static void
 fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len,
-		   struct smb_rqst *old_rq, __le16 cipher_type)
+		   const struct smb_rqst *old_rq, __le16 cipher_type)
 {
-	struct smb2_hdr *shdr =
-			(struct smb2_hdr *)old_rq->rq_iov[0].iov_base;
+	struct smb2_hdr *shdr = (struct smb2_hdr *)old_rq->rq_iov[0].iov_base;
 
-	memset(tr_hdr, 0, sizeof(struct smb2_transform_hdr));
-	tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM;
-	tr_hdr->OriginalMessageSize = cpu_to_le32(orig_len);
-	tr_hdr->Flags = cpu_to_le16(0x01);
+	*tr_hdr = (struct smb2_transform_hdr){
+		.ProtocolId		= SMB2_TRANSFORM_PROTO_NUM,
+		.OriginalMessageSize	= cpu_to_le32(orig_len),
+		.Flags			= cpu_to_le16(0x01),
+		.SessionId		= shdr->SessionId,
+	};
 	if ((cipher_type == SMB2_ENCRYPTION_AES128_GCM) ||
 	    (cipher_type == SMB2_ENCRYPTION_AES256_GCM))
 		get_random_bytes(&tr_hdr->Nonce, SMB3_AES_GCM_NONCE);
 	else
 		get_random_bytes(&tr_hdr->Nonce, SMB3_AES_CCM_NONCE);
-	memcpy(&tr_hdr->SessionId, &shdr->SessionId, 8);
 }
 
 static void *smb2_aead_req_alloc(struct crypto_aead *tfm, const struct smb_rqst *rqst,
@@ -4269,6 +4269,75 @@ static void *smb2_get_aead_req(struct crypto_aead *tfm, struct smb_rqst *rqst,
 	return p;
 }
 
+/*
+ * Allocate the context info needed for the encryption operation, along with a
+ * scatterlist to point to the buffer.
+ */
+static void *smb2_aead_req_alloc_new(struct crypto_aead *tfm, const struct iov_iter *iter,
+				 const u8 *sig, u8 **iv,
+				 struct aead_request **req, struct sg_table *sgt,
+				 unsigned int *num_sgs, size_t *sensitive_size)
+{
+	unsigned int req_size = sizeof(**req) + crypto_aead_reqsize(tfm);
+	unsigned int iv_size = crypto_aead_ivsize(tfm);
+	unsigned int len;
+	u8 *p;
+
+	*num_sgs = iov_iter_npages(iter, INT_MAX);
+
+	len = iv_size;
+	len += crypto_aead_alignmask(tfm) & ~(crypto_tfm_ctx_alignment() - 1);
+	len = ALIGN(len, crypto_tfm_ctx_alignment());
+	len += req_size;
+	len = ALIGN(len, __alignof__(struct scatterlist));
+	len += array_size(*num_sgs, sizeof(struct scatterlist));
+	*sensitive_size = len;
+
+	p = kvzalloc(len, GFP_NOFS);
+	if (!p)
+		return ERR_PTR(-ENOMEM);
+
+	*iv = (u8 *)PTR_ALIGN(p, crypto_aead_alignmask(tfm) + 1);
+	*req = (struct aead_request *)PTR_ALIGN(*iv + iv_size,
+						crypto_tfm_ctx_alignment());
+	sgt->sgl = (struct scatterlist *)PTR_ALIGN((u8 *)*req + req_size,
+						   __alignof__(struct scatterlist));
+	return p;
+}
+
+/*
+ * Set up for doing a crypto operation, building a scatterlist from the
+ * supplied iterator.
+ */
+static void *smb2_get_aead_req_new(struct crypto_aead *tfm, const struct iov_iter *iter,
+				   const u8 *sig, u8 **iv,
+				   struct aead_request **req, struct scatterlist **sgl,
+				   size_t *sensitive_size)
+{
+	struct sg_table sgtable = {};
+	struct iov_iter tmp = *iter;
+	unsigned int num_sgs;
+	ssize_t rc;
+	void *p;
+
+	p = smb2_aead_req_alloc_new(tfm, iter, sig, iv, req, &sgtable,
+				    &num_sgs, sensitive_size);
+	if (IS_ERR(p))
+		return ERR_CAST(p);
+
+	sg_init_marker(sgtable.sgl, num_sgs);
+
+	rc = extract_iter_to_sg(&tmp, iov_iter_count(iter), &sgtable, num_sgs, 0);
+	sgtable.orig_nents = sgtable.nents;
+	if (rc < 0)
+		return ERR_PTR(rc);
+
+	cifs_sg_set_buf(&sgtable, sig, SMB2_SIGNATURE_SIZE);
+	sg_mark_end(&sgtable.sgl[sgtable.nents - 1]);
+	*sgl = sgtable.sgl;
+	return p;
+}
+
 static int
 smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key)
 {
@@ -4299,18 +4368,15 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key)
 }
 
 /*
- * Encrypt @rqst message. @rqst[0] has the following format:
- * iov[0]   - transform header (associate data),
- * iov[1-N] - SMB2 header and pages - data to encrypt.
+ * Encrypt the message in the buffer described by the iterator.
  * On success return encrypted data in iov[1-N] and pages, leave iov[0]
  * untouched.
  */
 static int
-encrypt_message(struct TCP_Server_Info *server, int num_rqst,
-		struct smb_rqst *rqst, struct crypto_aead *tfm)
+encrypt_message(struct TCP_Server_Info *server,
+		struct smb2_transform_hdr *tr_hdr,
+		struct iov_iter *iter, struct crypto_aead *tfm)
 {
-	struct smb2_transform_hdr *tr_hdr =
-		(struct smb2_transform_hdr *)rqst[0].rq_iov[0].iov_base;
 	unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
 	int rc = 0;
 	struct scatterlist *sg;
@@ -4346,8 +4412,8 @@ encrypt_message(struct TCP_Server_Info *server, int num_rqst,
 		return rc;
 	}
 
-	creq = smb2_get_aead_req(tfm, rqst, num_rqst, sign, &iv, &req, &sg,
-				 &sensitive_size);
+	creq = smb2_get_aead_req_new(tfm, iter, sign, &iv, &req, &sg,
+				     &sensitive_size);
 	if (IS_ERR(creq))
 		return PTR_ERR(creq);
 
@@ -4447,94 +4513,23 @@ decrypt_message(struct TCP_Server_Info *server, int num_rqst,
 }
 
 /*
- * Copy data from an iterator to the folios in a folio queue buffer.
- */
-static bool cifs_copy_iter_to_folioq(struct iov_iter *iter, size_t size,
-				     struct folio_queue *buffer)
-{
-	for (; buffer; buffer = buffer->next) {
-		for (int s = 0; s < folioq_count(buffer); s++) {
-			struct folio *folio = folioq_folio(buffer, s);
-			size_t part = folioq_folio_size(buffer, s);
-
-			part = umin(part, size);
-
-			if (copy_folio_from_iter(folio, 0, part, iter) != part)
-				return false;
-			size -= part;
-		}
-	}
-	return true;
-}
-
-void
-smb3_free_compound_rqst(int num_rqst, struct smb_rqst *rqst)
-{
-	for (int i = 0; i < num_rqst; i++)
-		netfs_free_folioq_buffer(rqst[i].rq_buffer);
-}
-
-/*
- * This function will initialize new_rq and encrypt the content.
- * The first entry, new_rq[0], only contains a single iov which contains
- * a smb2_transform_hdr and is pre-allocated by the caller.
- * This function then populates new_rq[1+] with the content from olq_rq[0+].
- *
- * The end result is an array of smb_rqst structures where the first structure
- * only contains a single iov for the transform header which we then can pass
- * to crypt_message().
- *
- * new_rq[0].rq_iov[0] :  smb2_transform_hdr pre-allocated by the caller
- * new_rq[1+].rq_iov[*] == old_rq[0+].rq_iov[*] : SMB2/3 requests
+ * This function encrypts the content in the buffer described by the iterator
+ * and fills in the transform header.  The source request buffers are provided
+ * for reference.
  */
 static int
-smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst,
-		       struct smb_rqst *new_rq, struct smb_rqst *old_rq)
+smb3_init_transform_rq(struct TCP_Server_Info *server,
+		       int num_rqst, const struct smb_rqst *rqst,
+		       struct smb2_transform_hdr *tr_hdr,
+		       struct iov_iter *iter)
 {
-	struct smb2_transform_hdr *tr_hdr = new_rq[0].rq_iov[0].iov_base;
-	unsigned int orig_len = 0;
-	int rc = -ENOMEM;
-
-	for (int i = 1; i < num_rqst; i++) {
-		struct smb_rqst *old = &old_rq[i - 1];
-		struct smb_rqst *new = &new_rq[i];
-		struct folio_queue *buffer;
-		size_t size = iov_iter_count(&old->rq_iter);
-
-		orig_len += smb_rqst_len(server, old);
-		new->rq_iov = old->rq_iov;
-		new->rq_nvec = old->rq_nvec;
-
-		if (size > 0) {
-			size_t cur_size = 0;
-			rc = netfs_alloc_folioq_buffer(NULL, &buffer, &cur_size,
-						       size, GFP_NOFS);
-			if (rc < 0)
-				goto err_free;
-
-			new->rq_buffer = buffer;
-			iov_iter_folio_queue(&new->rq_iter, ITER_SOURCE,
-					     buffer, 0, 0, size);
-
-			if (!cifs_copy_iter_to_folioq(&old->rq_iter, size, buffer)) {
-				rc = -EIO;
-				goto err_free;
-			}
-		}
-	}
+	int rc;
 
-	/* fill the 1st iov with a transform header */
-	fill_transform_hdr(tr_hdr, orig_len, old_rq, server->cipher_type);
+	fill_transform_hdr(tr_hdr, iov_iter_count(iter), rqst,
+			   server->cipher_type);
 
-	rc = encrypt_message(server, num_rqst, new_rq, server->secmech.enc);
+	rc = encrypt_message(server, tr_hdr, iter, server->secmech.enc);
 	cifs_dbg(FYI, "Encrypt message returned %d\n", rc);
-	if (rc)
-		goto err_free;
-
-	return rc;
-
-err_free:
-	smb3_free_compound_rqst(num_rqst - 1, &new_rq[1]);
 	return rc;
 }
 
diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c
index 754e94a0e07f..a75cb3f0ca72 100644
--- a/fs/smb/client/smbdirect.c
+++ b/fs/smb/client/smbdirect.c
@@ -1015,27 +1015,6 @@ static int smbd_post_send_empty(struct smbd_connection *info)
 	return smbd_post_send_iter(info, NULL, &remaining_data_length);
 }
 
-static int smbd_post_send_full_iter(struct smbd_connection *info,
-				    struct iov_iter *iter,
-				    int *_remaining_data_length)
-{
-	int rc = 0;
-
-	/*
-	 * smbd_post_send_iter() respects the
-	 * negotiated max_send_size, so we need to
-	 * loop until the full iter is posted
-	 */
-
-	while (iov_iter_count(iter) > 0) {
-		rc = smbd_post_send_iter(info, iter, _remaining_data_length);
-		if (rc < 0)
-			break;
-	}
-
-	return rc;
-}
-
 /*
  * Post a receive request to the transport
  * The remote peer can only send data when a receive request is posted
@@ -1929,75 +1908,38 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg)
 
 /*
  * Send data to transport
- * Each rqst is transported as a SMBDirect payload
- * rqst: the data to write
  * return value: 0 if successfully write, otherwise error code
  */
-int smbd_send(struct TCP_Server_Info *server,
-	int num_rqst, struct smb_rqst *rqst_array)
+int smbd_send(struct TCP_Server_Info *server, struct iov_iter *iter)
 {
 	struct smbd_connection *info = server->smbd_conn;
 	struct smbdirect_socket *sc = &info->socket;
 	struct smbdirect_socket_parameters *sp = &sc->parameters;
-	struct smb_rqst *rqst;
-	struct iov_iter iter;
-	unsigned int remaining_data_length, klen;
-	int rc, i, rqst_idx;
+	size_t size = iov_iter_count(iter);
+	unsigned int remain = 0;
+	int rc;
 
 	if (sc->status != SMBDIRECT_SOCKET_CONNECTED)
 		return -EAGAIN;
 
-	/*
-	 * Add in the page array if there is one. The caller needs to set
-	 * rq_tailsz to PAGE_SIZE when the buffer has multiple pages and
-	 * ends at page boundary
-	 */
-	remaining_data_length = 0;
-	for (i = 0; i < num_rqst; i++)
-		remaining_data_length += smb_rqst_len(server, &rqst_array[i]);
-
-	if (unlikely(remaining_data_length > sp->max_fragmented_send_size)) {
+	if (unlikely(size > sp->max_fragmented_send_size)) {
 		/* assertion: payload never exceeds negotiated maximum */
-		log_write(ERR, "payload size %d > max size %d\n",
-			remaining_data_length, sp->max_fragmented_send_size);
+		log_write(ERR, "payload size %zu > max size %d\n",
+			  size, sp->max_fragmented_send_size);
 		return -EINVAL;
 	}
 
-	log_write(INFO, "num_rqst=%d total length=%u\n",
-			num_rqst, remaining_data_length);
-
-	rqst_idx = 0;
-	do {
-		rqst = &rqst_array[rqst_idx];
-
-		cifs_dbg(FYI, "Sending smb (RDMA): idx=%d smb_len=%lu\n",
-			 rqst_idx, smb_rqst_len(server, rqst));
-		for (i = 0; i < rqst->rq_nvec; i++)
-			dump_smb(rqst->rq_iov[i].iov_base, rqst->rq_iov[i].iov_len);
-
-		log_write(INFO, "RDMA-WR[%u] nvec=%d len=%u iter=%zu rqlen=%lu\n",
-			  rqst_idx, rqst->rq_nvec, remaining_data_length,
-			  iov_iter_count(&rqst->rq_iter), smb_rqst_len(server, rqst));
+	log_write(INFO, "size=%zu\n", size);
 
-		/* Send the metadata pages. */
-		klen = 0;
-		for (i = 0; i < rqst->rq_nvec; i++)
-			klen += rqst->rq_iov[i].iov_len;
-		iov_iter_kvec(&iter, ITER_SOURCE, rqst->rq_iov, rqst->rq_nvec, klen);
-
-		rc = smbd_post_send_full_iter(info, &iter, &remaining_data_length);
+	/*
+	 * smbd_post_send_iter() respects the negotiated max_send_size, so we
+	 * need to loop until the full iter is posted
+	 */
+	while (iov_iter_count(iter) > 0) {
+		rc = smbd_post_send_iter(info, iter, &remain);
 		if (rc < 0)
 			break;
-
-		if (iov_iter_count(&rqst->rq_iter) > 0) {
-			/* And then the data pages if there are any */
-			rc = smbd_post_send_full_iter(info, &rqst->rq_iter,
-						      &remaining_data_length);
-			if (rc < 0)
-				break;
-		}
-
-	} while (++rqst_idx < num_rqst);
+	}
 
 	/*
 	 * As an optimization, we don't wait for individual I/O to finish
diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h
index 75b3f491c3ad..aec119d95c5c 100644
--- a/fs/smb/client/smbdirect.h
+++ b/fs/smb/client/smbdirect.h
@@ -214,8 +214,7 @@ void smbd_destroy(struct TCP_Server_Info *server);
 
 /* Interface for carrying upper layer I/O through send/recv */
 int smbd_recv(struct smbd_connection *info, struct msghdr *msg);
-int smbd_send(struct TCP_Server_Info *server,
-	int num_rqst, struct smb_rqst *rqst);
+int smbd_send(struct TCP_Server_Info *server, struct iov_iter *iter);
 
 enum mr_state {
 	MR_READY,
@@ -254,7 +253,7 @@ static inline void *smbd_get_connection(
 static inline int smbd_reconnect(struct TCP_Server_Info *server) {return -1; }
 static inline void smbd_destroy(struct TCP_Server_Info *server) {}
 static inline int smbd_recv(struct smbd_connection *info, struct msghdr *msg) {return -1; }
-static inline int smbd_send(struct TCP_Server_Info *server, int num_rqst, struct smb_rqst *rqst) {return -1; }
+static inline int smbd_send(struct TCP_Server_Info *server, struct iov_iter *iter) {return -1; }
 #endif
 
 #endif
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index 288351c27fc4..6459acf959f3 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -22,6 +22,8 @@
 #include <linux/mempool.h>
 #include <linux/sched/signal.h>
 #include <linux/task_io_accounting_ops.h>
+#include <linux/iov_iter.h>
+#include "rfc1002pdu.h"
 #include "cifspdu.h"
 #include "cifsglob.h"
 #include "cifsproto.h"
@@ -244,6 +246,80 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg,
 	return 0;
 }
 
+/*
+ * smb_sendmsg - send a buffer to the socket
+ * @server:	Server to send the data to
+ * @smb_msg:	Message to send
+ * @sent:	amount of data sent on socket is stored here
+ *
+ * Our basic "send data to server" function. Should be called with srv_mutex
+ * held. The caller is responsible for handling the results.
+ */
+int smb_sendmsg(struct TCP_Server_Info *server, struct msghdr *smb_msg,
+		size_t *sent)
+{
+	int rc = 0;
+	int retries = 0;
+	struct socket *ssocket = server->ssocket;
+
+	*sent = 0;
+
+	if (server->noblocksnd)
+		smb_msg->msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
+	else
+		smb_msg->msg_flags = MSG_NOSIGNAL;
+	smb_msg->msg_flags = MSG_SPLICE_PAGES;
+
+	while (msg_data_left(smb_msg)) {
+		/*
+		 * If blocking send, we try 3 times, since each can block
+		 * for 5 seconds. For nonblocking  we have to try more
+		 * but wait increasing amounts of time allowing time for
+		 * socket to clear.  The overall time we wait in either
+		 * case to send on the socket is about 15 seconds.
+		 * Similarly we wait for 15 seconds for a response from
+		 * the server in SendReceive[2] for the server to send
+		 * a response back for most types of requests (except
+		 * SMB Write past end of file which can be slow, and
+		 * blocking lock operations). NFS waits slightly longer
+		 * than CIFS, but this can make it take longer for
+		 * nonresponsive servers to be detected and 15 seconds
+		 * is more than enough time for modern networks to
+		 * send a packet.  In most cases if we fail to send
+		 * after the retries we will kill the socket and
+		 * reconnect which may clear the network problem.
+		 */
+		rc = sock_sendmsg(ssocket, smb_msg);
+		if (rc == -EAGAIN) {
+			retries++;
+			if (retries >= 14 ||
+			    (!server->noblocksnd && (retries > 2))) {
+				cifs_server_dbg(VFS, "sends on sock %p stuck for 15 seconds\n",
+					 ssocket);
+				return -EAGAIN;
+			}
+			msleep(1 << retries);
+			continue;
+		}
+
+		if (rc < 0)
+			return rc;
+
+		if (rc == 0) {
+			/* should never happen, letting socket clear before
+			   retrying is our only obvious option here */
+			cifs_server_dbg(VFS, "tcp sent no data\n");
+			msleep(500);
+			continue;
+		}
+
+		/* send was at least partially successful */
+		*sent += rc;
+		retries = 0; /* in case we get ENOSPC on the next send */
+	}
+	return 0;
+}
+
 unsigned long
 smb_rqst_len(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 {
@@ -269,26 +345,22 @@ smb_rqst_len(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 	return buflen;
 }
 
-int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
-		    struct smb_rqst *rqst)
+int
+__smb_send_rqst(struct TCP_Server_Info *server, struct iov_iter *iter)
 {
-	int rc;
-	struct kvec *iov;
-	int n_vec;
+	struct socket *ssocket = server->ssocket;
+	struct msghdr smb_msg = { .msg_iter = *iter, };
 	unsigned int send_length = 0;
-	unsigned int i, j;
 	sigset_t mask, oldmask;
-	size_t total_len = 0, sent, size;
-	struct socket *ssocket = server->ssocket;
-	struct msghdr smb_msg = {};
-	__be32 rfc1002_marker;
+	size_t total_len = 0, sent;
+	int rc;
 
 	cifs_in_send_inc(server);
 	if (cifs_rdma_enabled(server)) {
 		/* return -EAGAIN when connecting or reconnecting */
 		rc = -EAGAIN;
 		if (server->smbd_conn)
-			rc = smbd_send(server, num_rqst, rqst);
+			rc = smbd_send(server, iter);
 		goto smbd_done;
 	}
 
@@ -306,10 +378,6 @@ int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
 	/* cork the socket */
 	tcp_sock_set_cork(ssocket->sk, true);
 
-	for (j = 0; j < num_rqst; j++)
-		send_length += smb_rqst_len(server, &rqst[j]);
-	rfc1002_marker = cpu_to_be32(send_length);
-
 	/*
 	 * We should not allow signals to interrupt the network send because
 	 * any partial send will cause session reconnects thus increasing
@@ -320,52 +388,9 @@ int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
 	sigfillset(&mask);
 	sigprocmask(SIG_BLOCK, &mask, &oldmask);
 
-	/* Generate a rfc1002 marker for SMB2+ */
-	if (!is_smb1(server)) {
-		struct kvec hiov = {
-			.iov_base = &rfc1002_marker,
-			.iov_len  = 4
-		};
-		iov_iter_kvec(&smb_msg.msg_iter, ITER_SOURCE, &hiov, 1, 4);
-		rc = smb_send_kvec(server, &smb_msg, &sent);
-		if (rc < 0)
-			goto unmask;
-
-		total_len += sent;
-		send_length += 4;
-	}
-
-	cifs_dbg(FYI, "Sending smb: smb_len=%u\n", send_length);
-
-	for (j = 0; j < num_rqst; j++) {
-		iov = rqst[j].rq_iov;
-		n_vec = rqst[j].rq_nvec;
-
-		size = 0;
-		for (i = 0; i < n_vec; i++) {
-			dump_smb(iov[i].iov_base, iov[i].iov_len);
-			size += iov[i].iov_len;
-		}
-
-		iov_iter_kvec(&smb_msg.msg_iter, ITER_SOURCE, iov, n_vec, size);
-
-		rc = smb_send_kvec(server, &smb_msg, &sent);
-		if (rc < 0)
-			goto unmask;
+	cifs_dbg(FYI, "Sending smb: smb_len=%zu\n", iov_iter_count(iter));
+	rc = smb_sendmsg(server, &smb_msg, &sent);
 
-		total_len += sent;
-
-		if (iov_iter_count(&rqst[j].rq_iter) > 0) {
-			smb_msg.msg_iter = rqst[j].rq_iter;
-			rc = smb_send_kvec(server, &smb_msg, &sent);
-			if (rc < 0)
-				break;
-			total_len += sent;
-		}
-
-}
-
-unmask:
 	sigprocmask(SIG_SETMASK, &oldmask, NULL);
 
 	/*
@@ -379,7 +404,7 @@ int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
 	 * won't be any response from the server to handle.
 	 */
 
-	if (signal_pending(current) && (total_len != send_length)) {
+	if (signal_pending(current) && (total_len != iov_iter_count(iter))) {
 		cifs_dbg(FYI, "signal is pending after attempt to send\n");
 		rc = -ERESTARTSYS;
 	}
@@ -387,7 +412,7 @@ int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
 	/* uncork it */
 	tcp_sock_set_cork(ssocket->sk, false);
 
-	if ((total_len > 0) && (total_len != send_length)) {
+	if (total_len > 0 && total_len != iov_iter_count(iter)) {
 		cifs_dbg(FYI, "partial send (wanted=%u sent=%zu): terminating session\n",
 			 send_length, total_len);
 		/*
@@ -417,41 +442,137 @@ int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
 	return rc;
 }
 
+static size_t smb3_copy_data_iter(void *iter_from, size_t progress, size_t len,
+				  void *priv, void *priv2)
+{
+	struct iov_iter *iter = priv;
+	return copy_to_iter(iter_from, len, iter) == len ? 0 : len;
+}
+
+/*
+ * Copy the data into a buffer that we can use for encryption in place and also
+ * pass to sendmsg() with MSG_SPLICE_PAGES.  This avoids a lot of copies in TCP
+ * at the expense of an upfront here.  A spare slot is left in the bvec queue
+ * at the front for the header(s).
+ */
+static int smb_copy_data_into_buffer(struct TCP_Server_Info *server,
+				     int num_rqst, struct smb_rqst *rqst,
+				     struct iov_iter *iter, struct bvecq **_bq)
+{
+	struct bvecq *bq;
+	size_t total_len = 0, offset = 0;
+
+	for (int i = 0; i < num_rqst; i++) {
+		struct smb_rqst *req = &rqst[i];
+		size_t size = iov_iter_count(&req->rq_iter);
+
+		for (int j = 0; j < req->rq_nvec; j++)
+			size += req->rq_iov[j].iov_len;
+		total_len = ALIGN8(total_len);
+		total_len += size;
+	}
+
+	bq = netfs_alloc_bvecq_buffer(total_len, 1, GFP_NOFS);
+	if (!bq)
+		return -ENOMEM;
+
+	iov_iter_bvec_queue(iter, ITER_DEST, bq, 1, 0, total_len);
+
+	for (int i = 0; i < num_rqst; i++) {
+		struct smb_rqst *req = &rqst[i];
+		size_t size = iov_iter_count(&req->rq_iter);
+
+		if (offset & 7) {
+			unsigned int tmp = offset;
+			offset = ALIGN8(offset);
+			iov_iter_zero(offset - tmp, iter);
+		}
+
+		for (int j = 0; j < req->rq_nvec; j++) {
+			size_t len = req->rq_iov[j].iov_len;
+			if (copy_to_iter(req->rq_iov[j].iov_base, len, iter) != len)
+				goto error;
+			offset += len;
+		}
+
+		if (iterate_and_advance_kernel(&req->rq_iter,
+					       size, iter, NULL,
+					       smb3_copy_data_iter) != size)
+			goto error;
+
+		offset += size;
+	}
+
+	if (WARN_ONCE(offset != total_len,
+		      "offset=%zx total_len=%zx\n", offset, total_len)) {
+		goto error;
+	}
+	iov_iter_bvec_queue(iter, ITER_DEST, bq, 1, 0, total_len);
+	*_bq = bq;
+	return 0;
+error:
+	netfs_free_bvecq_buffer(bq);
+	*_bq = NULL;
+	return -EIO;
+}
+
 static int
 smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
 	      struct smb_rqst *rqst, int flags)
 {
-	struct smb2_transform_hdr tr_hdr;
-	struct smb_rqst new_rqst[MAX_COMPOUND] = {};
-	struct kvec iov = {
-		.iov_base = &tr_hdr,
-		.iov_len = sizeof(tr_hdr),
-	};
+	struct smb2_transform_hdr *tr_hdr;
+	struct iov_iter iter;
+	struct bvecq *bq;
+	u32 content_len;
 	int rc;
 
-	if (flags & CIFS_COMPRESS_REQ)
-		return smb_compress(server, &rqst[0], __smb_send_rqst);
-
-	if (!(flags & CIFS_TRANSFORM_REQ))
-		return __smb_send_rqst(server, num_rqst, rqst);
-
-	if (WARN_ON_ONCE(num_rqst > MAX_COMPOUND - 1))
-		return -EIO;
-
-	if (!server->ops->init_transform_rq) {
+	if ((flags & CIFS_TRANSFORM_REQ) &&
+	    !server->ops->init_transform_rq) {
 		cifs_server_dbg(VFS, "Encryption requested but transform callback is missing\n");
 		return -EIO;
 	}
 
-	new_rqst[0].rq_iov = &iov;
-	new_rqst[0].rq_nvec = 1;
+	rc = smb_copy_data_into_buffer(server, num_rqst, rqst, &iter, &bq);
+	if (rc)
+		return rc;
+	content_len = iov_iter_count(&iter);
+
+	if (is_smb1(server)) {
+		iov_iter_bvec_queue(&iter, ITER_SOURCE, bq, 1, 0, content_len);
+	} else {
+		__le32 *rfc1002;
+		void *hdr_blob;
+		u32 hdr_len = 0;
+
+		/* TODO: Allocate netmem here */
+		rc = -ENOMEM;
+		hdr_blob = (void *)__get_free_page(GFP_NOFS);
+		if (!hdr_blob)
+			goto error;
+
+		//if (flags & CIFS_COMPRESS_REQ)
+		//	return smb_compress(server, &iter, &bq);
+
+		/* Set the RFC1002 header at the front. */
+		rfc1002 = hdr_blob;
+		*rfc1002 = cpu_to_be32(RFC1002_SESSION_MESSAGE << 24 | content_len);
+
+		if (flags & CIFS_TRANSFORM_REQ) {
+			tr_hdr = hdr_blob + 4;
+			hdr_len += sizeof(*tr_hdr);
+			iov_iter_bvec_queue(&iter, ITER_SOURCE, bq, 1, 0, content_len);
+
+			rc = server->ops->init_transform_rq(server, num_rqst, rqst, tr_hdr, &iter);
+			if (rc)
+				goto error;
+		}
 
-	rc = server->ops->init_transform_rq(server, num_rqst + 1,
-					    new_rqst, rqst);
-	if (!rc) {
-		rc = __smb_send_rqst(server, num_rqst + 1, new_rqst);
-		smb3_free_compound_rqst(num_rqst, &new_rqst[1]);
+		bvec_set_virt(&bq->bv[0], hdr_blob, hdr_len);
+		iov_iter_bvec_queue(&iter, ITER_SOURCE, bq, 0, 0, hdr_len + content_len);
 	}
+	rc = __smb_send_rqst(server, &iter);
+error:
+	netfs_free_bvecq_buffer(bq);
 	return rc;
 }
 


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 17/31] cifs: Rework smb2 decryption
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (15 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 16/31] cifs: Rewrite base TCP transmission David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 18/31] cifs: Pass smb_message structs down into the transport layer David Howells
                   ` (17 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/cifsglob.h |  60 -----------------
 fs/smb/client/smb2ops.c  | 138 +++++----------------------------------
 2 files changed, 15 insertions(+), 183 deletions(-)

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index ae06c2b5a9c8..1eed8a463b58 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -2280,66 +2280,6 @@ static inline void move_cifs_info_to_smb2(struct smb2_file_all_info *dst, const
 	dst->FileNameLength = src->FileNameLength;
 }
 
-static inline int cifs_get_num_sgs(const struct smb_rqst *rqst,
-				   int num_rqst,
-				   const u8 *sig)
-{
-	unsigned int len, skip;
-	unsigned int nents = 0;
-	unsigned long addr;
-	size_t data_size;
-	int i, j;
-
-	/*
-	 * The first rqst has a transform header where the first 20 bytes are
-	 * not part of the encrypted blob.
-	 */
-	skip = 20;
-
-	/* Assumes the first rqst has a transform header as the first iov.
-	 * I.e.
-	 * rqst[0].rq_iov[0]  is transform header
-	 * rqst[0].rq_iov[1+] data to be encrypted/decrypted
-	 * rqst[1+].rq_iov[0+] data to be encrypted/decrypted
-	 */
-	for (i = 0; i < num_rqst; i++) {
-		data_size = iov_iter_count(&rqst[i].rq_iter);
-
-		/* We really don't want a mixture of pinned and unpinned pages
-		 * in the sglist.  It's hard to keep track of which is what.
-		 * Instead, we convert to a BVEC-type iterator higher up.
-		 */
-		if (data_size &&
-		    WARN_ON_ONCE(user_backed_iter(&rqst[i].rq_iter)))
-			return -EIO;
-
-		/* We also don't want to have any extra refs or pins to clean
-		 * up in the sglist.
-		 */
-		if (data_size &&
-		    WARN_ON_ONCE(iov_iter_extract_will_pin(&rqst[i].rq_iter)))
-			return -EIO;
-
-		for (j = 0; j < rqst[i].rq_nvec; j++) {
-			struct kvec *iov = &rqst[i].rq_iov[j];
-
-			addr = (unsigned long)iov->iov_base + skip;
-			if (is_vmalloc_or_module_addr((void *)addr)) {
-				len = iov->iov_len - skip;
-				nents += DIV_ROUND_UP(offset_in_page(addr) + len,
-						      PAGE_SIZE);
-			} else {
-				nents++;
-			}
-			skip = 0;
-		}
-		if (data_size)
-			nents += iov_iter_npages(&rqst[i].rq_iter, INT_MAX);
-	}
-	nents += DIV_ROUND_UP(offset_in_page(sig) + SMB2_SIGNATURE_SIZE, PAGE_SIZE);
-	return nents;
-}
-
 /* We can not use the normal sg_set_buf() as we will sometimes pass a
  * stack object as buf.
  */
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index baa54e746f0f..5933757d0170 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -4186,94 +4186,11 @@ fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len,
 		get_random_bytes(&tr_hdr->Nonce, SMB3_AES_CCM_NONCE);
 }
 
-static void *smb2_aead_req_alloc(struct crypto_aead *tfm, const struct smb_rqst *rqst,
-				 int num_rqst, const u8 *sig, u8 **iv,
-				 struct aead_request **req, struct sg_table *sgt,
-				 unsigned int *num_sgs, size_t *sensitive_size)
-{
-	unsigned int req_size = sizeof(**req) + crypto_aead_reqsize(tfm);
-	unsigned int iv_size = crypto_aead_ivsize(tfm);
-	unsigned int len;
-	u8 *p;
-
-	*num_sgs = cifs_get_num_sgs(rqst, num_rqst, sig);
-	if (IS_ERR_VALUE((long)(int)*num_sgs))
-		return ERR_PTR(*num_sgs);
-
-	len = iv_size;
-	len += crypto_aead_alignmask(tfm) & ~(crypto_tfm_ctx_alignment() - 1);
-	len = ALIGN(len, crypto_tfm_ctx_alignment());
-	len += req_size;
-	len = ALIGN(len, __alignof__(struct scatterlist));
-	len += array_size(*num_sgs, sizeof(struct scatterlist));
-	*sensitive_size = len;
-
-	p = kvzalloc(len, GFP_NOFS);
-	if (!p)
-		return ERR_PTR(-ENOMEM);
-
-	*iv = (u8 *)PTR_ALIGN(p, crypto_aead_alignmask(tfm) + 1);
-	*req = (struct aead_request *)PTR_ALIGN(*iv + iv_size,
-						crypto_tfm_ctx_alignment());
-	sgt->sgl = (struct scatterlist *)PTR_ALIGN((u8 *)*req + req_size,
-						   __alignof__(struct scatterlist));
-	return p;
-}
-
-static void *smb2_get_aead_req(struct crypto_aead *tfm, struct smb_rqst *rqst,
-			       int num_rqst, const u8 *sig, u8 **iv,
-			       struct aead_request **req, struct scatterlist **sgl,
-			       size_t *sensitive_size)
-{
-	struct sg_table sgtable = {};
-	unsigned int skip, num_sgs, i, j;
-	ssize_t rc;
-	void *p;
-
-	p = smb2_aead_req_alloc(tfm, rqst, num_rqst, sig, iv, req, &sgtable,
-				&num_sgs, sensitive_size);
-	if (IS_ERR(p))
-		return ERR_CAST(p);
-
-	sg_init_marker(sgtable.sgl, num_sgs);
-
-	/*
-	 * The first rqst has a transform header where the
-	 * first 20 bytes are not part of the encrypted blob.
-	 */
-	skip = 20;
-
-	for (i = 0; i < num_rqst; i++) {
-		struct iov_iter *iter = &rqst[i].rq_iter;
-		size_t count = iov_iter_count(iter);
-
-		for (j = 0; j < rqst[i].rq_nvec; j++) {
-			cifs_sg_set_buf(&sgtable,
-					rqst[i].rq_iov[j].iov_base + skip,
-					rqst[i].rq_iov[j].iov_len - skip);
-
-			/* See the above comment on the 'skip' assignment */
-			skip = 0;
-		}
-		sgtable.orig_nents = sgtable.nents;
-
-		rc = extract_iter_to_sg(iter, count, &sgtable,
-					num_sgs - sgtable.nents, 0);
-		iov_iter_revert(iter, rc);
-		sgtable.orig_nents = sgtable.nents;
-	}
-
-	cifs_sg_set_buf(&sgtable, sig, SMB2_SIGNATURE_SIZE);
-	sg_mark_end(&sgtable.sgl[sgtable.nents - 1]);
-	*sgl = sgtable.sgl;
-	return p;
-}
-
 /*
  * Allocate the context info needed for the encryption operation, along with a
  * scatterlist to point to the buffer.
  */
-static void *smb2_aead_req_alloc_new(struct crypto_aead *tfm, const struct iov_iter *iter,
+static void *smb2_aead_req_alloc(struct crypto_aead *tfm, const struct iov_iter *iter,
 				 const u8 *sig, u8 **iv,
 				 struct aead_request **req, struct sg_table *sgt,
 				 unsigned int *num_sgs, size_t *sensitive_size)
@@ -4309,10 +4226,10 @@ static void *smb2_aead_req_alloc_new(struct crypto_aead *tfm, const struct iov_i
  * Set up for doing a crypto operation, building a scatterlist from the
  * supplied iterator.
  */
-static void *smb2_get_aead_req_new(struct crypto_aead *tfm, const struct iov_iter *iter,
-				   const u8 *sig, u8 **iv,
-				   struct aead_request **req, struct scatterlist **sgl,
-				   size_t *sensitive_size)
+static void *smb2_get_aead_req(struct crypto_aead *tfm, const struct iov_iter *iter,
+			       const u8 *sig, u8 **iv,
+			       struct aead_request **req, struct scatterlist **sgl,
+			       size_t *sensitive_size)
 {
 	struct sg_table sgtable = {};
 	struct iov_iter tmp = *iter;
@@ -4320,8 +4237,8 @@ static void *smb2_get_aead_req_new(struct crypto_aead *tfm, const struct iov_ite
 	ssize_t rc;
 	void *p;
 
-	p = smb2_aead_req_alloc_new(tfm, iter, sig, iv, req, &sgtable,
-				    &num_sgs, sensitive_size);
+	p = smb2_aead_req_alloc(tfm, iter, sig, iv, req, &sgtable,
+				&num_sgs, sensitive_size);
 	if (IS_ERR(p))
 		return ERR_CAST(p);
 
@@ -4412,8 +4329,8 @@ encrypt_message(struct TCP_Server_Info *server,
 		return rc;
 	}
 
-	creq = smb2_get_aead_req_new(tfm, iter, sign, &iv, &req, &sg,
-				     &sensitive_size);
+	creq = smb2_get_aead_req(tfm, iter, sign, &iv, &req, &sg,
+				 &sensitive_size);
 	if (IS_ERR(creq))
 		return PTR_ERR(creq);
 
@@ -4446,11 +4363,10 @@ encrypt_message(struct TCP_Server_Info *server,
  * untouched.
  */
 static int
-decrypt_message(struct TCP_Server_Info *server, int num_rqst,
-		struct smb_rqst *rqst, struct crypto_aead *tfm)
+decrypt_message(struct TCP_Server_Info *server,
+		struct smb2_transform_hdr *tr_hdr,
+		struct iov_iter *iter, struct crypto_aead *tfm)
 {
-	struct smb2_transform_hdr *tr_hdr =
-		(struct smb2_transform_hdr *)rqst[0].rq_iov[0].iov_base;
 	unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
 	int rc = 0;
 	struct scatterlist *sg;
@@ -4486,8 +4402,7 @@ decrypt_message(struct TCP_Server_Info *server, int num_rqst,
 		return rc;
 	}
 
-	creq = smb2_get_aead_req(tfm, rqst, num_rqst, sign, &iv, &req, &sg,
-				 &sensitive_size);
+	creq = smb2_get_aead_req(tfm, iter, sign, &iv, &req, &sg, &sensitive_size);
 	if (IS_ERR(creq))
 		return PTR_ERR(creq);
 
@@ -4546,24 +4461,10 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
 		 unsigned int buf_data_size, struct iov_iter *iter,
 		 bool is_offloaded)
 {
+	struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
 	struct crypto_aead *tfm;
-	struct smb_rqst rqst = {NULL};
-	struct kvec iov[2];
-	size_t iter_size = 0;
 	int rc;
 
-	iov[0].iov_base = buf;
-	iov[0].iov_len = sizeof(struct smb2_transform_hdr);
-	iov[1].iov_base = buf + sizeof(struct smb2_transform_hdr);
-	iov[1].iov_len = buf_data_size;
-
-	rqst.rq_iov = iov;
-	rqst.rq_nvec = 2;
-	if (iter) {
-		rqst.rq_iter = *iter;
-		iter_size = iov_iter_count(iter);
-	}
-
 	if (is_offloaded) {
 		if ((server->cipher_type == SMB2_ENCRYPTION_AES128_GCM) ||
 		    (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM))
@@ -4583,20 +4484,11 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
 		tfm = server->secmech.dec;
 	}
 
-	rc = decrypt_message(server, 1, &rqst, tfm);
+	rc = decrypt_message(server, tr_hdr, iter, tfm);
 	cifs_dbg(FYI, "Decrypt message returned %d\n", rc);
 
 	if (is_offloaded)
 		crypto_free_aead(tfm);
-
-	if (rc)
-		return rc;
-
-	memmove(buf, iov[1].iov_base, buf_data_size);
-
-	if (!is_offloaded)
-		server->total_read = buf_data_size + iter_size;
-
 	return rc;
 }
 


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 18/31] cifs: Pass smb_message structs down into the transport layer
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (16 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 17/31] cifs: Rework smb2 decryption David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-08 14:21   ` Enzo Matsumiya
  2025-08-06 20:36 ` [RFC PATCH 19/31] cifs: Clean up mid->callback_data and kill off mid->creator David Howells
                   ` (16 subsequent siblings)
  34 siblings, 1 reply; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Institute the creation of smb_message structs at the layer above the
transport layer and pass them down into the transport layer.  This replaces
the handling of mid_q_structs entirely within the transport layer.

This includes the following changes:

 (1) The smb_rqst struct is partially absorbed into the smb_message struct.
     Because the latter is on a linked list, the fixed-size arrays of
     requests can be got rid of - along with the COMPOUND_MAX-1 limit that
     gets imposed by the encryption code because it needs to steal a slot
     for the transform header.

 (2) Hand smb_message structs into the message sending code in the
     transport rather than allocating them (as it did for mid_q_structs) in
     the ->setup_request/->setup_async_request functions.

     For the moment compound_send_rcv() does the generation of smb_message
     structs, stringing them together before passing them down.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/cifsglob.h      |  38 ++--
 fs/smb/client/cifsproto.h     |  39 ++--
 fs/smb/client/cifssmb.c       |   1 -
 fs/smb/client/cifstransport.c |   8 +-
 fs/smb/client/compress.h      |   6 +-
 fs/smb/client/connect.c       |  24 +--
 fs/smb/client/netmisc.c       |   5 +-
 fs/smb/client/smb1ops.c       |  19 +-
 fs/smb/client/smb2misc.c      |  45 ++---
 fs/smb/client/smb2ops.c       |  40 +++--
 fs/smb/client/smb2pdu.c       | 212 +++++++++++++---------
 fs/smb/client/smb2proto.h     |  31 ++--
 fs/smb/client/smb2transport.c | 183 +++++++------------
 fs/smb/client/transport.c     | 325 +++++++++++++++++++---------------
 14 files changed, 501 insertions(+), 475 deletions(-)

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 1eed8a463b58..4173b87bdf0f 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -313,26 +313,24 @@ struct cifs_credits;
 
 struct smb_version_operations {
 	int (*send_cancel)(struct cifs_ses *ses, struct TCP_Server_Info *server,
-			   struct smb_rqst *rqst, struct smb_message *smb,
-			   unsigned int xid);
+			   struct smb_message *smb, unsigned int xid);
 	bool (*compare_fids)(struct cifsFileInfo *, struct cifsFileInfo *);
-	/* setup request: allocate mid, sign message */
-	struct smb_message *(*setup_request)(struct cifs_ses *,
-					     struct TCP_Server_Info *,
-					     struct smb_rqst *);
+	/* setup request: set up mid, sign message */
+	int (*setup_request)(struct cifs_ses *ses,
+			     struct TCP_Server_Info *server,
+			     struct smb_message *smb);
 	/* setup async request: allocate mid, sign message */
-	struct smb_message *(*setup_async_request)(struct TCP_Server_Info *,
-						   struct smb_rqst *);
+	int (*setup_async_request)(struct TCP_Server_Info *server, struct smb_message *smb);
 	/* check response: verify signature, map error */
-	int (*check_receive)(struct smb_message *, struct TCP_Server_Info *,
-			     bool);
+	int (*check_receive)(struct smb_message *smb, struct TCP_Server_Info *server,
+			     bool log_error);
 	void (*add_credits)(struct TCP_Server_Info *server,
 			    struct cifs_credits *credits,
 			    const int optype);
 	void (*set_credits)(struct TCP_Server_Info *, const int);
 	int * (*get_credits_field)(struct TCP_Server_Info *, const int);
 	unsigned int (*get_credits)(struct smb_message *smb);
-	__u64 (*get_next_mid)(struct TCP_Server_Info *);
+	__u64 (*get_next_mid)(struct TCP_Server_Info *server, unsigned int count);
 	void (*revert_current_mid)(struct TCP_Server_Info *server,
 				   const unsigned int val);
 	/* data offset from read response message */
@@ -537,8 +535,8 @@ struct smb_version_operations {
 	void (*new_lease_key)(struct cifs_fid *);
 	int (*generate_signingkey)(struct cifs_ses *ses,
 				   struct TCP_Server_Info *server);
-	int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *,
-				bool allocate_crypto);
+	int (*calc_signature)(struct smb_message *smb, struct TCP_Server_Info *server,
+			      bool allocate_crypto);
 	int (*set_integrity)(const unsigned int, struct cifs_tcon *tcon,
 			     struct cifsFileInfo *src_file);
 	int (*enum_snapshots)(const unsigned int xid, struct cifs_tcon *tcon,
@@ -594,10 +592,8 @@ struct smb_version_operations {
 	long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t,
 			  loff_t);
 	/* init transform (compress/encrypt) request */
-	int (*init_transform_rq)(struct TCP_Server_Info *server,
-				 int num_rqst, const struct smb_rqst *rqst,
-				 struct smb2_transform_hdr *tr_hdr,
-				 struct iov_iter *iter);
+	int (*init_transform_rq)(struct TCP_Server_Info *server, struct smb_message *head_smb,
+				 struct smb2_transform_hdr *tr_hdr, struct iov_iter *iter);
 	int (*is_transform_hdr)(void *buf);
 	int (*receive_transform)(struct TCP_Server_Info *,
 				 struct smb_message **smb, char **, int *);
@@ -945,16 +941,16 @@ adjust_credits(struct TCP_Server_Info *server, struct cifs_io_subrequest *subreq
 		server->ops->adjust_credits(server, subreq, trace) : 0;
 }
 
-static inline __le64
-get_next_mid64(struct TCP_Server_Info *server)
+static inline __u64
+get_next_mid64(struct TCP_Server_Info *server, unsigned int count)
 {
-	return cpu_to_le64(server->ops->get_next_mid(server));
+	return server->ops->get_next_mid(server, count);
 }
 
 static inline __le16
 get_next_mid(struct TCP_Server_Info *server)
 {
-	__u16 mid = server->ops->get_next_mid(server);
+	__u16 mid = server->ops->get_next_mid(server, 1);
 	/*
 	 * The value in the SMB header should be little endian for easy
 	 * on-the-wire decoding.
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index 76cb047b2715..fd5fe2723b4a 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -83,8 +83,6 @@ extern char *cifs_build_path_to_root(struct smb3_fs_context *ctx,
 				     int add_treename);
 extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
 char *cifs_build_devname(char *nodename, const char *prepath);
-extern void delete_mid(struct smb_message *smb);
-void __release_mid(struct smb_message *smb);
 extern void cifs_wake_up_task(struct smb_message *smb);
 extern int cifs_handle_standard(struct TCP_Server_Info *server,
 				struct smb_message *smb);
@@ -96,15 +94,16 @@ extern int cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs);
 extern bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs);
 extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
 extern int cifs_call_async(struct TCP_Server_Info *server,
-			struct smb_rqst *rqst,
-			mid_receive_t receive, mid_callback_t callback,
-			mid_handle_t handle, void *cbdata, const int flags,
-			const struct cifs_credits *exist_credits);
+			   struct smb_message *msg, const int flags,
+			   const struct cifs_credits *exist_credits);
 extern struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses);
 extern int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
 			  struct TCP_Server_Info *server,
 			  struct smb_rqst *rqst, int *resp_buf_type,
 			  const int flags, struct kvec *resp_iov);
+int smb_send_recv_messages(const unsigned int xid, struct cifs_ses *ses,
+			   struct TCP_Server_Info *server,
+			   struct smb_message *smb, const int flags);
 extern int compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 			      struct TCP_Server_Info *server,
 			      const int flags, const int num_rqst,
@@ -117,14 +116,14 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
 extern int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
 			    char *in_buf, int flags);
 int cifs_sync_mid_result(struct smb_message *smb, struct TCP_Server_Info *server);
-extern struct smb_message *cifs_setup_request(struct cifs_ses *,
-				struct TCP_Server_Info *,
-				struct smb_rqst *);
-extern struct smb_message *cifs_setup_async_request(struct TCP_Server_Info *,
-						struct smb_rqst *);
+int cifs_setup_request(struct cifs_ses *ses,
+		       struct TCP_Server_Info *server,
+		       struct smb_message *smb);
+int cifs_setup_async_request(struct TCP_Server_Info *server,
+			     struct smb_message *smb);
 int __smb_send_rqst(struct TCP_Server_Info *server, struct iov_iter *iter);
-extern int cifs_check_receive(struct smb_message *msg,
-			struct TCP_Server_Info *server, bool log_error);
+int cifs_check_receive(struct smb_message *smb,
+		       struct TCP_Server_Info *server, bool log_error);
 int wait_for_free_request(struct TCP_Server_Info *server, const int flags,
 			  unsigned int *instance);
 extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server,
@@ -133,11 +132,10 @@ extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server,
 
 static inline int
 send_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
-	    struct smb_rqst *rqst, struct smb_message *smb,
-	    unsigned int xid)
+	    struct smb_message *smb, unsigned int xid)
 {
 	return server->ops->send_cancel ?
-		server->ops->send_cancel(ses, server, rqst, smb, xid) : 0;
+		server->ops->send_cancel(ses, server, smb, xid) : 0;
 }
 
 int wait_for_response(struct TCP_Server_Info *server, struct smb_message *smb);
@@ -181,7 +179,8 @@ extern int decode_negTokenInit(unsigned char *security_blob, int length,
 extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len);
 extern void cifs_set_port(struct sockaddr *addr, const unsigned short int port);
 extern int map_smb_to_linux_error(char *buf, bool logErr);
-extern int map_and_check_smb_error(struct smb_message *smb, bool logErr);
+extern int map_and_check_smb_error(struct TCP_Server_Info *server,
+				   struct smb_message *smb, bool logErr);
 extern void header_assemble(struct smb_hdr *, char /* command */ ,
 			    const struct cifs_tcon *, int /* length of
 			    fixed section (word count) in two byte units */);
@@ -754,12 +753,6 @@ static inline bool dfs_src_pathname_equal(const char *s1, const char *s2)
 	return true;
 }
 
-static inline void release_mid(struct smb_message *smb)
-{
-	if (refcount_dec_and_test(&smb->ref))
-		__release_mid(smb);
-}
-
 static inline void cifs_free_open_info(struct cifs_open_info_data *data)
 {
 	kfree(data->symlink_target);
diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
index a7a9f63f8c21..789ce76e3154 100644
--- a/fs/smb/client/cifssmb.c
+++ b/fs/smb/client/cifssmb.c
@@ -582,7 +582,6 @@ cifs_echo_callback(struct smb_message *smb)
 	struct TCP_Server_Info *server = smb->callback_data;
 	struct cifs_credits credits = { .value = 1, .instance = 0 };
 
-	release_mid(smb);
 	add_credits(server, &credits, CIFS_ECHO_OP);
 }
 
diff --git a/fs/smb/client/cifstransport.c b/fs/smb/client/cifstransport.c
index a2db95faeb17..8cdb9252a37e 100644
--- a/fs/smb/client/cifstransport.c
+++ b/fs/smb/client/cifstransport.c
@@ -101,8 +101,8 @@ static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
 	return 0;
 }
 
-struct smb_message *
-cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
+int
+cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_message *smb)
 {
 	int rc;
 	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
@@ -181,9 +181,9 @@ cifs_check_receive(struct smb_message *smb, struct TCP_Server_Info *server,
 	return map_and_check_smb_error(smb, log_error);
 }
 
-struct smb_message *
+int
 cifs_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *ignored,
-		   struct smb_rqst *rqst)
+		   struct smb_message *smb)
 {
 	int rc;
 	struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
diff --git a/fs/smb/client/compress.h b/fs/smb/client/compress.h
index f3ed1d3e52fb..472b0e8b2f45 100644
--- a/fs/smb/client/compress.h
+++ b/fs/smb/client/compress.h
@@ -35,7 +35,7 @@ int smb_compress(struct TCP_Server_Info *server, struct smb_rqst *rq, compress_s
  * should_compress() - Determines if a request (write) or the response to a
  *		       request (read) should be compressed.
  * @tcon: tcon of the request is being sent to
- * @rqst: request to evaluate
+ * @smb: request to evaluate
  *
  * Return: true iff:
  * - compression was successfully negotiated with server
@@ -46,7 +46,7 @@ int smb_compress(struct TCP_Server_Info *server, struct smb_rqst *rq, compress_s
  *
  * Return false otherwise.
  */
-bool should_compress(const struct cifs_tcon *tcon, const struct smb_rqst *rq);
+bool should_compress(const struct cifs_tcon *tcon, const struct smb_message *smb);
 
 /**
  * smb_compress_alg_valid() - Validate a compression algorithm.
@@ -77,7 +77,7 @@ static inline int smb_compress(void *unused1, void *unused2, void *unused3)
 	return -EOPNOTSUPP;
 }
 
-static inline bool should_compress(void *unused1, void *unused2)
+static inline bool should_compress(const struct cifs_tcon *tcon, const struct smb_message *smb)
 {
 	return false;
 }
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index d26e2a6d7674..7a64b070f74b 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -323,7 +323,6 @@ cifs_abort_connection(struct TCP_Server_Info *server)
 	cifs_dbg(FYI, "%s: moving mids to private list\n", __func__);
 	spin_lock(&server->mid_lock);
 	list_for_each_entry_safe(smb, nsmb, &server->pending_mid_q, qhead) {
-		smb_get_message(smb);
 		if (smb->mid_state == MID_REQUEST_SUBMITTED)
 			smb->mid_state = MID_RETRY_NEEDED;
 		list_move(&smb->qhead, &retry_list);
@@ -336,7 +335,7 @@ cifs_abort_connection(struct TCP_Server_Info *server)
 	list_for_each_entry_safe(smb, nsmb, &retry_list, qhead) {
 		list_del_init(&smb->qhead);
 		smb->callback(smb);
-		release_mid(smb);
+		smb_put_message(smb);
 	}
 
 	if (cifs_rdma_enabled(server)) {
@@ -871,9 +870,9 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
 		    server->tcpStatus == CifsInNegotiate &&
 		    !server->with_rfc1001 &&
 		    server->rfc1001_sessinit != 0) {
-			int rc, mid_rc;
 			struct smb_message *smb, *nsmb;
 			LIST_HEAD(dispose_list);
+			int rc, mid_rc;
 
 			cifs_dbg(FYI, "RFC 1002 negative session response during SMB Negotiate, retrying with NetBIOS session\n");
 
@@ -886,7 +885,6 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
 			 */
 			spin_lock(&server->mid_lock);
 			list_for_each_entry_safe(smb, nsmb, &server->pending_mid_q, qhead) {
-				smb_get_message(smb);
 				list_move(&smb->qhead, &dispose_list);
 				smb->mid_flags |= MID_DELETED;
 			}
@@ -920,7 +918,7 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
 				smb->mid_rc = mid_rc;
 				smb->mid_state = MID_RC;
 				smb->callback(smb);
-				release_mid(smb);
+				smb_put_message(smb);
 			}
 
 			/*
@@ -1097,15 +1095,12 @@ clean_demultiplex_info(struct TCP_Server_Info *server)
 	}
 
 	if (!list_empty(&server->pending_mid_q)) {
-		struct smb_message *smb;
-		struct list_head *tmp, *tmp2;
+		struct smb_message *smb, *smb2;
 		LIST_HEAD(dispose_list);
 
 		spin_lock(&server->mid_lock);
-		list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
-			smb = list_entry(tmp, struct smb_message, qhead);
+		list_for_each_entry_safe(smb, smb2, &server->pending_mid_q, qhead) {
 			cifs_dbg(FYI, "Clearing mid %llu\n", smb->mid);
-			smb_get_message(smb);
 			smb->mid_state = MID_SHUTDOWN;
 			list_move(&smb->qhead, &dispose_list);
 			smb->mid_flags |= MID_DELETED;
@@ -1113,12 +1108,11 @@ clean_demultiplex_info(struct TCP_Server_Info *server)
 		spin_unlock(&server->mid_lock);
 
 		/* now walk dispose list and issue callbacks */
-		list_for_each_safe(tmp, tmp2, &dispose_list) {
-			smb = list_entry(tmp, struct smb_message, qhead);
+		list_for_each_entry_safe(smb, smb2, &dispose_list, qhead) {
 			cifs_dbg(FYI, "Callback mid %llu\n", smb->mid);
 			list_del_init(&smb->qhead);
 			smb->callback(smb);
-			release_mid(smb);
+			smb_put_message(smb);
 		}
 		/* 1/8th of sec is more than enough time for them to exit */
 		msleep(125);
@@ -1361,7 +1355,7 @@ cifs_demultiplex_thread(void *p)
 		if (length < 0) {
 			for (i = 0; i < num_smbs; i++)
 				if (smbs[i])
-					release_mid(smbs[i]);
+					smb_put_message(smbs[i]);
 			continue;
 		}
 
@@ -1396,7 +1390,7 @@ cifs_demultiplex_thread(void *p)
 				if (!smbs[i]->multiRsp || smbs[i]->multiEnd)
 					smbs[i]->callback(smbs[i]);
 
-				release_mid(smbs[i]);
+				smb_put_message(smbs[i]);
 			} else if (server->ops->is_oplock_break &&
 				   server->ops->is_oplock_break(bufs[i],
 								server)) {
diff --git a/fs/smb/client/netmisc.c b/fs/smb/client/netmisc.c
index b34d2b91cf5a..89bd1ca9e3ce 100644
--- a/fs/smb/client/netmisc.c
+++ b/fs/smb/client/netmisc.c
@@ -889,7 +889,8 @@ map_smb_to_linux_error(char *buf, bool logErr)
 }
 
 int
-map_and_check_smb_error(struct smb_message *smb, bool logErr)
+map_and_check_smb_error(struct TCP_Server_Info *server,
+			struct smb_message *smb, bool logErr)
 {
 	int rc;
 	struct smb_hdr *rhdr = (struct smb_hdr *)smb->resp_buf;
@@ -904,7 +905,7 @@ map_and_check_smb_error(struct smb_message *smb, bool logErr)
 		if (class == ERRSRV && code == ERRbaduid) {
 			cifs_dbg(FYI, "Server returned 0x%x, reconnecting session...\n",
 				code);
-			cifs_signal_cifsd_for_reconnect(smb->server, false);
+			cifs_signal_cifsd_for_reconnect(server, false);
 		}
 	}
 
diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
index 185210b7fd03..f179f1b4c0c1 100644
--- a/fs/smb/client/smb1ops.c
+++ b/fs/smb/client/smb1ops.c
@@ -29,11 +29,10 @@
  */
 static int
 send_nt_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
-	       struct smb_rqst *rqst, struct smb_message *smb,
-	       unsigned int xid)
+	       struct smb_message *smb, unsigned int xid)
 {
 	struct iov_iter iter;
-	struct smb_hdr *in_buf = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
+	struct smb_hdr *in_buf = (struct smb_hdr *)smb->rqst.rq_iov[0].iov_base;
 	struct kvec iov[1];
 	struct smb_rqst crqst = { .rq_iov = iov, .rq_nvec = 1 };
 	int rc = 0;
@@ -80,10 +79,9 @@ send_nt_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
  */
 static int
 send_lock_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
-		 struct smb_rqst *rqst, struct smb_message *smb,
-		 unsigned int xid)
+		 struct smb_message *smb, unsigned int xid)
 {
-	struct smb_hdr *in_buf = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
+	struct smb_hdr *in_buf = (struct smb_hdr *)smb->rqst.rq_iov[0].iov_base;
 	LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
 	int rc;
 
@@ -104,12 +102,11 @@ send_lock_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
 }
 
 static int cifs_send_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
-			    struct smb_rqst *rqst, struct smb_message *smb,
-			    unsigned int xid)
+			    struct smb_message *smb, unsigned int xid)
 {
 	if (smb->sr_flags & CIFS_WINDOWS_LOCK)
-		return send_lock_cancel(ses, server, rqst, smb, xid);
-	return send_nt_cancel(ses, server, rqst, smb, xid);
+		return send_lock_cancel(ses, server, smb, xid);
+	return send_nt_cancel(ses, server, smb, xid);
 }
 
 static bool
@@ -210,7 +207,7 @@ cifs_get_credits(struct smb_message *smb)
  * so many threads being in the vfs at one time.
  */
 static __u64
-cifs_get_next_mid(struct TCP_Server_Info *server)
+cifs_get_next_mid(struct TCP_Server_Info *server, unsigned int count)
 {
 	__u64 mid = 0;
 	__u16 last_mid, cur_mid;
diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c
index b8e3fe26d658..122e9fe78e23 100644
--- a/fs/smb/client/smb2misc.c
+++ b/fs/smb/client/smb2misc.c
@@ -866,27 +866,22 @@ smb2_handle_cancelled_mid(struct smb_message *smb, struct TCP_Server_Info *serve
 }
 
 /**
- * smb311_update_preauth_hash - update @ses hash with the packet data in @iov
- *
- * Assumes @iov does not contain the rfc1002 length and iov[0] has the
- * SMB2 header.
- *
+ * smb311_update_preauth_hash - update @ses hash from the message
  * @ses:	server session structure
  * @server:	pointer to server info
- * @iov:	array containing the SMB request we will send to the server
- * @nvec:	number of array entries for the iov
+ * @smb:	the SMB request we will send to the server
+ * @hash_resp:	T if we're hashing a response
  */
 int
 smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *server,
-			   struct kvec *iov, int nvec)
+			   struct smb_message *smb, bool hash_resp)
 {
-	int i, rc;
-	struct smb2_hdr *hdr;
 	struct shash_desc *sha512 = NULL;
+	struct kvec *iov;
+	int i, rc, ioc;
 
-	hdr = (struct smb2_hdr *)iov[0].iov_base;
 	/* neg prot are always taken */
-	if (le16_to_cpu(hdr->Command) == SMB2_NEGOTIATE)
+	if (smb->command_id == SMB2_NEGOTIATE)
 		goto ok;
 
 	/*
@@ -897,15 +892,16 @@ smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *server,
 	if (server->dialect != SMB311_PROT_ID)
 		return 0;
 
-	if (le16_to_cpu(hdr->Command) != SMB2_SESSION_SETUP)
+	if (smb->command_id != SMB2_SESSION_SETUP)
 		return 0;
 
 	/* skip last sess setup response */
-	if ((hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR)
-	    && (hdr->Status == NT_STATUS_OK
-		|| (hdr->Status !=
-		    cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))))
-		return 0;
+	if (hash_resp) {
+		struct smb2_hdr *resp = smb->resp_iov->iov_base;
+		if (resp->Status == NT_STATUS_OK ||
+		    resp->Status != cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
+			return 0;
+	}
 
 ok:
 	rc = smb311_crypto_shash_allocate(server);
@@ -926,8 +922,17 @@ smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *server,
 		return rc;
 	}
 
-	for (i = 0; i < nvec; i++) {
-		rc = crypto_shash_update(sha512, iov[i].iov_base, iov[i].iov_len);
+	if (hash_resp) {
+		ioc = 1;
+		iov = smb->resp_iov;
+	} else {
+		ioc = smb->rqst.rq_nvec;
+		iov = smb->rqst.rq_iov;
+	}
+
+	for (i = 0; i < ioc; i++) {
+		rc = crypto_shash_update(sha512, iov[i].iov_base,
+					 iov[i].iov_len);
 		if (rc) {
 			cifs_dbg(VFS, "%s: Could not update sha512 shash\n",
 				 __func__);
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 5933757d0170..835a76169d40 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -370,12 +370,13 @@ smb2_adjust_credits(struct TCP_Server_Info *server,
 }
 
 static __u64
-smb2_get_next_mid(struct TCP_Server_Info *server)
+smb2_get_next_mid(struct TCP_Server_Info *server, unsigned int count)
 {
 	__u64 mid;
 	/* for SMB2 we need the current value */
 	spin_lock(&server->mid_lock);
-	mid = server->CurrentMid++;
+	mid = server->CurrentMid;
+	server->CurrentMid = mid + umax(count, 1);
 	spin_unlock(&server->mid_lock);
 	return mid;
 }
@@ -407,7 +408,6 @@ __smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue)
 		if ((smb->mid == wire_mid) &&
 		    (smb->mid_state == MID_REQUEST_SUBMITTED) &&
 		    (smb->command_id == command)) {
-			smb_get_message(smb);
 			if (dequeue) {
 				list_del_init(&smb->qhead);
 				smb->mid_flags |= MID_DELETED;
@@ -4168,10 +4168,12 @@ smb2_dir_needs_close(struct cifsFileInfo *cfile)
 }
 
 static void
-fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len,
-		   const struct smb_rqst *old_rq, __le16 cipher_type)
+fill_transform_hdr(struct smb2_transform_hdr *tr_hdr,
+		   struct smb_message *head_smb,
+		   unsigned int orig_len,
+		   __le16 cipher_type)
 {
-	struct smb2_hdr *shdr = (struct smb2_hdr *)old_rq->rq_iov[0].iov_base;
+	struct smb2_hdr *shdr = head_smb->request;
 
 	*tr_hdr = (struct smb2_transform_hdr){
 		.ProtocolId		= SMB2_TRANSFORM_PROTO_NUM,
@@ -4422,7 +4424,6 @@ decrypt_message(struct TCP_Server_Info *server,
 	aead_request_set_ad(req, assoc_data_len);
 
 	rc = crypto_aead_decrypt(req);
-
 	kvfree_sensitive(creq, sensitive_size);
 	return rc;
 }
@@ -4434,13 +4435,14 @@ decrypt_message(struct TCP_Server_Info *server,
  */
 static int
 smb3_init_transform_rq(struct TCP_Server_Info *server,
-		       int num_rqst, const struct smb_rqst *rqst,
+		       struct smb_message *head_smb,
 		       struct smb2_transform_hdr *tr_hdr,
 		       struct iov_iter *iter)
+
 {
 	int rc;
 
-	fill_transform_hdr(tr_hdr, iov_iter_count(iter), rqst,
+	fill_transform_hdr(tr_hdr, head_smb, iov_iter_count(iter),
 			   server->cipher_type);
 
 	rc = encrypt_message(server, tr_hdr, iter, server->secmech.enc);
@@ -4689,9 +4691,9 @@ static void smb2_decrypt_offload(struct work_struct *work)
 
 	dw->server->lstrp = jiffies;
 	smb = smb2_find_dequeue_mid(dw->server, dw->buf);
-	if (smb == NULL)
+	if (smb == NULL) {
 		cifs_dbg(FYI, "mid not found\n");
-	else {
+	} else {
 		smb->decrypted = true;
 		rc = handle_read_data(dw->server, smb, dw->buf,
 				      dw->server->vals->read_rsp_size,
@@ -4724,7 +4726,7 @@ static void smb2_decrypt_offload(struct work_struct *work)
 				spin_unlock(&dw->server->srv_lock);
 			}
 		}
-		release_mid(smb);
+		smb_put_message(smb);
 	}
 
 free_pages:
@@ -4735,9 +4737,12 @@ static void smb2_decrypt_offload(struct work_struct *work)
 
 
 static int
-receive_encrypted_read(struct TCP_Server_Info *server, struct smb_message **smb,
+receive_encrypted_read(struct TCP_Server_Info *server, struct smb_message **mid,
 		       int *num_mids)
 {
+	WARN_ON_ONCE(1);
+	return -ENOANO; // TODO
+#if 0
 	char *buf = server->smallbuf;
 	struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
 	struct iov_iter iter;
@@ -4753,8 +4758,8 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct smb_message **smb,
 	dw->server = server;
 
 	*num_mids = 1;
-	len = min_t(unsigned int, buflen, server->vals->read_rsp_size +
-		sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + 1;
+	len = umin(buflen, server->vals->read_rsp_size +
+		   sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + 1;
 
 	rc = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1, len);
 	if (rc < 0)
@@ -4836,6 +4841,7 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct smb_message **smb,
 discard_data:
 	cifs_discard_remaining_data(server);
 	goto free_pages;
+#endif
 }
 
 static int
@@ -4893,9 +4899,9 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
 	}
 
 	smb = smb2_find_mid(server, buf);
-	if (smb == NULL)
+	if (smb == NULL) {
 		cifs_dbg(FYI, "mid not found\n");
-	else {
+	} else {
 		cifs_dbg(FYI, "mid found\n");
 		smb->decrypted = true;
 		smb->resp_buf_size = server->pdu_size;
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 8554a4aa001d..6b94da4c1149 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -4106,7 +4106,6 @@ smb2_echo_callback(struct smb_message *smb)
 		credits.instance = server->reconnect_instance;
 	}
 
-	release_mid(smb);
 	add_credits(server, &credits, CIFS_ECHO_OP);
 }
 
@@ -4262,10 +4261,9 @@ int
 SMB2_echo(struct TCP_Server_Info *server)
 {
 	struct smb2_echo_req *req;
+	struct smb_message *smb;
 	int rc = 0;
 	struct kvec iov[1];
-	struct smb_rqst rqst = { .rq_iov = iov,
-				 .rq_nvec = 1 };
 	unsigned int total_len;
 
 	cifs_dbg(FYI, "In echo request for conn_id %lld\n", server->conn_id);
@@ -4280,22 +4278,36 @@ SMB2_echo(struct TCP_Server_Info *server)
 	}
 	spin_unlock(&server->srv_lock);
 
+	smb = smb_message_alloc(SMB2_ECHO, GFP_NOFS);
+	if (!smb)
+		return -ENOMEM;
+
 	rc = smb2_plain_req_init(SMB2_ECHO, NULL, server,
 				 (void **)&req, &total_len);
-	if (rc)
+	if (rc) {
+		mempool_free(smb, &smb_message_pool);
 		return rc;
-
-	req->hdr.CreditRequest = cpu_to_le16(1);
+	}
 
 	iov[0].iov_len = total_len;
 	iov[0].iov_base = (char *)req;
 
-	rc = cifs_call_async(server, &rqst, NULL, smb2_echo_callback, NULL,
-			     server, CIFS_ECHO_OP, NULL);
+	smb->rqst.rq_iov	= iov;
+	smb->rqst.rq_nvec	= 1;
+	smb->command_id		= SMB2_ECHO;
+	smb->request		= req;
+	smb->total_len		= total_len;
+	smb->callback		= smb2_echo_callback;
+	smb->callback_data	= server;
+
+	req->hdr.CreditRequest = cpu_to_le16(1);
+
+	rc = cifs_call_async(server, smb, CIFS_ECHO_OP, NULL);
 	if (rc)
 		cifs_dbg(FYI, "Echo request failed: %d\n", rc);
 
 	cifs_small_buf_release(req);
+	smb_put_message(smb);
 	return rc;
 }
 
@@ -4559,7 +4571,7 @@ smb2_readv_callback(struct smb_message *smb)
 			int rc;
 
 			iov_iter_truncate(&rqst.rq_iter, rdata->got_bytes);
-			rc = smb2_verify_signature(&rqst, server);
+			rc = smb2_verify_signature(smb, server);
 			if (rc)
 				cifs_tcon_dbg(VFS, "SMB signature verification returned error = %d\n",
 					 rc);
@@ -4645,7 +4657,6 @@ smb2_readv_callback(struct smb_message *smb)
 	rdata->subreq.transferred += rdata->got_bytes;
 	trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_progress);
 	netfs_read_subreq_terminated(&rdata->subreq);
-	release_mid(smb);
 	trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0,
 			      server->credits, server->in_flight,
 			      credits.value, cifs_trace_rw_credits_read_response_add);
@@ -4656,46 +4667,62 @@ smb2_readv_callback(struct smb_message *smb)
 int
 smb2_async_readv(struct cifs_io_subrequest *rdata)
 {
-	int rc, flags = 0;
-	char *buf;
 	struct netfs_io_subrequest *subreq = &rdata->subreq;
-	struct smb2_hdr *shdr;
-	struct cifs_io_parms io_parms;
-	struct smb_rqst rqst = { .rq_iov = rdata->iov,
-				 .rq_nvec = 1 };
 	struct TCP_Server_Info *server;
+	struct smb_message *smb;
+	struct smb2_hdr *shdr;
 	struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink);
 	unsigned int total_len;
+	void *buf;
 	int credit_request;
+	int rc, flags = 0;
 
 	cifs_dbg(FYI, "%s: offset=%llu bytes=%zu\n",
 		 __func__, subreq->start, subreq->len);
 
-	if (!rdata->server)
-		rdata->server = cifs_pick_channel(tcon->ses);
+	server = rdata->server;
+	if (!server)
+		server = rdata->server = cifs_pick_channel(tcon->ses);
+
+	struct cifs_io_parms io_parms = {
+		.tcon		= tlink_tcon(rdata->req->cfile->tlink),
+		.server		= server,
+		.offset		= subreq->start + subreq->transferred,
+		.length		= subreq->len   - subreq->transferred,
+		.persistent_fid	= rdata->req->cfile->fid.persistent_fid,
+		.volatile_fid	= rdata->req->cfile->fid.volatile_fid,
+		.pid		= rdata->req->pid,
+	};
 
-	io_parms.tcon = tlink_tcon(rdata->req->cfile->tlink);
-	io_parms.server = server = rdata->server;
-	io_parms.offset = subreq->start + subreq->transferred;
-	io_parms.length = subreq->len   - subreq->transferred;
-	io_parms.persistent_fid = rdata->req->cfile->fid.persistent_fid;
-	io_parms.volatile_fid = rdata->req->cfile->fid.volatile_fid;
-	io_parms.pid = rdata->req->pid;
+	smb = smb_message_alloc(SMB2_READ, GFP_NOFS);
+	if (!smb)
+		return -ENOMEM;
 
-	rc = smb2_new_read_req(
-		(void **) &buf, &total_len, &io_parms, rdata, 0, 0);
-	if (rc)
+	rc = smb2_new_read_req(&buf, &total_len, &io_parms, rdata, 0, 0);
+	if (rc) {
+		mempool_free(smb, &smb_message_pool);
 		return rc;
+	}
 
 	if (smb3_encryption_required(io_parms.tcon))
 		flags |= CIFS_TRANSFORM_REQ;
 
-	rdata->iov[0].iov_base = buf;
-	rdata->iov[0].iov_len = total_len;
-	rdata->got_bytes = 0;
-	rdata->result = 0;
+	rdata->iov[0].iov_base	= buf;
+	rdata->iov[0].iov_len	= total_len;
+	rdata->got_bytes	= 0;
+	rdata->result		= 0;
+
+	smb->rqst.rq_iov	= rdata->iov;
+	smb->rqst.rq_nvec	= 1;
+	smb->command_id		= SMB2_READ;
+	smb->request		= buf;
+	smb->total_len		= total_len;
+	smb->receive		= cifs_readv_receive;
+	smb->handle		= smb3_handle_read_data;
+	smb->callback		= smb2_readv_callback;
+	smb->callback_data	= rdata;
 
-	shdr = (struct smb2_hdr *)buf;
+	shdr = (struct smb2_hdr *)smb->request;
 
 	if (rdata->credits.value > 0) {
 		shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(io_parms.length,
@@ -4715,10 +4742,7 @@ smb2_async_readv(struct cifs_io_subrequest *rdata)
 		flags |= CIFS_HAS_CREDITS;
 	}
 
-	rc = cifs_call_async(server, &rqst,
-			     cifs_readv_receive, smb2_readv_callback,
-			     smb3_handle_read_data, rdata, flags,
-			     &rdata->credits);
+	rc = cifs_call_async(server, smb, flags, &rdata->credits);
 	if (rc) {
 		cifs_stats_fail_inc(io_parms.tcon, SMB2_READ);
 		trace_smb3_read_err(rdata->rreq->debug_id,
@@ -4732,6 +4756,7 @@ smb2_async_readv(struct cifs_io_subrequest *rdata)
 
 async_readv_out:
 	cifs_small_buf_release(buf);
+	smb_put_message(smb);
 	return rc;
 }
 
@@ -4931,7 +4956,6 @@ smb2_writev_callback(struct smb_message *smb)
 			      0, cifs_trace_rw_credits_write_response_clear);
 	wdata->credits.value = 0;
 	cifs_write_subrequest_terminated(wdata, result ?: written);
-	release_mid(smb);
 	trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0,
 			      server->credits, server->in_flight,
 			      credits.value, cifs_trace_rw_credits_write_response_add);
@@ -4942,77 +4966,90 @@ smb2_writev_callback(struct smb_message *smb)
 void
 smb2_async_writev(struct cifs_io_subrequest *wdata)
 {
-	int rc = -EACCES, flags = 0;
 	struct smb2_write_req *req = NULL;
+	struct smb_message *smb;
 	struct smb2_hdr *shdr;
 	struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink);
 	struct TCP_Server_Info *server = wdata->server;
 	struct kvec iov[1];
-	struct smb_rqst rqst = { };
 	unsigned int total_len, xid = wdata->xid;
-	struct cifs_io_parms _io_parms;
-	struct cifs_io_parms *io_parms = NULL;
 	int credit_request;
+	int rc = -EACCES, flags = 0;
 
 	/*
 	 * in future we may get cifs_io_parms passed in from the caller,
 	 * but for now we construct it here...
 	 */
-	_io_parms = (struct cifs_io_parms) {
-		.tcon = tcon,
-		.server = server,
-		.offset = wdata->subreq.start,
-		.length = wdata->subreq.len,
-		.persistent_fid = wdata->req->cfile->fid.persistent_fid,
-		.volatile_fid = wdata->req->cfile->fid.volatile_fid,
-		.pid = wdata->req->pid,
+	struct cifs_io_parms io_parms = {
+		.tcon		= tcon,
+		.server		= server,
+		.offset		= wdata->subreq.start,
+		.length		= wdata->subreq.len,
+		.persistent_fid	= wdata->req->cfile->fid.persistent_fid,
+		.volatile_fid	= wdata->req->cfile->fid.volatile_fid,
+		.pid		= wdata->req->pid,
 	};
-	io_parms = &_io_parms;
+
+	smb = smb_message_alloc(SMB2_WRITE, GFP_NOFS);
+	if (!smb) {
+		rc = -ENOMEM;
+		goto out;
+	}
 
 	rc = smb2_plain_req_init(SMB2_WRITE, tcon, server,
 				 (void **) &req, &total_len);
-	if (rc)
+	if (rc) {
+		mempool_free(smb, &smb_message_pool);
 		goto out;
+	}
 
-	rqst.rq_iov = iov;
-	rqst.rq_iter = wdata->subreq.io_iter;
+	smb->rqst.rq_iov = iov;
+	smb->rqst.rq_iter = wdata->subreq.io_iter;
+
+	smb->rqst.rq_iov[0].iov_len = total_len - 1;
+	smb->rqst.rq_iov[0].iov_base = (char *)req;
+	smb->rqst.rq_nvec += 1;
 
-	rqst.rq_iov[0].iov_len = total_len - 1;
-	rqst.rq_iov[0].iov_base = (char *)req;
-	rqst.rq_nvec += 1;
+	smb->rqst.rq_iov	= wdata->iov;
+	smb->rqst.rq_nvec	= 1;
+	smb->command_id		= SMB2_WRITE;
+	smb->request		= req;
+	smb->total_len		= total_len;
+	smb->callback		= smb2_writev_callback;
+	smb->callback_data	= wdata;
 
 	if (smb3_encryption_required(tcon))
 		flags |= CIFS_TRANSFORM_REQ;
 
 	shdr = (struct smb2_hdr *)req;
-	shdr->Id.SyncId.ProcessId = cpu_to_le32(io_parms->pid);
-
-	req->PersistentFileId = io_parms->persistent_fid;
-	req->VolatileFileId = io_parms->volatile_fid;
-	req->WriteChannelInfoOffset = 0;
-	req->WriteChannelInfoLength = 0;
-	req->Channel = SMB2_CHANNEL_NONE;
-	req->Length = cpu_to_le32(io_parms->length);
-	req->Offset = cpu_to_le64(io_parms->offset);
-	req->DataOffset = cpu_to_le16(
-				offsetof(struct smb2_write_req, Buffer));
-	req->RemainingBytes = 0;
+	shdr->Id.SyncId.ProcessId = cpu_to_le32(io_parms.pid);
+
+	req->PersistentFileId		= io_parms.persistent_fid;
+	req->VolatileFileId		= io_parms.volatile_fid;
+	req->WriteChannelInfoOffset	= 0;
+	req->WriteChannelInfoLength	= 0;
+	req->Channel			= SMB2_CHANNEL_NONE;
+	req->Length			= cpu_to_le32(io_parms.length);
+	req->Offset			= cpu_to_le64(io_parms.offset);
+	req->DataOffset			=
+		cpu_to_le16(offsetof(struct smb2_write_req, Buffer));
+	req->RemainingBytes		= 0;
 
 	trace_smb3_write_enter(wdata->rreq->debug_id,
 			       wdata->subreq.debug_index,
 			       wdata->xid,
-			       io_parms->persistent_fid,
-			       io_parms->tcon->tid,
-			       io_parms->tcon->ses->Suid,
-			       io_parms->offset,
-			       io_parms->length);
+			       io_parms.persistent_fid,
+			       io_parms.tcon->tid,
+			       io_parms.tcon->ses->Suid,
+			       io_parms.offset,
+			       io_parms.length);
 
 #ifdef CONFIG_CIFS_SMB_DIRECT
 	/*
 	 * If we want to do a server RDMA read, fill in and append
 	 * smbdirect_buffer_descriptor_v1 to the end of write request
 	 */
-	if (smb3_use_rdma_offload(io_parms)) {
+	if (smb3_use_rdma_offload(&io_parms)) {
 		struct smbdirect_buffer_descriptor_v1 *v1;
 		bool need_invalidate = server->dialect == SMB30_PROT_ID;
 
@@ -5038,21 +5075,21 @@ smb2_async_writev(struct cifs_io_subrequest *wdata)
 		v1->token = cpu_to_le32(wdata->mr->mr->rkey);
 		v1->length = cpu_to_le32(wdata->mr->mr->length);
 
-		rqst.rq_iov[0].iov_len += sizeof(*v1);
+		smb->rqst.rq_iov[0].iov_len += sizeof(*v1);
 
 		/*
 		 * We keep wdata->subreq.io_iter,
 		 * but we have to truncate rqst.rq_iter
 		 */
-		iov_iter_truncate(&rqst.rq_iter, 0);
+		iov_iter_truncate(&smb->rqst.rq_iter, 0);
 	}
 #endif
 
 	if (wdata->subreq.retry_count > 0)
-		smb2_set_replay(server, &rqst);
+		smb2_set_replay(server, &smb->rqst);
 
 	cifs_dbg(FYI, "async write at %llu %u bytes iter=%zx\n",
-		 io_parms->offset, io_parms->length, iov_iter_count(&wdata->subreq.io_iter));
+		 io_parms.offset, io_parms.length, iov_iter_count(&wdata->subreq.io_iter));
 
 	if (wdata->credits.value > 0) {
 		shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->subreq.len,
@@ -5073,27 +5110,28 @@ smb2_async_writev(struct cifs_io_subrequest *wdata)
 	}
 
 	/* XXX: compression + encryption is unsupported for now */
-	if (((flags & CIFS_TRANSFORM_REQ) != CIFS_TRANSFORM_REQ) && should_compress(tcon, &rqst))
+	if (((flags & CIFS_TRANSFORM_REQ) != CIFS_TRANSFORM_REQ) &&
+	    should_compress(tcon, smb))
 		flags |= CIFS_COMPRESS_REQ;
 
-	rc = cifs_call_async(server, &rqst, NULL, smb2_writev_callback, NULL,
-			     wdata, flags, &wdata->credits);
+	rc = cifs_call_async(server, smb, flags, &wdata->credits);
 	/* Can't touch wdata if rc == 0 */
 	if (rc) {
 		trace_smb3_write_err(wdata->rreq->debug_id,
 				     wdata->subreq.debug_index,
 				     xid,
-				     io_parms->persistent_fid,
-				     io_parms->tcon->tid,
-				     io_parms->tcon->ses->Suid,
-				     io_parms->offset,
-				     io_parms->length,
+				     io_parms.persistent_fid,
+				     io_parms.tcon->tid,
+				     io_parms.tcon->ses->Suid,
+				     io_parms.offset,
+				     io_parms.length,
 				     rc);
 		cifs_stats_fail_inc(tcon, SMB2_WRITE);
 	}
 
 async_writev_out:
 	cifs_small_buf_release(req);
+	smb_put_message(smb);
 out:
 	if (rc) {
 		trace_smb3_rw_credits(wdata->rreq->debug_id,
diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h
index 6f1ce0399334..3018b171c6de 100644
--- a/fs/smb/client/smb2proto.h
+++ b/fs/smb/client/smb2proto.h
@@ -29,22 +29,20 @@ extern char *smb2_get_data_area_len(int *off, int *len,
 extern __le16 *cifs_convert_path_to_utf16(const char *from,
 					  struct cifs_sb_info *cifs_sb);
 
-extern int smb2_verify_signature(struct smb_rqst *, struct TCP_Server_Info *);
-extern int smb2_check_receive(struct smb_message *smb,
-			      struct TCP_Server_Info *server, bool log_error);
-extern struct smb_message *smb2_setup_request(struct cifs_ses *ses,
-					      struct TCP_Server_Info *,
-					      struct smb_rqst *rqst);
-extern struct smb_message *smb2_setup_async_request(
-			struct TCP_Server_Info *server, struct smb_rqst *rqst);
+int smb2_verify_signature(struct smb_message *smb, struct TCP_Server_Info *server);
+int smb2_check_receive(struct smb_message *smb, struct TCP_Server_Info *server,
+		       bool log_error);
+int smb2_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *server,
+		       struct smb_message *smb);
+int smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_message *smb);
 extern struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server,
 						__u64 ses_id, __u32  tid);
-extern int smb2_calc_signature(struct smb_rqst *rqst,
-				struct TCP_Server_Info *server,
-				bool allocate_crypto);
-extern int smb3_calc_signature(struct smb_rqst *rqst,
-				struct TCP_Server_Info *server,
-				bool allocate_crypto);
+int smb2_calc_signature(struct smb_message *smb,
+			struct TCP_Server_Info *server,
+			bool allocate_crypto);
+int smb3_calc_signature(struct smb_message *smb,
+			struct TCP_Server_Info *server,
+			bool allocate_crypto);
 extern void smb2_echo_request(struct work_struct *work);
 extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode);
 extern bool smb2_is_valid_oplock_break(char *buffer,
@@ -127,8 +125,7 @@ extern int smb2_unlock_range(struct cifsFileInfo *cfile,
 extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
 extern void smb2_reconnect_server(struct work_struct *work);
 extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
-extern unsigned long smb_rqst_len(struct TCP_Server_Info *server,
-				  struct smb_rqst *rqst);
+extern unsigned long smb_rqst_len(struct TCP_Server_Info *server, struct smb_rqst *rqst);
 extern void smb2_set_next_command(struct cifs_tcon *tcon,
 				  struct smb_rqst *rqst);
 extern void smb2_set_related(struct smb_rqst *rqst);
@@ -298,7 +295,7 @@ extern void smb2_copy_fs_info_to_kstatfs(
 extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server);
 extern int smb311_update_preauth_hash(struct cifs_ses *ses,
 				      struct TCP_Server_Info *server,
-				      struct kvec *iov, int nvec);
+				      struct smb_message *smb, bool hash_resp);
 extern int smb2_query_info_compound(const unsigned int xid,
 				    struct cifs_tcon *tcon,
 				    const char *path, u32 desired_access,
diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index b217bc0e8e5b..b02f458e408a 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -252,14 +252,13 @@ smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32  tid)
 	return tcon;
 }
 
-int
-smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
+int smb2_calc_signature(struct smb_message *smb, struct TCP_Server_Info *server,
 			bool allocate_crypto)
 {
 	int rc;
 	unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
 	unsigned char *sigptr = smb2_signature;
-	struct kvec *iov = rqst->rq_iov;
+	struct kvec *iov = smb->rqst.rq_iov;
 	struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base;
 	struct shash_desc *shash = NULL;
 	struct smb_rqst drqst;
@@ -308,7 +307,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
 	 * Sign the rfc1002 length prior to passing the data (iov[1-N]) down to
 	 * __cifs_calc_signature().
 	 */
-	drqst = *rqst;
+	drqst = smb->rqst;
 	if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) {
 		rc = crypto_shash_update(shash, iov[0].iov_base,
 					 iov[0].iov_len);
@@ -581,15 +580,14 @@ generate_smb311signingkey(struct cifs_ses *ses,
 	return generate_smb3signingkey(ses, server, &triplet);
 }
 
-int
-smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
+int smb3_calc_signature(struct smb_message *smb, struct TCP_Server_Info *server,
 			bool allocate_crypto)
 {
 	int rc;
 	unsigned char smb3_signature[SMB2_CMACAES_SIZE];
 	unsigned char *sigptr = smb3_signature;
-	struct kvec *iov = rqst->rq_iov;
-	struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base;
+	struct kvec *iov = smb->rqst.rq_iov;
+	struct smb2_hdr *shdr = smb->request;
 	struct shash_desc *shash = NULL;
 	struct smb_rqst drqst;
 	u8 key[SMB3_SIGN_KEY_SIZE];
@@ -635,7 +633,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
 	 * Sign the rfc1002 length prior to passing the data (iov[1-N]) down to
 	 * __cifs_calc_signature().
 	 */
-	drqst = *rqst;
+	drqst = smb->rqst;
 	if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) {
 		rc = crypto_shash_update(shash, iov[0].iov_base,
 					 iov[0].iov_len);
@@ -660,23 +658,22 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
 
 /* must be called with server->srv_mutex held */
 static int
-smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
+smb2_sign_rqst(struct smb_message *smb, struct TCP_Server_Info *server)
 {
 	int rc = 0;
-	struct smb2_hdr *shdr;
+	struct smb2_hdr *shdr = smb->request;
 	struct smb2_sess_setup_req *ssr;
 	bool is_binding;
 	bool is_signed;
 
-	shdr = (struct smb2_hdr *)rqst->rq_iov[0].iov_base;
 	ssr = (struct smb2_sess_setup_req *)shdr;
 
-	is_binding = le16_to_cpu(shdr->Command) == SMB2_SESSION_SETUP &&
+	is_binding = smb->command_id == SMB2_SESSION_SETUP &&
 		(ssr->Flags & SMB2_SESSION_REQ_FLAG_BINDING);
 	is_signed = shdr->Flags & SMB2_FLAGS_SIGNED;
-
 	if (!is_signed)
 		return 0;
+
 	spin_lock(&server->srv_lock);
 	if (server->ops->need_neg &&
 	    server->ops->need_neg(server)) {
@@ -689,24 +686,21 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 		return 0;
 	}
 
-	rc = server->ops->calc_signature(rqst, server, false);
-
+	rc = server->ops->calc_signature(smb, server, false);
 	return rc;
 }
 
-int
-smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
+int smb2_verify_signature(struct smb_message *smb, struct TCP_Server_Info *server)
 {
-	unsigned int rc;
+	struct smb2_hdr *shdr = smb->request;
 	char server_response_sig[SMB2_SIGNATURE_SIZE];
-	struct smb2_hdr *shdr =
-			(struct smb2_hdr *)rqst->rq_iov[0].iov_base;
+	int rc;
 
-	if (le16_to_cpu(shdr->Command) == SMB2_NEGOTIATE ||
-	    le16_to_cpu(shdr->Command) == SMB2_SESSION_SETUP ||
-	    le16_to_cpu(shdr->Command) == SMB2_OPLOCK_BREAK ||
+	if (smb->command_id == SMB2_NEGOTIATE ||
+	    smb->command_id == SMB2_SESSION_SETUP ||
+	    smb->command_id == SMB2_OPLOCK_BREAK ||
 	    server->ignore_signature ||
-	    (!server->session_estab))
+	    !server->session_estab)
 		return 0;
 
 	/*
@@ -727,7 +721,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 
 	memset(shdr->Signature, 0, SMB2_SIGNATURE_SIZE);
 
-	rc = server->ops->calc_signature(rqst, server, true);
+	rc = server->ops->calc_signature(smb, server, true);
 
 	if (rc)
 		return rc;
@@ -736,8 +730,8 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 		cifs_dbg(VFS, "sign fail cmd 0x%x message id 0x%llx\n",
 			shdr->Command, shdr->MessageId);
 		return -EACCES;
-	} else
-		return 0;
+	}
+	return 0;
 }
 
 /*
@@ -746,58 +740,40 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
  */
 static inline void
 smb2_seq_num_into_buf(struct TCP_Server_Info *server,
-		      struct smb2_hdr *shdr)
+		      struct smb_message *smb)
 {
-	unsigned int i, num = le16_to_cpu(shdr->CreditCharge);
+	struct smb2_hdr *shdr = smb->request;
+	unsigned int num = le16_to_cpu(shdr->CreditCharge);
 
-	shdr->MessageId = get_next_mid64(server);
 	/* skip message numbers according to CreditCharge field */
-	for (i = 1; i < num; i++)
-		get_next_mid(server);
+	smb->mid = get_next_mid64(server, num);
+	shdr->MessageId = cpu_to_le64(smb->mid);
 }
 
-static struct smb_message *
-smb2_mid_entry_alloc(const struct smb2_hdr *shdr,
-		     struct TCP_Server_Info *server)
+static void smb2_init_mid(struct smb_message *smb,
+			  struct TCP_Server_Info *server)
 {
-	struct smb_message *smb;
+	const struct smb2_hdr *shdr = smb->request;
 	unsigned int credits = le16_to_cpu(shdr->CreditCharge);
 
-	if (server == NULL) {
-		cifs_dbg(VFS, "Null TCP session in smb2_mid_entry_alloc\n");
-		return NULL;
-	}
-
-	smb = mempool_alloc(&smb_message_pool, GFP_NOFS);
-	memset(smb, 0, sizeof(*smb));
-	refcount_set(&smb->ref, 1);
-	smb->mid = le64_to_cpu(shdr->MessageId);
-	smb->credits_consumed = credits > 0 ? credits : 1;
-	smb->pid = current->pid;
-	smb->command_id = le16_to_cpu(shdr->Command);
-	smb->when_alloc = jiffies;
-	smb->server = server;
+	smb->credits_consumed	= credits > 0 ? credits : 1;
+	smb->server		= server;
 
 	/*
 	 * The default is for the mid to be synchronous, so the
 	 * default callback just wakes up the current task.
 	 */
-	get_task_struct(current);
-	smb->creator = current;
-	smb->callback = cifs_wake_up_task;
-	smb->callback_data = current;
+	smb->creator		= get_task_struct(current);
 
 	atomic_inc(&mid_count);
-	smb->mid_state = MID_REQUEST_ALLOCATED;
 	trace_smb3_cmd_enter(le32_to_cpu(shdr->Id.SyncId.TreeId),
 			     le64_to_cpu(shdr->SessionId),
 			     le16_to_cpu(shdr->Command), smb->mid);
-	return smb;
 }
 
 static int
 smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server,
-		   struct smb2_hdr *shdr, struct smb_message **smb)
+		   struct smb_message *smb)
 {
 	spin_lock(&server->srv_lock);
 	if (server->tcpStatus == CifsExiting) {
@@ -812,7 +788,7 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server,
 	}
 
 	if (server->tcpStatus == CifsNeedNegotiate &&
-	    le16_to_cpu(shdr->Command) != SMB2_NEGOTIATE) {
+	    smb->command_id != SMB2_NEGOTIATE) {
 		spin_unlock(&server->srv_lock);
 		return -EAGAIN;
 	}
@@ -820,8 +796,8 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server,
 
 	spin_lock(&ses->ses_lock);
 	if (ses->ses_status == SES_NEW) {
-		if (le16_to_cpu(shdr->Command) != SMB2_SESSION_SETUP &&
-		    le16_to_cpu(shdr->Command) != SMB2_NEGOTIATE) {
+		if (smb->command_id != SMB2_SESSION_SETUP &&
+		    smb->command_id != SMB2_NEGOTIATE) {
 			spin_unlock(&ses->ses_lock);
 			return -EAGAIN;
 		}
@@ -829,7 +805,7 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server,
 	}
 
 	if (ses->ses_status == SES_EXITING) {
-		if (le16_to_cpu(shdr->Command) != SMB2_LOGOFF) {
+		if (smb->command_id != SMB2_LOGOFF) {
 			spin_unlock(&ses->ses_lock);
 			return -EAGAIN;
 		}
@@ -837,101 +813,78 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server,
 	}
 	spin_unlock(&ses->ses_lock);
 
-	*smb = smb2_mid_entry_alloc(shdr, server);
-	if (*smb == NULL)
-		return -ENOMEM;
+	smb2_init_mid(smb, server);
+
+	smb_get_message(smb);
 	spin_lock(&server->mid_lock);
-	list_add_tail(&(*smb)->qhead, &server->pending_mid_q);
+	list_add_tail(&smb->qhead, &server->pending_mid_q);
 	spin_unlock(&server->mid_lock);
-
 	return 0;
 }
 
-int
-smb2_check_receive(struct smb_message *mid, struct TCP_Server_Info *server,
-		   bool log_error)
+int smb2_check_receive(struct smb_message *smb, struct TCP_Server_Info *server,
+		       bool log_error)
 {
-	unsigned int len = mid->resp_buf_size;
-	struct kvec iov[1];
-	struct smb_rqst rqst = { .rq_iov = iov,
-				 .rq_nvec = 1 };
+	unsigned int len = smb->resp_buf_size;
 
-	iov[0].iov_base = (char *)mid->resp_buf;
-	iov[0].iov_len = len;
-
-	dump_smb(mid->resp_buf, min_t(u32, 80, len));
+	dump_smb(smb->resp_buf, min_t(u32, 80, len));
 	/* convert the length into a more usable form */
-	if (len > 24 && server->sign && !mid->decrypted) {
+	if (len > 24 && server->sign && !smb->decrypted) {
 		int rc;
 
-		rc = smb2_verify_signature(&rqst, server);
+		rc = smb2_verify_signature(smb, server);
 		if (rc)
 			cifs_server_dbg(VFS, "SMB signature verification returned error = %d\n",
 				 rc);
 	}
 
-	return map_smb2_to_linux_error(mid->resp_buf, log_error);
+	return map_smb2_to_linux_error(smb->resp_buf, log_error);
 }
 
-struct smb_message *
-smb2_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *server,
-		   struct smb_rqst *rqst)
+int smb2_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *server,
+		       struct smb_message *smb)
 {
+	struct smb2_hdr *shdr = smb->request;
 	int rc;
-	struct smb2_hdr *shdr =
-			(struct smb2_hdr *)rqst->rq_iov[0].iov_base;
-	struct smb_message *mid;
 
-	smb2_seq_num_into_buf(server, shdr);
+	smb2_seq_num_into_buf(server, smb);
 
-	rc = smb2_get_mid_entry(ses, server, shdr, &mid);
+	rc = smb2_get_mid_entry(ses, server, smb);
 	if (rc) {
 		revert_current_mid_from_hdr(server, shdr);
-		return ERR_PTR(rc);
+		return rc;
 	}
 
-	rc = smb2_sign_rqst(rqst, server);
-	if (rc) {
+	rc = smb2_sign_rqst(smb, server);
+	if (rc)
 		revert_current_mid_from_hdr(server, shdr);
-		delete_mid(mid);
-		return ERR_PTR(rc);
-	}
-
-	return mid;
+	return rc;
 }
 
-struct smb_message *
-smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
+int
+smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_message *smb)
 {
+	struct smb2_hdr *shdr = smb->request;
 	int rc;
-	struct smb2_hdr *shdr =
-			(struct smb2_hdr *)rqst->rq_iov[0].iov_base;
-	struct smb_message *smb;
 
 	spin_lock(&server->srv_lock);
 	if (server->tcpStatus == CifsNeedNegotiate &&
-	    le16_to_cpu(shdr->Command) != SMB2_NEGOTIATE) {
+	   smb->command_id != SMB2_NEGOTIATE) {
 		spin_unlock(&server->srv_lock);
-		return ERR_PTR(-EAGAIN);
+		return -EAGAIN;
 	}
 	spin_unlock(&server->srv_lock);
 
-	smb2_seq_num_into_buf(server, shdr);
-
-	smb = smb2_mid_entry_alloc(shdr, server);
-	if (smb == NULL) {
-		revert_current_mid_from_hdr(server, shdr);
-		return ERR_PTR(-ENOMEM);
-	}
+	smb2_seq_num_into_buf(server, smb);
+	smb2_init_mid(smb, server);
 
-	rc = smb2_sign_rqst(rqst, server);
+	rc = smb2_sign_rqst(smb, server);
 	if (rc) {
 		revert_current_mid_from_hdr(server, shdr);
-		release_mid(smb);
-		return ERR_PTR(rc);
+		return rc;
 	}
 
-	return smb;
+	return 0;
 }
 
 int
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index 6459acf959f3..042f689bbf52 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -40,7 +40,17 @@ struct smb_message *smb_message_alloc(enum smb2_command cmd, gfp_t gfp)
 	if (smb) {
 		memset(smb, 0, sizeof(*smb));
 		refcount_set(&smb->ref, 1);
-		smb->command_id = cmd;
+		smb->command_id	= cmd;
+		smb->when_alloc	= jiffies;
+		smb->pid	= current->pid;
+
+		/*
+		 * The default is for the mid to be synchronous, so the default
+		 * callback just wakes up the current task.
+		 */
+		smb->callback		= cifs_wake_up_task;
+		smb->callback_data	= current;
+		smb->mid_state		= MID_REQUEST_ALLOCATED;
 	}
 	return smb;
 }
@@ -60,7 +70,8 @@ void smb_put_message(struct smb_message *smb)
 }
 
 /*
- * Dispose of a chain of compound messages.
+ * Dispose of a chain of compound messages.  This should only be called by the
+ * caller of smb_send_recv_messages().
  */
 void smb_put_messages(struct smb_message *smb)
 {
@@ -80,7 +91,7 @@ cifs_wake_up_task(struct smb_message *smb)
 	wake_up_process(smb->callback_data);
 }
 
-void __release_mid(struct smb_message *smb)
+static void smb_clear_mid(struct smb_message *smb, struct TCP_Server_Info *server)
 {
 #ifdef CONFIG_CIFS_STATS2
 	enum smb2_command command = smb->server->vals->lock_cmd;
@@ -88,7 +99,6 @@ void __release_mid(struct smb_message *smb)
 	unsigned long now;
 	unsigned long roundtrip_time;
 #endif
-	struct TCP_Server_Info *server = smb->server;
 
 	if (smb->resp_buf && (smb->mid_flags & MID_WAIT_CANCELLED) &&
 	    (smb->mid_state == MID_RESPONSE_RECEIVED ||
@@ -154,22 +164,33 @@ void __release_mid(struct smb_message *smb)
 	}
 #endif
 	put_task_struct(smb->creator);
-
-	mempool_free(smb, &smb_message_pool);
 }
 
-void
-delete_mid(struct smb_message *smb)
+static bool discard_message(struct TCP_Server_Info *server, struct smb_message *smb)
 {
-	spin_lock(&smb->server->mid_lock);
+	bool got_ref = false;
+
+	spin_lock(&server->mid_lock);
 
 	if (!(smb->mid_flags & MID_DELETED)) {
 		list_del_init(&smb->qhead);
 		smb->mid_flags |= MID_DELETED;
+		got_ref = true;
 	}
-	spin_unlock(&smb->server->mid_lock);
 
-	release_mid(smb);
+	spin_unlock(&server->mid_lock);
+	return got_ref;
+}
+
+static void smb_discard_messages(struct TCP_Server_Info *server, struct smb_message *head_smb)
+{
+	struct smb_message *smb, *next;
+
+	for (smb = head_smb; smb; smb = next) {
+		next = smb->next;
+		if (discard_message(server, smb))
+			smb_put_message(smb);
+	}
 }
 
 /*
@@ -456,20 +477,16 @@ static size_t smb3_copy_data_iter(void *iter_from, size_t progress, size_t len,
  * at the front for the header(s).
  */
 static int smb_copy_data_into_buffer(struct TCP_Server_Info *server,
-				     int num_rqst, struct smb_rqst *rqst,
+				     struct smb_message *head_smb,
 				     struct iov_iter *iter, struct bvecq **_bq)
 {
+	struct smb_message *smb;
 	struct bvecq *bq;
 	size_t total_len = 0, offset = 0;
 
-	for (int i = 0; i < num_rqst; i++) {
-		struct smb_rqst *req = &rqst[i];
-		size_t size = iov_iter_count(&req->rq_iter);
-
-		for (int j = 0; j < req->rq_nvec; j++)
-			size += req->rq_iov[j].iov_len;
+	for (smb = head_smb; smb; smb = smb->next) {
 		total_len = ALIGN8(total_len);
-		total_len += size;
+		total_len += smb->total_len;
 	}
 
 	bq = netfs_alloc_bvecq_buffer(total_len, 1, GFP_NOFS);
@@ -478,9 +495,8 @@ static int smb_copy_data_into_buffer(struct TCP_Server_Info *server,
 
 	iov_iter_bvec_queue(iter, ITER_DEST, bq, 1, 0, total_len);
 
-	for (int i = 0; i < num_rqst; i++) {
-		struct smb_rqst *req = &rqst[i];
-		size_t size = iov_iter_count(&req->rq_iter);
+	for (smb = head_smb; smb; smb = smb->next) {
+		size_t size = iov_iter_count(&smb->rqst.rq_iter);
 
 		if (offset & 7) {
 			unsigned int tmp = offset;
@@ -488,14 +504,15 @@ static int smb_copy_data_into_buffer(struct TCP_Server_Info *server,
 			iov_iter_zero(offset - tmp, iter);
 		}
 
-		for (int j = 0; j < req->rq_nvec; j++) {
-			size_t len = req->rq_iov[j].iov_len;
-			if (copy_to_iter(req->rq_iov[j].iov_base, len, iter) != len)
+		for (int i = 0; i < smb->rqst.rq_nvec; i++) {
+			size_t len = smb->rqst.rq_iov[i].iov_len;
+			if (copy_to_iter(smb->rqst.rq_iov[i].iov_base,
+					 len, iter) != len)
 				goto error;
 			offset += len;
 		}
 
-		if (iterate_and_advance_kernel(&req->rq_iter,
+		if (iterate_and_advance_kernel(&smb->rqst.rq_iter,
 					       size, iter, NULL,
 					       smb3_copy_data_iter) != size)
 			goto error;
@@ -517,8 +534,7 @@ static int smb_copy_data_into_buffer(struct TCP_Server_Info *server,
 }
 
 static int
-smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
-	      struct smb_rqst *rqst, int flags)
+smb_send_rqst(struct TCP_Server_Info *server, struct smb_message *head_smb, int flags)
 {
 	struct smb2_transform_hdr *tr_hdr;
 	struct iov_iter iter;
@@ -532,7 +548,7 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
 		return -EIO;
 	}
 
-	rc = smb_copy_data_into_buffer(server, num_rqst, rqst, &iter, &bq);
+	rc = smb_copy_data_into_buffer(server, head_smb, &iter, &bq);
 	if (rc)
 		return rc;
 	content_len = iov_iter_count(&iter);
@@ -562,7 +578,7 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
 			hdr_len += sizeof(*tr_hdr);
 			iov_iter_bvec_queue(&iter, ITER_SOURCE, bq, 1, 0, content_len);
 
-			rc = server->ops->init_transform_rq(server, num_rqst, rqst, tr_hdr, &iter);
+			rc = server->ops->init_transform_rq(server, head_smb, tr_hdr, &iter);
 			if (rc)
 				goto error;
 		}
@@ -816,16 +832,16 @@ int wait_for_response(struct TCP_Server_Info *server, struct smb_message *smb)
  * the result. Caller is responsible for dealing with timeouts.
  */
 int
-cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
-		mid_receive_t receive, mid_callback_t callback,
-		mid_handle_t handle, void *cbdata, const int flags,
-		const struct cifs_credits *exist_credits)
+cifs_call_async(struct TCP_Server_Info *server, struct smb_message *smb,
+		const int flags, const struct cifs_credits *exist_credits)
 {
-	int rc;
-	struct smb_message *smb;
 	struct cifs_credits credits = { .value = 0, .instance = 0 };
 	unsigned int instance;
 	int optype;
+	int rc;
+
+	if (WARN_ON_ONCE(smb->next))
+		return -EIO;
 
 	optype = flags & CIFS_OP_MASK;
 
@@ -851,21 +867,17 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 		return -EAGAIN;
 	}
 
-	smb = server->ops->setup_async_request(server, rqst);
-	if (IS_ERR(smb)) {
+	rc = server->ops->setup_async_request(server, smb);
+	if (rc) {
 		cifs_server_unlock(server);
 		add_credits_and_wake_if(server, &credits, optype);
-		return PTR_ERR(smb);
+		return rc;
 	}
 
-	smb->sr_flags = flags;
-	smb->receive = receive;
-	smb->callback = callback;
-	smb->callback_data = cbdata;
-	smb->handle = handle;
 	smb->mid_state = MID_REQUEST_SUBMITTED;
 
 	/* put it on the pending_mid_q */
+	smb_get_message(smb);
 	spin_lock(&server->mid_lock);
 	list_add_tail(&smb->qhead, &server->pending_mid_q);
 	spin_unlock(&server->mid_lock);
@@ -875,12 +887,13 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 	 * I/O response may come back and free the mid entry on another thread.
 	 */
 	cifs_save_when_sent(smb);
-	rc = smb_send_rqst(server, 1, rqst, flags);
+	rc = smb_send_rqst(server, smb, flags);
 
 	if (rc < 0) {
 		revert_current_mid(server, smb->credits_consumed);
 		server->sequence_number -= 2;
-		delete_mid(smb);
+		if (discard_message(server, smb))
+			smb_put_message(smb);
 	}
 
 	cifs_server_unlock(server);
@@ -930,7 +943,7 @@ int cifs_sync_mid_result(struct smb_message *smb, struct TCP_Server_Info *server
 	spin_unlock(&server->mid_lock);
 
 sync_mid_done:
-	release_mid(smb);
+	smb_clear_mid(smb, server);
 	return rc;
 }
 
@@ -960,7 +973,6 @@ static void
 cifs_cancelled_callback(struct smb_message *smb)
 {
 	cifs_compound_callback(smb);
-	release_mid(smb);
 }
 
 /*
@@ -1017,31 +1029,29 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses)
 	return server;
 }
 
-int
-compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
-		   struct TCP_Server_Info *server,
-		   const int flags, const int num_rqst, struct smb_rqst *rqst,
-		   int *resp_buf_type, struct kvec *resp_iov)
+/*
+ * Send a single message or a string of messages as a compound.
+ */
+int smb_send_recv_messages(const unsigned int xid, struct cifs_ses *ses,
+			   struct TCP_Server_Info *server,
+			   struct smb_message *head_smb, const int flags)
 {
-	int i, j, optype, rc = 0;
-	struct smb_message *smb[MAX_COMPOUND];
-	bool cancelled_mid[MAX_COMPOUND] = {false};
-	struct cifs_credits credits[MAX_COMPOUND] = {
-		{ .value = 0, .instance = 0 }
-	};
 	unsigned int instance;
+	int nr_reqs, i, optype, rc = 0;
 	char *buf;
 
-	optype = flags & CIFS_OP_MASK;
-
-	for (i = 0; i < num_rqst; i++)
-		resp_buf_type[i] = CIFS_NO_BUFFER;  /* no response buf yet */
-
 	if (!ses || !ses->server || !server) {
 		cifs_dbg(VFS, "Null session\n");
 		return -EIO;
 	}
 
+	optype = flags & CIFS_OP_MASK;
+
+	/* TODO: Stitch together the messages in a compound. */
+	nr_reqs = 0;
+	for (struct smb_message *smb = head_smb; smb; smb = smb->next)
+		nr_reqs++;
+
 	spin_lock(&server->srv_lock);
 	if (server->tcpStatus == CifsExiting) {
 		spin_unlock(&server->srv_lock);
@@ -1057,14 +1067,13 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 	 * other requests.
 	 * This can be handled by the eventual session reconnect.
 	 */
-	rc = wait_for_compound_request(server, num_rqst, flags,
-				       &instance);
+	rc = wait_for_compound_request(server, nr_reqs, flags, &instance);
 	if (rc)
 		return rc;
 
-	for (i = 0; i < num_rqst; i++) {
-		credits[i].value = 1;
-		credits[i].instance = instance;
+	for (struct smb_message *smb = head_smb; smb; smb = smb->next) {
+		smb->credits.value	= 1;
+		smb->credits.instance	= instance;
 	}
 
 	/*
@@ -1084,45 +1093,46 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 	 */
 	if (instance != server->reconnect_instance) {
 		cifs_server_unlock(server);
-		for (j = 0; j < num_rqst; j++)
-			add_credits(server, &credits[j], optype);
+		for (struct smb_message *smb = head_smb; smb; smb = smb->next)
+			add_credits(server, &smb->credits, optype);
 		return -EAGAIN;
 	}
 
-	for (i = 0; i < num_rqst; i++) {
-		smb[i] = server->ops->setup_request(ses, server, &rqst[i]);
-		if (IS_ERR(smb[i])) {
-			revert_current_mid(server, i);
-			for (j = 0; j < i; j++)
-				delete_mid(smb[j]);
-			cifs_server_unlock(server);
-
-			/* Update # of requests on wire to server */
-			for (j = 0; j < num_rqst; j++)
-				add_credits(server, &credits[j], optype);
-			return PTR_ERR(smb[i]);
-		}
-
-		smb[i]->sr_flags = flags;
-		smb[i]->mid_state = MID_REQUEST_SUBMITTED;
-		smb[i]->optype = optype;
+	i = 0;
+	for (struct smb_message *smb = head_smb; smb; smb = smb->next) {
+		smb->optype = optype;
 		/*
 		 * Invoke callback for every part of the compound chain
 		 * to calculate credits properly. Wake up this thread only when
 		 * the last element is received.
 		 */
-		if (i < num_rqst - 1)
-			smb[i]->callback = cifs_compound_callback;
+		if (smb->next)
+			smb->callback = cifs_compound_callback;
 		else
-			smb[i]->callback = cifs_compound_last_callback;
+			smb->callback = cifs_compound_last_callback;
+
+		rc = server->ops->setup_request(ses, server, smb);
+		if (rc) {
+			revert_current_mid(server, i);
+			smb_discard_messages(server, head_smb);
+			cifs_server_unlock(server);
+
+			/* Update # of requests on wire to server */
+			for (struct smb_message *smb = head_smb; smb; smb = smb->next)
+				add_credits(server, &smb->credits, optype);
+			return rc;
+		}
+
+		smb->mid_state = MID_REQUEST_SUBMITTED;
 	}
-	rc = smb_send_rqst(server, num_rqst, rqst, flags);
 
-	for (i = 0; i < num_rqst; i++)
-		cifs_save_when_sent(smb[i]);
+	rc = smb_send_rqst(server, head_smb, flags);
+
+	for (struct smb_message *smb = head_smb; smb; smb = smb->next)
+		cifs_save_when_sent(smb);
 
 	if (rc < 0) {
-		revert_current_mid(server, num_rqst);
+		revert_current_mid(server, nr_reqs);
 		server->sequence_number -= 2;
 	}
 
@@ -1133,8 +1143,8 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 	 * will not receive a response to - return credits back
 	 */
 	if (rc < 0 || (flags & CIFS_NO_SRV_RSP)) {
-		for (i = 0; i < num_rqst; i++)
-			add_credits(server, &credits[i], optype);
+		for (struct smb_message *smb = head_smb; smb; smb = smb->next)
+			add_credits(server, &smb->credits, optype);
 		goto out;
 	}
 
@@ -1154,70 +1164,71 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 		spin_unlock(&ses->ses_lock);
 
 		cifs_server_lock(server);
-		smb311_update_preauth_hash(ses, server, rqst[0].rq_iov, rqst[0].rq_nvec);
+		smb311_update_preauth_hash(ses, server, head_smb, false);
 		cifs_server_unlock(server);
-
-		spin_lock(&ses->ses_lock);
+	} else {
+		spin_unlock(&ses->ses_lock);
 	}
-	spin_unlock(&ses->ses_lock);
 
-	for (i = 0; i < num_rqst; i++) {
-		rc = wait_for_response(server, smb[i]);
-		if (rc != 0)
-			break;
+	for (struct smb_message *smb = head_smb; smb; smb = smb->next) {
+		if (!smb->next) {
+			rc = wait_for_response(server, smb);
+			if (rc != 0)
+				break;
+		}
 	}
 	if (rc != 0) {
-		for (; i < num_rqst; i++) {
+		for (struct smb_message *smb = head_smb; smb; smb = smb->next) {
 			cifs_server_dbg(FYI, "Cancelling wait for mid %llu cmd: %d\n",
-				 smb[i]->mid, smb[i]->command_id);
-			send_cancel(ses, server, &rqst[i], smb[i], xid);
+					smb->mid, smb->command_id);
+			send_cancel(ses, server, smb, xid);
 			spin_lock(&server->mid_lock);
-			smb[i]->mid_flags |= MID_WAIT_CANCELLED;
-			if (smb[i]->mid_state == MID_REQUEST_SUBMITTED ||
-			    smb[i]->mid_state == MID_RESPONSE_RECEIVED) {
-				smb[i]->callback = cifs_cancelled_callback;
-				cancelled_mid[i] = true;
-				credits[i].value = 0;
+			smb->mid_flags |= MID_WAIT_CANCELLED;
+			if (smb->mid_state == MID_REQUEST_SUBMITTED ||
+			    smb->mid_state == MID_RESPONSE_RECEIVED) {
+				smb->callback = cifs_cancelled_callback;
+				smb->cancelled = true;
+				smb->credits.value = 0;
 			}
 			spin_unlock(&server->mid_lock);
 		}
 	}
 
-	for (i = 0; i < num_rqst; i++) {
+	for (struct smb_message *smb = head_smb; smb; smb = smb->next) {
 		if (rc < 0)
 			goto out;
 
-		rc = cifs_sync_mid_result(smb[i], server);
+		rc = cifs_sync_mid_result(smb, server);
 		if (rc != 0) {
 			/* mark this mid as cancelled to not free it below */
-			cancelled_mid[i] = true;
+			smb->cancelled = true;
 			goto out;
 		}
 
-		if (!smb[i]->resp_buf ||
-		    smb[i]->mid_state != MID_RESPONSE_READY) {
+		if (!smb->resp_buf ||
+		    smb->mid_state != MID_RESPONSE_READY) {
 			rc = -EIO;
 			cifs_dbg(FYI, "Bad MID state?\n");
 			goto out;
 		}
 
-		rc = server->ops->check_receive(smb[i], server,
-						     flags & CIFS_LOG_ERROR);
+		rc = server->ops->check_receive(smb, server,
+						flags & CIFS_LOG_ERROR);
 
-		if (resp_iov) {
-			buf = (char *)smb[i]->resp_buf;
-			resp_iov[i].iov_base = buf;
-			resp_iov[i].iov_len = smb[i]->resp_buf_size +
+		if (smb->resp_iov) {
+			buf = (char *)smb->resp_buf;
+			smb->resp_iov->iov_base = buf;
+			smb->resp_iov->iov_len = smb->resp_buf_size +
 				HEADER_PREAMBLE_SIZE(server);
 
-			if (smb[i]->large_buf)
-				resp_buf_type[i] = CIFS_LARGE_BUFFER;
+			if (smb->large_buf)
+				*smb->resp_buf_type = CIFS_LARGE_BUFFER;
 			else
-				resp_buf_type[i] = CIFS_SMALL_BUFFER;
+				*smb->resp_buf_type = CIFS_SMALL_BUFFER;
 
 			/* mark it so buf will not be freed by delete_mid */
 			if ((flags & CIFS_NO_RSP_BUF) == 0)
-				smb[i]->resp_buf = NULL;
+				smb->resp_buf = NULL;
 		}
 	}
 
@@ -1226,17 +1237,13 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 	 */
 	spin_lock(&ses->ses_lock);
 	if ((ses->ses_status == SES_NEW) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) {
-		struct kvec iov = {
-			.iov_base = resp_iov[0].iov_base,
-			.iov_len = resp_iov[0].iov_len
-		};
 		spin_unlock(&ses->ses_lock);
 		cifs_server_lock(server);
-		smb311_update_preauth_hash(ses, server, &iov, 1);
+		smb311_update_preauth_hash(ses, server, head_smb, true);
 		cifs_server_unlock(server);
-		spin_lock(&ses->ses_lock);
+	} else {
+		spin_unlock(&ses->ses_lock);
 	}
-	spin_unlock(&ses->ses_lock);
 
 out:
 	/*
@@ -1245,11 +1252,51 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 	 * This is prevented above by using a noop callback that will not
 	 * wake this thread except for the very last PDU.
 	 */
-	for (i = 0; i < num_rqst; i++) {
-		if (!cancelled_mid[i])
-			delete_mid(smb[i]);
+	for (struct smb_message *smb = head_smb; smb; smb = smb->next)
+		if (!smb->cancelled)
+			discard_message(server, smb);
+
+	return rc;
+}
+
+int
+compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
+		   struct TCP_Server_Info *server,
+		   const int flags, const int num_rqst, struct smb_rqst *rqst,
+		   int *resp_buf_type, struct kvec *resp_iov)
+{
+	struct smb_message *head_smb = NULL, **ppsmb = &head_smb, *smb;
+	int rc = -ENOMEM;
+
+	if (!ses || !ses->server || !server) {
+		cifs_dbg(VFS, "Null session\n");
+		return -EIO;
+	}
+
+	for (int i = 0; i < num_rqst; i++) {
+		void *request = rqst[i].rq_iov[0].iov_base;
+		struct smb2_hdr *hdr = request;
+		enum smb2_command cmd = le16_to_cpu(hdr->Command);
+
+		smb = smb_message_alloc(cmd, GFP_NOFS);
+		if (!smb)
+			goto error;
+
+		*ppsmb = smb;
+		ppsmb = &smb->next;
+		smb->request		= request;
+		smb->rqst		= rqst[i];
+		smb->sr_flags		= flags;
+		smb->total_len		= smb_rqst_len(server, &smb->rqst);
+		smb->resp_buf_type	= &resp_buf_type[i];
+		smb->resp_iov		= &resp_iov[i];
+		resp_buf_type[i] = CIFS_NO_BUFFER;  /* no response buf yet */
 	}
 
+	rc = smb_send_recv_messages(xid, ses, server, head_smb, flags);
+
+error:
+	smb_put_messages(smb);
 	return rc;
 }
 


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 19/31] cifs: Clean up mid->callback_data and kill off mid->creator
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (17 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 18/31] cifs: Pass smb_message structs down into the transport layer David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 20/31] cifs: Don't need state locking in smb2_get_mid_entry() David Howells
                   ` (15 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

We shouldn't really be pinning a task_struct on the mid_q_struct.  Better
to provide a wait queue there and have the waiter wait on it.  For
synchronous operations, this allows them to remove themselves from it once
this is absorbed into smb_message and smb_message is generated higher up
the stack.  This also gets rid of one of the uses of mid->callback_data.

We can also get rid of the need for callback_data for the Echo command
callback by passing a server pointer down into ->callback() from the
callers (all of which have it available).  This can also be used in the
Read and Write callbacks.

We then only need the callback_data for the Read and Write commands - and
in both cases, it points to a cifs_io_subrequest struct.  So replace
callback_data with a specifically typed pointer in a union that other users
can be added to as the need arises.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/cifs_debug.c    |  3 +--
 fs/smb/client/cifsglob.h      | 11 ++++++++---
 fs/smb/client/cifsproto.h     |  2 +-
 fs/smb/client/cifstransport.c |  1 -
 fs/smb/client/connect.c       |  8 ++++----
 fs/smb/client/smb2ops.c       |  6 +++---
 fs/smb/client/smb2pdu.c       | 18 +++++++-----------
 fs/smb/client/smb2transport.c |  6 ------
 fs/smb/client/transport.c     | 27 +++++++++++++--------------
 9 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c
index cba30f339d6b..13c569ab3417 100644
--- a/fs/smb/client/cifs_debug.c
+++ b/fs/smb/client/cifs_debug.c
@@ -625,11 +625,10 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
 					   chan_server->conn_id);
 				spin_lock(&chan_server->mid_lock);
 				list_for_each_entry(smb, &chan_server->pending_mid_q, qhead) {
-					seq_printf(m, "\n\t\tState: %d com: %d pid: %d cbdata: %p mid %llu",
+					seq_printf(m, "\n\t\tState: %d com: %d pid: %d mid %llu",
 						   smb->mid_state,
 						   smb->command_id,
 						   smb->pid,
-						   smb->callback_data,
 						   smb->mid);
 				}
 				spin_unlock(&chan_server->mid_lock);
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 4173b87bdf0f..14b132fb14e0 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -1692,7 +1692,8 @@ typedef int (*mid_receive_t)(struct TCP_Server_Info *server,
  * - it will be called by cifsd, with no locks held
  * - the mid will be removed from any lists
  */
-typedef void (*mid_callback_t)(struct smb_message *smb);
+typedef void (*mid_callback_t)(struct TCP_Server_Info *server,
+			       struct smb_message *smb);
 
 /*
  * This is the protopyte for mid handle function. This is called once the mid
@@ -1731,11 +1732,17 @@ struct smb_message {
 	struct smb_message	*next;		/* Next message in compound */
 	struct cifs_credits	credits;	/* Credit requirements for this message */
 	void			*request;	/* Pointer to request message body */
+	wait_queue_head_t	waitq;		/* Wait queue for message events */
 	refcount_t		ref;
 	bool			sensitive;	/* Request contains sensitive data */
 	bool			cancelled;	/* T if cancelled */
 	unsigned int		sr_flags;	/* Flags passed to send_recv() */
 
+	/* PDU-type specific data */
+	union {
+		struct cifs_io_subrequest *subreq; /* Read/write subrequest */
+	};
+
 	/* Queue state */
 	struct list_head	qhead;		/* mids waiting on reply from this server */
 	struct TCP_Server_Info	*server;	/* server corresponding to this mid */
@@ -1752,8 +1759,6 @@ struct smb_message {
 	mid_receive_t		receive;	/* call receive callback */
 	mid_callback_t		callback;	/* call completion callback */
 	mid_handle_t		handle;		/* call handle mid callback */
-	void			*callback_data;	/* general purpose pointer for callback */
-	struct task_struct	*creator;
 	void			*resp_buf;	/* pointer to received SMB header */
 	unsigned int		resp_buf_size;
 	int			mid_state;	/* wish this were enum but can not pass to wait_event */
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index fd5fe2723b4a..abae67d83499 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -83,7 +83,7 @@ extern char *cifs_build_path_to_root(struct smb3_fs_context *ctx,
 				     int add_treename);
 extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
 char *cifs_build_devname(char *nodename, const char *prepath);
-extern void cifs_wake_up_task(struct smb_message *smb);
+extern void cifs_wake_up_task(	struct TCP_Server_Info *server, struct smb_message *smb);
 extern int cifs_handle_standard(struct TCP_Server_Info *server,
 				struct smb_message *smb);
 extern char *smb3_fs_context_fullpath(const struct smb3_fs_context *ctx,
diff --git a/fs/smb/client/cifstransport.c b/fs/smb/client/cifstransport.c
index 8cdb9252a37e..1e2a8839d742 100644
--- a/fs/smb/client/cifstransport.c
+++ b/fs/smb/client/cifstransport.c
@@ -60,7 +60,6 @@ alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
 	 * default callback just wakes up the current task.
 	 */
 	get_task_struct(current);
-	smb->creator = current;
 	smb->callback = cifs_wake_up_task;
 	smb->callback_data = current;
 
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index 7a64b070f74b..9bd19dd91d35 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -334,7 +334,7 @@ cifs_abort_connection(struct TCP_Server_Info *server)
 	cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__);
 	list_for_each_entry_safe(smb, nsmb, &retry_list, qhead) {
 		list_del_init(&smb->qhead);
-		smb->callback(smb);
+		smb->callback(server, smb);
 		smb_put_message(smb);
 	}
 
@@ -917,7 +917,7 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
 				list_del_init(&smb->qhead);
 				smb->mid_rc = mid_rc;
 				smb->mid_state = MID_RC;
-				smb->callback(smb);
+				smb->callback(server, smb);
 				smb_put_message(smb);
 			}
 
@@ -1111,7 +1111,7 @@ clean_demultiplex_info(struct TCP_Server_Info *server)
 		list_for_each_entry_safe(smb, smb2, &dispose_list, qhead) {
 			cifs_dbg(FYI, "Callback mid %llu\n", smb->mid);
 			list_del_init(&smb->qhead);
-			smb->callback(smb);
+			smb->callback(server, smb);
 			smb_put_message(smb);
 		}
 		/* 1/8th of sec is more than enough time for them to exit */
@@ -1388,7 +1388,7 @@ cifs_demultiplex_thread(void *p)
 				}
 
 				if (!smbs[i]->multiRsp || smbs[i]->multiEnd)
-					smbs[i]->callback(smbs[i]);
+					smbs[i]->callback(server, smbs[i]);
 
 				smb_put_message(smbs[i]);
 			} else if (server->ops->is_oplock_break &&
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 835a76169d40..63226bbba3d1 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -4527,7 +4527,7 @@ handle_read_data(struct TCP_Server_Info *server, struct smb_message *smb,
 	unsigned int cur_off;
 	unsigned int cur_page_idx;
 	unsigned int pad_len;
-	struct cifs_io_subrequest *rdata = smb->callback_data;
+	struct cifs_io_subrequest *rdata = smb->subreq;
 	struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
 	int length;
 	bool use_rdma_mr = false;
@@ -4707,7 +4707,7 @@ static void smb2_decrypt_offload(struct work_struct *work)
 				dw->server->ops->is_network_name_deleted(dw->buf,
 									 dw->server);
 
-			smb->callback(smb);
+			smb->callback(dw->server, smb);
 		} else {
 			spin_lock(&dw->server->srv_lock);
 			if (dw->server->tcpStatus == CifsNeedReconnect) {
@@ -4715,7 +4715,7 @@ static void smb2_decrypt_offload(struct work_struct *work)
 				smb->mid_state = MID_RETRY_NEEDED;
 				spin_unlock(&dw->server->mid_lock);
 				spin_unlock(&dw->server->srv_lock);
-				smb->callback(smb);
+				smb->callback(dw->server, smb);
 			} else {
 				spin_lock(&dw->server->mid_lock);
 				smb->mid_state = MID_REQUEST_SUBMITTED;
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 6b94da4c1149..8d50036fd028 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -4094,9 +4094,8 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
  * FIXME: maybe we should consider checking that the reply matches request?
  */
 static void
-smb2_echo_callback(struct smb_message *smb)
+smb2_echo_callback(struct TCP_Server_Info *server, struct smb_message *smb)
 {
-	struct TCP_Server_Info *server = smb->callback_data;
 	struct smb2_echo_rsp *rsp = (struct smb2_echo_rsp *)smb->resp_buf;
 	struct cifs_credits credits = { .value = 0, .instance = 0 };
 
@@ -4298,7 +4297,6 @@ SMB2_echo(struct TCP_Server_Info *server)
 	smb->request		= req;
 	smb->total_len		= total_len;
 	smb->callback		= smb2_echo_callback;
-	smb->callback_data	= server;
 
 	req->hdr.CreditRequest = cpu_to_le16(1);
 
@@ -4533,12 +4531,11 @@ smb2_new_read_req(void **buf, unsigned int *total_len,
 }
 
 static void
-smb2_readv_callback(struct smb_message *smb)
+smb2_readv_callback(struct TCP_Server_Info *server, struct smb_message *smb)
 {
-	struct cifs_io_subrequest *rdata = smb->callback_data;
+	struct cifs_io_subrequest *rdata = smb->subreq;
 	struct netfs_inode *ictx = netfs_inode(rdata->rreq->inode);
 	struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink);
-	struct TCP_Server_Info *server = rdata->server;
 	struct smb2_hdr *shdr = (struct smb2_hdr *)rdata->iov[0].iov_base;
 	struct cifs_credits credits = {
 		.value = 0,
@@ -4720,7 +4717,7 @@ smb2_async_readv(struct cifs_io_subrequest *rdata)
 	smb->receive		= cifs_readv_receive;
 	smb->handle		= smb3_handle_read_data;
 	smb->callback		= smb2_readv_callback;
-	smb->callback_data	= rdata;
+	smb->subreq		= rdata;
 
 	shdr = (struct smb2_hdr *)smb->request;
 
@@ -4847,11 +4844,10 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
  * workqueue completion task.
  */
 static void
-smb2_writev_callback(struct smb_message *smb)
+smb2_writev_callback(struct TCP_Server_Info *server, struct smb_message *smb)
 {
-	struct cifs_io_subrequest *wdata = smb->callback_data;
+	struct cifs_io_subrequest *wdata = smb->subreq;
 	struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink);
-	struct TCP_Server_Info *server = wdata->server;
 	struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)smb->resp_buf;
 	struct cifs_credits credits = {
 		.value = 0,
@@ -5016,7 +5012,7 @@ smb2_async_writev(struct cifs_io_subrequest *wdata)
 	smb->request		= req;
 	smb->total_len		= total_len;
 	smb->callback		= smb2_writev_callback;
-	smb->callback_data	= wdata;
+	smb->subreq		= wdata;
 
 	if (smb3_encryption_required(tcon))
 		flags |= CIFS_TRANSFORM_REQ;
diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index b02f458e408a..7c60584a8544 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -759,12 +759,6 @@ static void smb2_init_mid(struct smb_message *smb,
 	smb->credits_consumed	= credits > 0 ? credits : 1;
 	smb->server		= server;
 
-	/*
-	 * The default is for the mid to be synchronous, so the
-	 * default callback just wakes up the current task.
-	 */
-	smb->creator		= get_task_struct(current);
-
 	atomic_inc(&mid_count);
 	trace_smb3_cmd_enter(le32_to_cpu(shdr->Id.SyncId.TreeId),
 			     le64_to_cpu(shdr->SessionId),
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index 042f689bbf52..7a4788b54a07 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -49,8 +49,9 @@ struct smb_message *smb_message_alloc(enum smb2_command cmd, gfp_t gfp)
 		 * callback just wakes up the current task.
 		 */
 		smb->callback		= cifs_wake_up_task;
-		smb->callback_data	= current;
 		smb->mid_state		= MID_REQUEST_ALLOCATED;
+
+		init_waitqueue_head(&smb->waitq);
 	}
 	return smb;
 }
@@ -84,11 +85,11 @@ void smb_put_messages(struct smb_message *smb)
 }
 
 void
-cifs_wake_up_task(struct smb_message *smb)
+cifs_wake_up_task(struct TCP_Server_Info *server, struct smb_message *smb)
 {
 	if (smb->mid_state == MID_RESPONSE_RECEIVED)
 		smb->mid_state = MID_RESPONSE_READY;
-	wake_up_process(smb->callback_data);
+	wake_up_all(&smb->waitq);
 }
 
 static void smb_clear_mid(struct smb_message *smb, struct TCP_Server_Info *server)
@@ -163,7 +164,6 @@ static void smb_clear_mid(struct smb_message *smb, struct TCP_Server_Info *serve
 		}
 	}
 #endif
-	put_task_struct(smb->creator);
 }
 
 static bool discard_message(struct TCP_Server_Info *server, struct smb_message *smb)
@@ -817,7 +817,7 @@ int wait_for_response(struct TCP_Server_Info *server, struct smb_message *smb)
 	if (smb->sr_flags & CIFS_INTERRUPTIBLE_WAIT)
 		sleep_state = TASK_INTERRUPTIBLE;
 
-	error = wait_event_state(server->response_q,
+	error = wait_event_state(smb->waitq,
 				 smb->mid_state != MID_REQUEST_SUBMITTED &&
 				 smb->mid_state != MID_RESPONSE_RECEIVED,
 				 (sleep_state | TASK_FREEZABLE_UNSAFE));
@@ -948,9 +948,8 @@ int cifs_sync_mid_result(struct smb_message *smb, struct TCP_Server_Info *server
 }
 
 static void
-cifs_compound_callback(struct smb_message *smb)
+cifs_compound_callback(struct TCP_Server_Info *server, struct smb_message *smb)
 {
-	struct TCP_Server_Info *server = smb->server;
 	struct cifs_credits credits = {
 		.value = server->ops->get_credits(smb),
 		.instance = server->reconnect_instance,
@@ -963,16 +962,16 @@ cifs_compound_callback(struct smb_message *smb)
 }
 
 static void
-cifs_compound_last_callback(struct smb_message *smb)
+cifs_compound_last_callback(struct TCP_Server_Info *server, struct smb_message *smb)
 {
-	cifs_compound_callback(smb);
-	cifs_wake_up_task(smb);
+	cifs_compound_callback(server, smb);
+	cifs_wake_up_task(server, smb);
 }
 
 static void
-cifs_cancelled_callback(struct smb_message *smb)
+cifs_cancelled_callback(struct TCP_Server_Info *server, struct smb_message *smb)
 {
-	cifs_compound_callback(smb);
+	cifs_compound_callback(server, smb);
 }
 
 /*
@@ -1352,7 +1351,7 @@ __cifs_readv_discard(struct TCP_Server_Info *server, struct smb_message *smb,
 static int
 cifs_readv_discard(struct TCP_Server_Info *server, struct smb_message *smb)
 {
-	struct cifs_io_subrequest *rdata = smb->callback_data;
+	struct cifs_io_subrequest *rdata = smb->subreq;
 
 	return  __cifs_readv_discard(server, smb, rdata->result);
 }
@@ -1362,7 +1361,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct smb_message *smb)
 {
 	int length, len;
 	unsigned int data_offset, data_len;
-	struct cifs_io_subrequest *rdata = smb->callback_data;
+	struct cifs_io_subrequest *rdata = smb->subreq;
 	char *buf = server->smallbuf;
 	unsigned int buflen = server->pdu_size + HEADER_PREAMBLE_SIZE(server);
 	bool use_rdma_mr = false;


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 20/31] cifs: Don't need state locking in smb2_get_mid_entry()
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (18 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 19/31] cifs: Clean up mid->callback_data and kill off mid->creator David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 21/31] cifs: [DEBUG] smb_message refcounting David Howells
                   ` (14 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

There's no need to get ->srv_lock or ->ses_lock in smb2_get_mid_entry() as
all that happens of relevance (to the lock) inside the locked sections is
the reading of one status value in each.

Replace the locking with READ_ONCE() and use a switch instead of a chain of
if-statements.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/smb2transport.c | 46 +++++++++++++++--------------------
 1 file changed, 19 insertions(+), 27 deletions(-)

diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index 7c60584a8544..7194082bb5ac 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -769,43 +769,35 @@ static int
 smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server,
 		   struct smb_message *smb)
 {
-	spin_lock(&server->srv_lock);
-	if (server->tcpStatus == CifsExiting) {
-		spin_unlock(&server->srv_lock);
+	switch (READ_ONCE(server->tcpStatus)) {
+	case CifsExiting:
 		return -ENOENT;
-	}
-
-	if (server->tcpStatus == CifsNeedReconnect) {
-		spin_unlock(&server->srv_lock);
+	case CifsNeedReconnect:
 		cifs_dbg(FYI, "tcp session dead - return to caller to retry\n");
 		return -EAGAIN;
+	case CifsNeedNegotiate:
+		if (smb->command_id != SMB2_NEGOTIATE)
+			return -EAGAIN;
+		break;
+	default:
+		break;
 	}
 
-	if (server->tcpStatus == CifsNeedNegotiate &&
-	    smb->command_id != SMB2_NEGOTIATE) {
-		spin_unlock(&server->srv_lock);
-		return -EAGAIN;
-	}
-	spin_unlock(&server->srv_lock);
-
-	spin_lock(&ses->ses_lock);
-	if (ses->ses_status == SES_NEW) {
+	switch (READ_ONCE(ses->ses_status)) {
+	case SES_NEW:
 		if (smb->command_id != SMB2_SESSION_SETUP &&
-		    smb->command_id != SMB2_NEGOTIATE) {
-			spin_unlock(&ses->ses_lock);
+		    smb->command_id != SMB2_NEGOTIATE)
 			return -EAGAIN;
-		}
-		/* else ok - we are setting up session */
-	}
-
-	if (ses->ses_status == SES_EXITING) {
-		if (smb->command_id != SMB2_LOGOFF) {
-			spin_unlock(&ses->ses_lock);
+			/* else ok - we are setting up session */
+		break;
+	case SES_EXITING:
+		if (smb->command_id != SMB2_LOGOFF)
 			return -EAGAIN;
-		}
 		/* else ok - we are shutting down the session */
+		break;
+	default:
+		break;
 	}
-	spin_unlock(&ses->ses_lock);
 
 	smb2_init_mid(smb, server);
 


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 21/31] cifs: [DEBUG] smb_message refcounting
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (19 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 20/31] cifs: Don't need state locking in smb2_get_mid_entry() David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 22/31] cifs: Add netmem allocation functions David Howells
                   ` (13 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/cifsglob.h      |  1 +
 fs/smb/client/cifsproto.h     |  5 +--
 fs/smb/client/connect.c       | 14 +++++---
 fs/smb/client/smb2ops.c       |  3 +-
 fs/smb/client/smb2pdu.c       |  6 ++--
 fs/smb/client/smb2transport.c |  2 +-
 fs/smb/client/trace.h         | 61 +++++++++++++++++++++++++++++++++++
 fs/smb/client/transport.c     | 57 ++++++++++++++++++++++++++------
 8 files changed, 127 insertions(+), 22 deletions(-)

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 14b132fb14e0..045a29cedf0e 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -1734,6 +1734,7 @@ struct smb_message {
 	void			*request;	/* Pointer to request message body */
 	wait_queue_head_t	waitq;		/* Wait queue for message events */
 	refcount_t		ref;
+	unsigned int		debug_id;	/* Debugging ID for tracing */
 	bool			sensitive;	/* Request contains sensitive data */
 	bool			cancelled;	/* T if cancelled */
 	unsigned int		sr_flags;	/* Flags passed to send_recv() */
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index abae67d83499..074b65bb57a5 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -761,8 +761,9 @@ static inline void cifs_free_open_info(struct cifs_open_info_data *data)
 }
 
 struct smb_message *smb_message_alloc(enum smb2_command cmd, gfp_t gfp);
-void smb_get_message(struct smb_message *smb);
-void smb_put_message(struct smb_message *smb);
+void smb_see_message(struct smb_message *smb, enum smb_message_trace trace);
+void smb_get_message(struct smb_message *smb, enum smb_message_trace trace);
+void smb_put_message(struct smb_message *smb, enum smb_message_trace trace);
 void smb_put_messages(struct smb_message *smb);
 
 #endif			/* _CIFSPROTO_H */
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index 9bd19dd91d35..74b88304a782 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -323,6 +323,7 @@ cifs_abort_connection(struct TCP_Server_Info *server)
 	cifs_dbg(FYI, "%s: moving mids to private list\n", __func__);
 	spin_lock(&server->mid_lock);
 	list_for_each_entry_safe(smb, nsmb, &server->pending_mid_q, qhead) {
+		smb_see_message(smb, smb_message_trace_see_abort_conn);
 		if (smb->mid_state == MID_REQUEST_SUBMITTED)
 			smb->mid_state = MID_RETRY_NEEDED;
 		list_move(&smb->qhead, &retry_list);
@@ -335,7 +336,7 @@ cifs_abort_connection(struct TCP_Server_Info *server)
 	list_for_each_entry_safe(smb, nsmb, &retry_list, qhead) {
 		list_del_init(&smb->qhead);
 		smb->callback(server, smb);
-		smb_put_message(smb);
+		smb_put_message(smb, smb_message_trace_put_abort_conn);
 	}
 
 	if (cifs_rdma_enabled(server)) {
@@ -885,6 +886,7 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
 			 */
 			spin_lock(&server->mid_lock);
 			list_for_each_entry_safe(smb, nsmb, &server->pending_mid_q, qhead) {
+				smb_see_message(smb, smb_message_trace_see_is_smb_resp);
 				list_move(&smb->qhead, &dispose_list);
 				smb->mid_flags |= MID_DELETED;
 			}
@@ -918,7 +920,7 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
 				smb->mid_rc = mid_rc;
 				smb->mid_state = MID_RC;
 				smb->callback(server, smb);
-				smb_put_message(smb);
+				smb_put_message(smb, smb_message_trace_put_is_smb_resp);
 			}
 
 			/*
@@ -968,6 +970,7 @@ dequeue_mid(struct smb_message *smb, bool malformed)
 		spin_unlock(&smb->server->mid_lock);
 		pr_warn_once("trying to dequeue a deleted mid\n");
 	} else {
+		smb_see_message(smb, smb_message_trace_see_dequeue_mid);
 		list_del_init(&smb->qhead);
 		smb->mid_flags |= MID_DELETED;
 		spin_unlock(&smb->server->mid_lock);
@@ -1101,6 +1104,7 @@ clean_demultiplex_info(struct TCP_Server_Info *server)
 		spin_lock(&server->mid_lock);
 		list_for_each_entry_safe(smb, smb2, &server->pending_mid_q, qhead) {
 			cifs_dbg(FYI, "Clearing mid %llu\n", smb->mid);
+			smb_see_message(smb, smb_message_trace_see_clean_demux);
 			smb->mid_state = MID_SHUTDOWN;
 			list_move(&smb->qhead, &dispose_list);
 			smb->mid_flags |= MID_DELETED;
@@ -1112,7 +1116,7 @@ clean_demultiplex_info(struct TCP_Server_Info *server)
 			cifs_dbg(FYI, "Callback mid %llu\n", smb->mid);
 			list_del_init(&smb->qhead);
 			smb->callback(server, smb);
-			smb_put_message(smb);
+			smb_put_message(smb, smb_message_trace_put_clean_demux);
 		}
 		/* 1/8th of sec is more than enough time for them to exit */
 		msleep(125);
@@ -1355,7 +1359,7 @@ cifs_demultiplex_thread(void *p)
 		if (length < 0) {
 			for (i = 0; i < num_smbs; i++)
 				if (smbs[i])
-					smb_put_message(smbs[i]);
+					smb_put_message(smbs[i], smb_message_trace_put_demux);
 			continue;
 		}
 
@@ -1390,7 +1394,7 @@ cifs_demultiplex_thread(void *p)
 				if (!smbs[i]->multiRsp || smbs[i]->multiEnd)
 					smbs[i]->callback(server, smbs[i]);
 
-				smb_put_message(smbs[i]);
+				smb_put_message(smbs[i], smb_message_trace_put_demux_cb);
 			} else if (server->ops->is_oplock_break &&
 				   server->ops->is_oplock_break(bufs[i],
 								server)) {
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 63226bbba3d1..1e24489b55e3 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -408,6 +408,7 @@ __smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue)
 		if ((smb->mid == wire_mid) &&
 		    (smb->mid_state == MID_REQUEST_SUBMITTED) &&
 		    (smb->command_id == command)) {
+			smb_see_message(smb, smb_message_trace_see_find_mid);
 			if (dequeue) {
 				list_del_init(&smb->qhead);
 				smb->mid_flags |= MID_DELETED;
@@ -4726,7 +4727,7 @@ static void smb2_decrypt_offload(struct work_struct *work)
 				spin_unlock(&dw->server->srv_lock);
 			}
 		}
-		smb_put_message(smb);
+		smb_put_message(smb, smb_message_trace_put_decrypt_offload);
 	}
 
 free_pages:
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 8d50036fd028..3009acf0d884 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -4305,7 +4305,7 @@ SMB2_echo(struct TCP_Server_Info *server)
 		cifs_dbg(FYI, "Echo request failed: %d\n", rc);
 
 	cifs_small_buf_release(req);
-	smb_put_message(smb);
+	smb_put_messages(smb);
 	return rc;
 }
 
@@ -4753,7 +4753,7 @@ smb2_async_readv(struct cifs_io_subrequest *rdata)
 
 async_readv_out:
 	cifs_small_buf_release(buf);
-	smb_put_message(smb);
+	smb_put_messages(smb);
 	return rc;
 }
 
@@ -5127,7 +5127,7 @@ smb2_async_writev(struct cifs_io_subrequest *wdata)
 
 async_writev_out:
 	cifs_small_buf_release(req);
-	smb_put_message(smb);
+	smb_put_messages(smb);
 out:
 	if (rc) {
 		trace_smb3_rw_credits(wdata->rreq->debug_id,
diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index 7194082bb5ac..da6377521fe9 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -801,7 +801,7 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server,
 
 	smb2_init_mid(smb, server);
 
-	smb_get_message(smb);
+	smb_get_message(smb, smb_message_trace_get_enqueue_sync);
 	spin_lock(&server->mid_lock);
 	list_add_tail(&smb->qhead, &server->pending_mid_q);
 	spin_unlock(&server->mid_lock);
diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h
index 93e5b2bb9f28..5cee63960419 100644
--- a/fs/smb/client/trace.h
+++ b/fs/smb/client/trace.h
@@ -20,6 +20,45 @@
 /*
  * Specify enums for tracing information.
  */
+#define smb_message_traces \
+	EM(smb_message_trace_alloc_cancel,		"AL Cancel    ") \
+	EM(smb_message_trace_alloc_change_notify,	"AL Change-Nfy") \
+	EM(smb_message_trace_alloc_close,		"AL Close     ") \
+	EM(smb_message_trace_alloc_create,		"AL Create    ") \
+	EM(smb_message_trace_alloc_echo,		"AL Echo      ") \
+	EM(smb_message_trace_alloc_flush,		"AL Flush     ") \
+	EM(smb_message_trace_alloc_ioctl,		"AL Ioctl     ") \
+	EM(smb_message_trace_alloc_lock,		"AL Lock      ") \
+	EM(smb_message_trace_alloc_logoff,		"AL Logoff    ") \
+	EM(smb_message_trace_alloc_negotiate,		"AL Negotiate ") \
+	EM(smb_message_trace_alloc_oplock_break,	"AL Oplock-Brk") \
+	EM(smb_message_trace_alloc_query_directory,	"AL Query-Dir ") \
+	EM(smb_message_trace_alloc_query_info,		"AL Query-Info") \
+	EM(smb_message_trace_alloc_read,		"AL Read      ") \
+	EM(smb_message_trace_alloc_session_setup,	"AL Sess-setup") \
+	EM(smb_message_trace_alloc_set_info,		"AL Set-Info  ") \
+	EM(smb_message_trace_alloc_srv_to_cln_notif,	"AL s2c-Notify") \
+	EM(smb_message_trace_alloc_tree_connect,	"AL Tree-conn ") \
+	EM(smb_message_trace_alloc_tree_disconnect,	"AL Tree-disc ") \
+	EM(smb_message_trace_alloc_write,		"AL Write     ") \
+	EM(smb_message_trace_free,			"FREE         ") \
+	EM(smb_message_trace_get_call_async,		"GET call-asyn") \
+	EM(smb_message_trace_get_enqueue_sync,		"GET enq-sync ") \
+	EM(smb_message_trace_put_abort_conn,		"PUT abrt-conn") \
+	EM(smb_message_trace_put_clean_demux,		"PUT cln-demux") \
+	EM(smb_message_trace_put_decrypt_offload,	"PUT decrypt-o") \
+	EM(smb_message_trace_put_demux,			"PUT demux    ") \
+	EM(smb_message_trace_put_demux_cb,		"PUT demux-cb ") \
+	EM(smb_message_trace_put_discard_message,	"PUT disc-msg ") \
+	EM(smb_message_trace_put_is_smb_resp,		"PUT is-s-resp") \
+	EM(smb_message_trace_put_messages,		"PUT messages ") \
+	EM(smb_message_trace_see_abort_conn,		"SEE abrt-conn") \
+	EM(smb_message_trace_see_clean_demux,		"SEE cln-demux") \
+	EM(smb_message_trace_see_dequeue_mid,		"SEE deque-mid") \
+	EM(smb_message_trace_see_find_mid,		"SEE find-mid ") \
+	EM(smb_message_trace_see_is_smb_resp,		"SEE is-s-resp") \
+	E_(smb_message_trace_see_wake_up_task,		"SEE wake-task")
+
 #define smb3_rw_credits_traces \
 	EM(cifs_trace_rw_credits_call_readv_adjust,	"rd-call-adj") \
 	EM(cifs_trace_rw_credits_call_writev_adjust,	"wr-call-adj") \
@@ -79,6 +118,7 @@
 #define EM(a, b) a,
 #define E_(a, b) a
 
+enum smb_message_trace		{ smb_message_traces } __mode(byte);
 enum smb3_rw_credits_trace	{ smb3_rw_credits_traces } __mode(byte);
 enum smb3_tcon_ref_trace	{ smb3_tcon_ref_traces } __mode(byte);
 
@@ -92,6 +132,7 @@ enum smb3_tcon_ref_trace	{ smb3_tcon_ref_traces } __mode(byte);
 #define EM(a, b) TRACE_DEFINE_ENUM(a);
 #define E_(a, b) TRACE_DEFINE_ENUM(a);
 
+smb_message_traces;
 smb3_rw_credits_traces;
 smb3_tcon_ref_traces;
 
@@ -1573,6 +1614,26 @@ TRACE_EVENT(smb3_rw_credits,
 		      __entry->server_credits, __entry->in_flight)
 	    );
 
+TRACE_EVENT(smb3_message,
+	    TP_PROTO(unsigned int smb_message_debug_id, int ref,
+		     enum smb_message_trace trace),
+	    TP_ARGS(smb_message_debug_id, ref, trace),
+	    TP_STRUCT__entry(
+		    __field(unsigned int,		smb_message)
+		    __field(int,			ref)
+		    __field(enum smb_message_trace,	trace)
+			     ),
+	    TP_fast_assign(
+		    __entry->smb_message = smb_message_debug_id;
+		    __entry->ref	= ref;
+		    __entry->trace	= trace;
+			   ),
+	    TP_printk("SMB=%08x %s r=%d",
+		      __entry->smb_message,
+		      __print_symbolic(__entry->trace, smb_message_traces),
+		      __entry->ref)
+	    );
+
 
 #undef EM
 #undef E_
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index 7a4788b54a07..2ccfdd6b958b 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -34,12 +34,14 @@
 
 struct smb_message *smb_message_alloc(enum smb2_command cmd, gfp_t gfp)
 {
+	static atomic_t debug_ids;
 	struct smb_message *smb;
 
 	smb = mempool_alloc(&smb_message_pool, gfp);
 	if (smb) {
 		memset(smb, 0, sizeof(*smb));
 		refcount_set(&smb->ref, 1);
+		smb->debug_id	= atomic_inc_return(&debug_ids);
 		smb->command_id	= cmd;
 		smb->when_alloc	= jiffies;
 		smb->pid	= current->pid;
@@ -52,22 +54,47 @@ struct smb_message *smb_message_alloc(enum smb2_command cmd, gfp_t gfp)
 		smb->mid_state		= MID_REQUEST_ALLOCATED;
 
 		init_waitqueue_head(&smb->waitq);
+		trace_smb3_message(smb->debug_id, 1, (enum smb_message_trace)cmd);
 	}
 	return smb;
 }
 
-void smb_get_message(struct smb_message *smb)
+void smb_see_message(struct smb_message *smb, enum smb_message_trace trace)
 {
-	refcount_inc(&smb->ref);
+	trace_smb3_message(smb->debug_id, refcount_read(&smb->ref), trace);
+}
+
+void smb_get_message(struct smb_message *smb, enum smb_message_trace trace)
+{
+	int r;
+
+	__refcount_inc(&smb->ref, &r);
+	trace_smb3_message(smb->debug_id, r + 1, trace);
+	printk("GET SMB=%08x{%d} %pSR\n",
+	       smb->debug_id, r + 1, __builtin_return_address(0));
+}
+
+static void smb_free_message(struct smb_message *smb)
+{
+	trace_smb3_message(smb->debug_id, refcount_read(&smb->ref),
+			   smb_message_trace_free);
+	mempool_free(smb, &smb_message_pool);
 }
 
 /*
  * Drop a ref on a message.  This does not touch the chained messages.
  */
-void smb_put_message(struct smb_message *smb)
+void smb_put_message(struct smb_message *smb, enum smb_message_trace trace)
 {
-	if (refcount_dec_and_test(&smb->ref))
-		mempool_free(smb, &smb_message_pool);
+	unsigned int debug_id = smb->debug_id;
+	bool dead;
+	int r;
+
+	dead = __refcount_dec_and_test(&smb->ref, &r);
+	trace_smb3_message(debug_id, r - 1, trace);
+	printk("PUT SMB=%08x{%d} %pSR\n", debug_id, r - 1, __builtin_return_address(0));
+	if (dead)
+		smb_free_message(smb);
 }
 
 /*
@@ -79,8 +106,17 @@ void smb_put_messages(struct smb_message *smb)
 	struct smb_message *next;
 
 	for (; smb; smb = next) {
+		unsigned int debug_id = smb->debug_id;
+		bool dead;
+		int r;
+
 		next = smb->next;
-		smb_put_message(smb);
+		dead = __refcount_dec_and_test(&smb->ref, &r);
+		trace_smb3_message(debug_id, r - 1, smb_message_trace_put_messages);
+		printk("PUTS SMB=%08x{%d} %pSR\n",
+		       debug_id, r - 1, __builtin_return_address(0));
+		if (dead)
+			smb_free_message(smb);
 	}
 }
 
@@ -89,6 +125,7 @@ cifs_wake_up_task(struct TCP_Server_Info *server, struct smb_message *smb)
 {
 	if (smb->mid_state == MID_RESPONSE_RECEIVED)
 		smb->mid_state = MID_RESPONSE_READY;
+	smb_see_message(smb, smb_message_trace_see_wake_up_task);
 	wake_up_all(&smb->waitq);
 }
 
@@ -189,7 +226,7 @@ static void smb_discard_messages(struct TCP_Server_Info *server, struct smb_mess
 	for (smb = head_smb; smb; smb = next) {
 		next = smb->next;
 		if (discard_message(server, smb))
-			smb_put_message(smb);
+			smb_put_message(smb, smb_message_trace_put_discard_message);
 	}
 }
 
@@ -877,7 +914,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_message *smb,
 	smb->mid_state = MID_REQUEST_SUBMITTED;
 
 	/* put it on the pending_mid_q */
-	smb_get_message(smb);
+	smb_get_message(smb, smb_message_trace_get_call_async);
 	spin_lock(&server->mid_lock);
 	list_add_tail(&smb->qhead, &server->pending_mid_q);
 	spin_unlock(&server->mid_lock);
@@ -893,7 +930,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_message *smb,
 		revert_current_mid(server, smb->credits_consumed);
 		server->sequence_number -= 2;
 		if (discard_message(server, smb))
-			smb_put_message(smb);
+			smb_put_message(smb, smb_message_trace_put_discard_message);
 	}
 
 	cifs_server_unlock(server);
@@ -1295,7 +1332,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 	rc = smb_send_recv_messages(xid, ses, server, head_smb, flags);
 
 error:
-	smb_put_messages(smb);
+	smb_put_messages(head_smb);
 	return rc;
 }
 


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 22/31] cifs: Add netmem allocation functions
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (20 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 21/31] cifs: [DEBUG] smb_message refcounting David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 23/31] cifs: Add more pieces to smb_message David Howells
                   ` (12 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Add (stub) functions for doing netmem allocations.  We want to allocate
memory from the netmem buffering as that does bulk DMA and IOMMU
management.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/cifsproto.h |  3 +++
 fs/smb/client/transport.c | 15 +++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index 074b65bb57a5..ccd70a402567 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -766,4 +766,7 @@ void smb_get_message(struct smb_message *smb, enum smb_message_trace trace);
 void smb_put_message(struct smb_message *smb, enum smb_message_trace trace);
 void smb_put_messages(struct smb_message *smb);
 
+void *cifs_allocate_tx_buf(struct TCP_Server_Info *server, size_t size);
+void cifs_free_tx_buf(void *p);
+
 #endif			/* _CIFSPROTO_H */
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index 2ccfdd6b958b..b497bf319a7e 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -32,6 +32,21 @@
 #include "smbdirect.h"
 #include "compress.h"
 
+/*
+ * Allocate transmission buffers for a socket.  This memory will be allocated
+ * from the netmem buffers.  It comes with a page ref that we need to drop.
+ * The networking layer can pin it by getting its own ref.
+ */
+void *cifs_allocate_tx_buf(struct TCP_Server_Info *server, size_t size)
+{
+	return NULL; /* TODO */
+}
+
+void cifs_free_tx_buf(void *p)
+{
+	/* TODO */
+}
+
 struct smb_message *smb_message_alloc(enum smb2_command cmd, gfp_t gfp)
 {
 	static atomic_t debug_ids;


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 23/31] cifs: Add more pieces to smb_message
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (21 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 22/31] cifs: Add netmem allocation functions David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 24/31] cifs: Convert SMB2 Negotiate Protocol request David Howells
                   ` (11 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Add more pieces to the smb_message struct to facilitate future changes.

Also move towards not needing the server pointer in smb_message.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/cifsglob.h      |   7 ++
 fs/smb/client/cifsproto.h     |  15 +++
 fs/smb/client/cifstransport.c |   2 +-
 fs/smb/client/smb2ops.c       |  10 ++
 fs/smb/client/smb2pdu.c       | 198 ++++++++++++++++++++++++++++++++++
 fs/smb/client/smb2proto.h     |   1 +
 fs/smb/client/transport.c     |  28 ++++-
 7 files changed, 259 insertions(+), 2 deletions(-)

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 045a29cedf0e..0cc71f504c68 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -1774,7 +1774,12 @@ struct smb_message {
 	/* Request details */
 	enum smb2_command	command_id;	/* Command ID */
 	s16			pre_offset;	/* Offset of pre-headers from ->body (negative) */
+	u16			ext_offset;	/* Offset of extensions from ->body */
+	u16			latest_record;	/* Offset of latest context record (or 0) */
+	u16			offset;		/* Running offset during assembly */
+	u16			data_offset;	/* Offset of data in message (maybe in ->body) */
 	unsigned int		total_len;	/* Total length of from hdr_offset onwards */
+	struct iov_iter		iter;		/* Data iterator */
 	/* Response */
 	void			*response;	/* Protocol part of response */
 	u32			response_len;	/* Size of response */
@@ -1782,6 +1787,8 @@ struct smb_message {
 	struct smb_rqst		rqst;
 	int			*resp_buf_type;
 	struct kvec		*resp_iov;
+	/* Variable-length request fragment list - must be last! */
+	struct bvecq		bvecq;		/* List of request frags (passed to socket) */
 };
 
 struct close_cancelled_open {
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index ccd70a402567..60a0c9b64d98 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -765,8 +765,23 @@ void smb_see_message(struct smb_message *smb, enum smb_message_trace trace);
 void smb_get_message(struct smb_message *smb, enum smb_message_trace trace);
 void smb_put_message(struct smb_message *smb, enum smb_message_trace trace);
 void smb_put_messages(struct smb_message *smb);
+void smb_clear_request(struct smb_message *smb);
 
 void *cifs_allocate_tx_buf(struct TCP_Server_Info *server, size_t size);
 void cifs_free_tx_buf(void *p);
 
+/*
+ * Add a segment to a message.  This should be allocated with
+ * cifs_allocate_tx_buf() so that it can be used with MSG_SPLICE_PAGES.
+ */
+static inline void smb_add_segment_to_tx_buf(struct smb_message *smb,
+					     void *key_buf, size_t size)
+{
+	unsigned int nr = smb->bvecq.nr_segs;
+
+	bvec_set_virt(&smb->bvecq.bv[nr], key_buf, size);
+	smb->bvecq.nr_segs = nr++;
+	smb->total_len += size;
+}
+
 #endif			/* _CIFSPROTO_H */
diff --git a/fs/smb/client/cifstransport.c b/fs/smb/client/cifstransport.c
index 1e2a8839d742..b93dd2be68e1 100644
--- a/fs/smb/client/cifstransport.c
+++ b/fs/smb/client/cifstransport.c
@@ -177,7 +177,7 @@ cifs_check_receive(struct smb_message *smb, struct TCP_Server_Info *server,
 	}
 
 	/* BB special case reconnect tid and uid here? */
-	return map_and_check_smb_error(smb, log_error);
+	return map_and_check_smb_error(server, smb, log_error);
 }
 
 int
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 1e24489b55e3..9db383ec22e8 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -2602,6 +2602,16 @@ smb2_set_replay(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 	shdr->Flags |= SMB2_FLAGS_REPLAY_OPERATION;
 }
 
+void smb2_set_replay_smb(struct TCP_Server_Info *server, struct smb_message *smb)
+{
+	struct smb2_hdr *shdr = smb->request;
+
+	if (server->dialect < SMB30_PROT_ID)
+		return;
+
+	shdr->Flags |= SMB2_FLAGS_REPLAY_OPERATION;
+}
+
 void
 smb2_set_related(struct smb_rqst *rqst)
 {
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 3009acf0d884..58a2a4ff3368 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -91,6 +91,204 @@ int smb3_encryption_required(const struct cifs_tcon *tcon)
 	return 0;
 }
 
+static void smb2_enc_header(struct smb_message *smb,
+			    const struct cifs_tcon *tcon,
+			    struct TCP_Server_Info *server)
+{
+	struct smb2_hdr *shdr = smb->request;
+	struct smb3_hdr_req *smb3_hdr = (struct smb3_hdr_req *)shdr;
+
+	shdr->ProtocolId	= SMB2_PROTO_NUMBER;
+	shdr->StructureSize	= cpu_to_le16(64);
+	shdr->CreditCharge	= 0;
+	shdr->Status		= 0; /* ChanSeq for smb3 */
+	shdr->Command		= cpu_to_le16(smb->command_id);
+	shdr->CreditRequest	= cpu_to_le16(2);
+	shdr->Flags		= 0;
+	shdr->NextCommand	= 0;
+	shdr->MessageId		= 0;
+	shdr->Id.SyncId.ProcessId = cpu_to_le32((__u16)current->tgid);
+	shdr->SessionId		= 0;
+
+	if (server) {
+		/* After reconnect SMB3 must set ChannelSequence on subsequent reqs */
+		if (server->dialect >= SMB30_PROT_ID) {
+			/*
+			 * if primary channel is not set yet, use default
+			 * channel for chan sequence num
+			 */
+			if (SERVER_IS_CHAN(server))
+				smb3_hdr->ChannelSequence =
+					cpu_to_le16(server->primary_server->channel_sequence_num);
+			else
+				smb3_hdr->ChannelSequence =
+					cpu_to_le16(server->channel_sequence_num);
+		}
+		spin_lock(&server->req_lock);
+		/* Request up to 10 credits but don't go over the limit. */
+		if (server->credits >= server->max_credits)
+			shdr->CreditRequest = cpu_to_le16(0);
+		else
+			shdr->CreditRequest = cpu_to_le16(
+				min_t(int, server->max_credits -
+						server->credits, 10));
+		spin_unlock(&server->req_lock);
+	}
+
+	if (tcon) {
+		/* GLOBAL_CAP_LARGE_MTU will only be set if dialect > SMB2.02 */
+		/* See sections 2.2.4 and 3.2.4.1.5 of MS-SMB2 */
+		if (server && (server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
+			shdr->CreditCharge = cpu_to_le16(1);
+		/* else CreditCharge MBZ */
+
+		shdr->Id.SyncId.TreeId = cpu_to_le32(tcon->tid);
+		/* Uid is not converted */
+		if (tcon->ses)
+			shdr->SessionId = cpu_to_le64(tcon->ses->Suid);
+
+		/*
+		 * If we would set SMB2_FLAGS_DFS_OPERATIONS on open we also
+		 * would have to pass the path on the Open SMB prefixed by
+		 * \\server\share.  Not sure when we would need to do the
+		 * augmented path (if ever) and setting this flag breaks the
+		 * SMB2 open operation since it is illegal to send an empty
+		 * path name (without \\server\share prefix) when the DFS flag
+		 * is set in the SMB open header. We could consider setting the
+		 * flag on all operations other than open but it is safer to
+		 * net set it for now.
+		 */
+/*	if (tcon->share_flags & SHI1005_FLAGS_DFS)
+	shdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS; */
+
+		if (server && server->sign && !smb3_encryption_required(tcon))
+			shdr->Flags |= SMB2_FLAGS_SIGNED;
+	}
+}
+
+/* Flags for smb2_create_request() */
+#define SMB2_REQ_DYNAMIC	0x01	/* Dynamic request */
+#define SMB2_REQ_HEAD		0x02	/* Head of compound */
+#define SMB2_REQ_SENSITIVE	0x04	/* May contain sensitive crypto data */
+
+/*
+ * smb2_create_request: Allocate and set up a request
+ * @command: The command type we're going to issue
+ * @server: The server the command is going to go to
+ * @header_size: The size of the base protocol structure
+ * @protocol_size: The size of the header plus extensions
+ * @data_size: The size of the data payload
+ * @head: If this is the head of a compound
+ * @flags: Mask of SMB2_REQ_* flags
+ *
+ * Create a request and allocate netmem memory to hold the netbios header (if
+ * appropriate) and the protocol part of the message.  Memory will also be
+ * allocated for the data part of the message if this is to be encrypted by the
+ * CPU.  The allocated buffers will be attached to a bvec-queue struct so that
+ * they can be chained together and passed to the socket.
+ */
+static struct smb_message *smb2_create_request(enum smb2_command command,
+					       struct TCP_Server_Info *server,
+					       struct cifs_tcon *tcon,
+					       size_t header_size,
+					       size_t protocol_size,
+					       size_t data_size,
+					       unsigned int flags)
+{
+	struct smb_message *smb;
+	const size_t max_segs = 3; /* We preallocate 3 segment slots in the message */
+	size_t pre_size;
+	void *body;
+	bool encrypted = false; //, rdma = false;
+	u16 ssize;
+
+	smb = kzalloc(struct_size(smb, bvecq.bv, max_segs), GFP_NOFS);
+	if (!smb)
+		return NULL;
+
+	smb->command_id = command;
+	smb->sensitive = flags & SMB2_REQ_SENSITIVE;
+
+	/* We allocate space for inter-SMB padding or rfc1002 header plus
+	 * transform headers (as needed), but don't add them in at this time.
+	 */
+	pre_size = 8;
+	if (encrypted)
+		pre_size += sizeof(struct smb2_transform_hdr);
+	smb->pre_offset = -pre_size;
+
+	if (encrypted)
+		/* We want the encrypted blob to be correctly aligned. */
+		pre_size = round_up(pre_size, 16);
+
+	/* Allocate space for the SMB header, the request struct (both in
+	 * header_size) plus any extension bits, bearing in mind that some bits
+	 * may follow the header directly (header_added_size) and some may have
+	 * to be padded to an 8-byte alignment first (extension_size).  The
+	 * Negotiate Request has both.
+	 */
+	smb->ext_offset	 = header_size;
+	smb->offset	 = header_size;
+	smb->data_offset = protocol_size;
+	smb->total_len	 = protocol_size;
+
+	body = cifs_allocate_tx_buf(server, pre_size + protocol_size);
+	if (!body) {
+		kfree(smb);
+		return NULL;
+	}
+
+	smb_add_segment_to_tx_buf(smb, body + pre_size, protocol_size);
+	smb->request = body + pre_size;
+	smb->bvecq.max_segs = max_segs;
+
+	struct smb2_pdu *spdu = body;
+
+	smb2_enc_header(smb, tcon, server);
+	ssize = header_size - sizeof(spdu->hdr);
+	if (flags & SMB2_REQ_DYNAMIC)
+		ssize |= SMB2_STRUCT_HAS_DYNAMIC_PART;
+	spdu->StructureSize2 = cpu_to_le16(ssize);
+
+	if (tcon) {
+		cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_sent[command]);
+		cifs_stats_inc(&tcon->num_smbs_sent);
+	}
+
+	/* Include the buffer from the start of the RFC1002 header in the
+	 * iterator, but may need to adjust it later.
+	 */
+	iov_iter_bvec_queue(&smb->iter, ITER_SOURCE, &smb->bvecq, 0,
+			    pre_size, protocol_size);
+
+	return smb;
+}
+
+static void cifs_pad_to_8(struct smb_message *smb)
+{
+	size_t offset = smb->offset;
+	u8 *p = smb->request;
+
+	while (offset & 7)
+		p[offset++] = 0;
+	smb->offset = offset;
+}
+
+/*
+ * Begin adding an extension to a message.  The offset is padded to an 8-byte
+ * alignment;
+ */
+static void *cifs_begin_extension(struct smb_message *smb)
+{
+	cifs_pad_to_8(smb);
+	return smb->request + smb->offset;
+}
+
+static void cifs_end_extension(struct smb_message *smb, size_t size)
+{
+	smb->offset += size;
+}
+
 static void
 smb2_hdr_assemble(struct smb2_hdr *shdr, enum smb2_command smb2_cmd,
 		  const struct cifs_tcon *tcon,
diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h
index 3018b171c6de..22284a52f300 100644
--- a/fs/smb/client/smb2proto.h
+++ b/fs/smb/client/smb2proto.h
@@ -131,6 +131,7 @@ extern void smb2_set_next_command(struct cifs_tcon *tcon,
 extern void smb2_set_related(struct smb_rqst *rqst);
 extern void smb2_set_replay(struct TCP_Server_Info *server,
 			    struct smb_rqst *rqst);
+void smb2_set_replay_smb(struct TCP_Server_Info *server, struct smb_message *smb);
 extern bool smb2_should_replay(struct cifs_tcon *tcon,
 			  int *pretries,
 			  int *pcur_sleep);
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index b497bf319a7e..1d732953a90b 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -93,9 +93,31 @@ static void smb_free_message(struct smb_message *smb)
 {
 	trace_smb3_message(smb->debug_id, refcount_read(&smb->ref),
 			   smb_message_trace_free);
+	cifs_free_tx_buf(smb->request);
 	mempool_free(smb, &smb_message_pool);
 }
 
+/*
+ * Clear the request parts of a message.
+ */
+void smb_clear_request(struct smb_message *smb)
+{
+	for (; smb; smb = smb->next) {
+		if (smb->request) {
+			if (smb->sensitive) {
+				iov_iter_bvec_queue(&smb->iter, ITER_SOURCE,
+						    &smb->bvecq, 3,
+						    -smb->pre_offset,
+						    smb->ext_offset - -smb->pre_offset);
+				iov_iter_zero(smb->ext_offset - -smb->pre_offset,
+					      &smb->iter);
+			}
+			cifs_free_tx_buf(smb->request);
+			smb->request = NULL;
+		}
+	}
+}
+
 /*
  * Drop a ref on a message.  This does not touch the chained messages.
  */
@@ -120,6 +142,8 @@ void smb_put_messages(struct smb_message *smb)
 {
 	struct smb_message *next;
 
+	smb_clear_request(smb);
+
 	for (; smb; smb = next) {
 		unsigned int debug_id = smb->debug_id;
 		bool dead;
@@ -1099,9 +1123,11 @@ int smb_send_recv_messages(const unsigned int xid, struct cifs_ses *ses,
 	optype = flags & CIFS_OP_MASK;
 
 	/* TODO: Stitch together the messages in a compound. */
+	//u32 last_next = 0;
 	nr_reqs = 0;
-	for (struct smb_message *smb = head_smb; smb; smb = smb->next)
+	for (struct smb_message *smb = head_smb; smb; smb = smb->next) {
 		nr_reqs++;
+	}
 
 	spin_lock(&server->srv_lock);
 	if (server->tcpStatus == CifsExiting) {


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 24/31] cifs: Convert SMB2 Negotiate Protocol request
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (22 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 23/31] cifs: Add more pieces to smb_message David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-08 14:44   ` Enzo Matsumiya
  2025-08-08 15:10   ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 25/31] cifs: Convert SMB2 Session Setup request David Howells
                   ` (10 subsequent siblings)
  34 siblings, 2 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/smb2pdu.c | 509 ++++++++++++++++++++++++----------------
 fs/smb/common/smb2pdu.h |  24 +-
 fs/smb/server/smb2pdu.c |  22 +-
 3 files changed, 319 insertions(+), 236 deletions(-)

diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 58a2a4ff3368..f1b6d36fe7cd 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -788,144 +788,200 @@ static int smb2_ioctl_req_init(u32 opcode, struct cifs_tcon *tcon,
 
 /* For explanation of negotiate contexts see MS-SMB2 section 2.2.3.1 */
 
-static void
-build_preauth_ctxt(struct smb2_preauth_neg_context *pneg_ctxt)
+static void *cifs_begin_neg_context(struct smb_message *smb,
+				    __le16 context_type)
 {
-	pneg_ctxt->ContextType = SMB2_PREAUTH_INTEGRITY_CAPABILITIES;
-	pneg_ctxt->DataLength = cpu_to_le16(38);
-	pneg_ctxt->HashAlgorithmCount = cpu_to_le16(1);
-	pneg_ctxt->SaltLength = cpu_to_le16(SMB311_SALT_SIZE);
-	get_random_bytes(pneg_ctxt->Salt, SMB311_SALT_SIZE);
-	pneg_ctxt->HashAlgorithms = SMB2_PREAUTH_INTEGRITY_SHA512;
+	struct smb2_neg_context *neg;
+
+	neg = cifs_begin_extension(smb);
+	neg->ContextType	= context_type;
+	neg->Reserved		= 0;
+	return (void *)neg;
 }
 
-static void
-build_compression_ctxt(struct smb2_compression_capabilities_context *pneg_ctxt)
+static void cifs_end_neg_context(struct smb_message *smb, void *p, size_t size)
+{
+	struct smb2_neg_context *neg = p;
+
+	neg->DataLength = cpu_to_le16(size - sizeof(*neg));
+	cifs_end_extension(smb, size);
+}
+
+static void build_preauth_ctxt(struct smb_message *smb)
 {
-	pneg_ctxt->ContextType = SMB2_COMPRESSION_CAPABILITIES;
-	pneg_ctxt->DataLength =
-		cpu_to_le16(sizeof(struct smb2_compression_capabilities_context)
-			  - sizeof(struct smb2_neg_context));
-	pneg_ctxt->CompressionAlgorithmCount = cpu_to_le16(3);
-	pneg_ctxt->CompressionAlgorithms[0] = SMB3_COMPRESS_LZ77;
-	pneg_ctxt->CompressionAlgorithms[1] = SMB3_COMPRESS_LZ77_HUFF;
-	pneg_ctxt->CompressionAlgorithms[2] = SMB3_COMPRESS_LZNT1;
+	struct smb2_preauth_neg_context *preauth;
+
+	preauth = cifs_begin_neg_context(smb, SMB2_PREAUTH_INTEGRITY_CAPABILITIES);
+	preauth->HashAlgorithmCount	= cpu_to_le16(1);
+	preauth->SaltLength		= cpu_to_le16(SMB311_SALT_SIZE);
+	preauth->HashAlgorithms		= SMB2_PREAUTH_INTEGRITY_SHA512;
+	get_random_bytes(preauth->Salt, SMB311_SALT_SIZE);
+	cifs_end_neg_context(smb, preauth, sizeof(*preauth));
 }
 
-static unsigned int
-build_signing_ctxt(struct smb2_signing_capabilities *pneg_ctxt)
+static void build_compression_ctxt(struct smb_message *smb)
+{
+	struct smb2_compression_capabilities_context *compr;
+
+	compr = cifs_begin_neg_context(smb, SMB2_COMPRESSION_CAPABILITIES);
+	compr->CompressionAlgorithmCount = cpu_to_le16(3);
+	compr->CompressionAlgorithms[0] = SMB3_COMPRESS_LZ77;
+	compr->CompressionAlgorithms[1] = SMB3_COMPRESS_LZ77_HUFF;
+	compr->CompressionAlgorithms[2] = SMB3_COMPRESS_LZNT1;
+	cifs_end_neg_context(smb, compr, sizeof(*compr));
+}
+
+static size_t smb2_size_signing_ctxt(void)
+{
+	size_t ctxt_len = sizeof(struct smb2_signing_capabilities);
+	unsigned short num_algs = 1; /* number of signing algorithms sent */
+
+	ctxt_len += sizeof(__le16) * num_algs;
+	return ALIGN8(ctxt_len);
+}
+
+static void build_signing_ctxt(struct smb_message *smb)
 {
-	unsigned int ctxt_len = sizeof(struct smb2_signing_capabilities);
+	struct smb2_signing_capabilities *scap;
 	unsigned short num_algs = 1; /* number of signing algorithms sent */
 
-	pneg_ctxt->ContextType = SMB2_SIGNING_CAPABILITIES;
+	scap = cifs_begin_neg_context(smb, SMB2_SIGNING_CAPABILITIES);
+	scap->SigningAlgorithmCount = cpu_to_le16(num_algs);
+	scap->SigningAlgorithms[0] = cpu_to_le16(SIGNING_ALG_AES_CMAC);
+	/* TBD add SIGNING_ALG_AES_GMAC and/or SIGNING_ALG_HMAC_SHA256 */
+
 	/*
 	 * Context Data length must be rounded to multiple of 8 for some servers
 	 */
-	pneg_ctxt->DataLength = cpu_to_le16(ALIGN8(sizeof(struct smb2_signing_capabilities) -
-					    sizeof(struct smb2_neg_context) +
-					    (num_algs * sizeof(u16))));
-	pneg_ctxt->SigningAlgorithmCount = cpu_to_le16(num_algs);
-	pneg_ctxt->SigningAlgorithms[0] = cpu_to_le16(SIGNING_ALG_AES_CMAC);
-
-	ctxt_len += sizeof(__le16) * num_algs;
-	ctxt_len = ALIGN8(ctxt_len);
-	return ctxt_len;
-	/* TBD add SIGNING_ALG_AES_GMAC and/or SIGNING_ALG_HMAC_SHA256 */
+	cifs_end_neg_context(smb, scap,
+			     ALIGN8(struct_size(scap, SigningAlgorithms, num_algs)));
 }
 
-static void
-build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt)
+static void build_encrypt_ctxt(struct smb_message *smb)
 {
-	pneg_ctxt->ContextType = SMB2_ENCRYPTION_CAPABILITIES;
-	if (require_gcm_256) {
-		pneg_ctxt->DataLength = cpu_to_le16(4); /* Cipher Count + 1 cipher */
-		pneg_ctxt->CipherCount = cpu_to_le16(1);
-		pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES256_GCM;
-	} else if (enable_gcm_256) {
-		pneg_ctxt->DataLength = cpu_to_le16(8); /* Cipher Count + 3 ciphers */
-		pneg_ctxt->CipherCount = cpu_to_le16(3);
-		pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_GCM;
-		pneg_ctxt->Ciphers[1] = SMB2_ENCRYPTION_AES256_GCM;
-		pneg_ctxt->Ciphers[2] = SMB2_ENCRYPTION_AES128_CCM;
+	struct smb2_encryption_neg_context *ecap;
+	size_t count;
+
+	ecap = cifs_begin_neg_context(smb, SMB2_ENCRYPTION_CAPABILITIES);
+
+	if (READ_ONCE(require_gcm_256)) {
+		ecap->Ciphers[0]  = SMB2_ENCRYPTION_AES256_GCM;
+		count = 1;
+	} else if (READ_ONCE(enable_gcm_256)) {
+		ecap->Ciphers[0]  = SMB2_ENCRYPTION_AES128_GCM;
+		ecap->Ciphers[1]  = SMB2_ENCRYPTION_AES256_GCM;
+		ecap->Ciphers[2]  = SMB2_ENCRYPTION_AES128_CCM;
+		count = 3;
 	} else {
-		pneg_ctxt->DataLength = cpu_to_le16(6); /* Cipher Count + 2 ciphers */
-		pneg_ctxt->CipherCount = cpu_to_le16(2);
-		pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_GCM;
-		pneg_ctxt->Ciphers[1] = SMB2_ENCRYPTION_AES128_CCM;
+		ecap->Ciphers[0]  = SMB2_ENCRYPTION_AES128_GCM;
+		ecap->Ciphers[1]  = SMB2_ENCRYPTION_AES128_CCM;
+		count = 2;
 	}
+	ecap->CipherCount = cpu_to_le16(count);
+	cifs_end_neg_context(smb, ecap, struct_size(ecap, Ciphers, count));
 }
 
-static unsigned int
-build_netname_ctxt(struct smb2_netname_neg_context *pneg_ctxt, char *hostname)
+static size_t smb2_size_netname_ctxt(struct TCP_Server_Info *server)
 {
+	size_t data_len;
+
+#if 0
 	struct nls_table *cp = load_nls_default();
+	const char *hostname;
 
-	pneg_ctxt->ContextType = SMB2_NETNAME_NEGOTIATE_CONTEXT_ID;
+	/* Only include up to first 100 bytes of server name in the NetName
+	 * field.
+	 */
+	cifs_server_lock(pserver);
+	hostname = pserver->hostname;
+	if (hostname && hostname[0])
+		data_len = cifs_size_strtoUTF16(hostname, 100, cp);
+	cifs_server_unlock(pserver);
+#else
+	/* Now, we can't just measure the length of hostname as, unless we hold
+	 * the lock, it may change under us, so allow maximum space for it.
+	 */
+	data_len = 400;
+#endif
+	return ALIGN8(sizeof(struct smb2_neg_context) + data_len);
+}
+
+static void build_netname_ctxt(struct smb_message *smb, const char *hostname)
+{
+	struct smb2_netname_neg_context *name;
+	struct nls_table *cp = load_nls_default();
+	size_t count;
+
+	name = cifs_begin_neg_context(smb, SMB2_NETNAME_NEGOTIATE_CONTEXT_ID);
 
 	/* copy up to max of first 100 bytes of server name to NetName field */
-	pneg_ctxt->DataLength = cpu_to_le16(2 * cifs_strtoUTF16(pneg_ctxt->NetName, hostname, 100, cp));
-	/* context size is DataLength + minimal smb2_neg_context */
-	return ALIGN8(le16_to_cpu(pneg_ctxt->DataLength) + sizeof(struct smb2_neg_context));
+	count = cifs_strtoUTF16(name->NetName, hostname, 100, cp);
+	cifs_end_neg_context(smb, name, struct_size(name, NetName, count));
 }
 
-static void
-build_posix_ctxt(struct smb2_posix_neg_context *pneg_ctxt)
+static void build_posix_ctxt(struct smb_message *smb)
 {
-	pneg_ctxt->ContextType = SMB2_POSIX_EXTENSIONS_AVAILABLE;
-	pneg_ctxt->DataLength = cpu_to_le16(POSIX_CTXT_DATA_LEN);
+	struct smb2_posix_neg_context *posix;
+
+	posix = cifs_begin_neg_context(smb, SMB2_POSIX_EXTENSIONS_AVAILABLE);
 	/* SMB2_CREATE_TAG_POSIX is "0x93AD25509CB411E7B42383DE968BCD7C" */
-	pneg_ctxt->Name[0] = 0x93;
-	pneg_ctxt->Name[1] = 0xAD;
-	pneg_ctxt->Name[2] = 0x25;
-	pneg_ctxt->Name[3] = 0x50;
-	pneg_ctxt->Name[4] = 0x9C;
-	pneg_ctxt->Name[5] = 0xB4;
-	pneg_ctxt->Name[6] = 0x11;
-	pneg_ctxt->Name[7] = 0xE7;
-	pneg_ctxt->Name[8] = 0xB4;
-	pneg_ctxt->Name[9] = 0x23;
-	pneg_ctxt->Name[10] = 0x83;
-	pneg_ctxt->Name[11] = 0xDE;
-	pneg_ctxt->Name[12] = 0x96;
-	pneg_ctxt->Name[13] = 0x8B;
-	pneg_ctxt->Name[14] = 0xCD;
-	pneg_ctxt->Name[15] = 0x7C;
+	posix->Name[0] = 0x93;
+	posix->Name[1] = 0xAD;
+	posix->Name[2] = 0x25;
+	posix->Name[3] = 0x50;
+	posix->Name[4] = 0x9C;
+	posix->Name[5] = 0xB4;
+	posix->Name[6] = 0x11;
+	posix->Name[7] = 0xE7;
+	posix->Name[8] = 0xB4;
+	posix->Name[9] = 0x23;
+	posix->Name[10] = 0x83;
+	posix->Name[11] = 0xDE;
+	posix->Name[12] = 0x96;
+	posix->Name[13] = 0x8B;
+	posix->Name[14] = 0xCD;
+	posix->Name[15] = 0x7C;
+	cifs_end_neg_context(smb, posix, sizeof(posix));
 }
 
-static void
-assemble_neg_contexts(struct smb2_negotiate_req *req,
-		      struct TCP_Server_Info *server, unsigned int *total_len)
+static size_t smb2_size_neg_contexts(struct TCP_Server_Info *server,
+				     size_t offset)
 {
-	unsigned int ctxt_len, neg_context_count;
 	struct TCP_Server_Info *pserver;
-	char *pneg_ctxt;
-	char *hostname;
-
-	if (*total_len > 200) {
-		/* In case length corrupted don't want to overrun smb buffer */
-		cifs_server_dbg(VFS, "Bad frame length assembling neg contexts\n");
-		return;
-	}
 
 	/*
 	 * round up total_len of fixed part of SMB3 negotiate request to 8
 	 * byte boundary before adding negotiate contexts
 	 */
-	*total_len = ALIGN8(*total_len);
+	offset = ALIGN8(offset);
+	offset += ALIGN8(sizeof(struct smb2_preauth_neg_context));
+	offset += ALIGN8(sizeof(struct smb2_encryption_neg_context));
 
-	pneg_ctxt = (*total_len) + (char *)req;
-	req->NegotiateContextOffset = cpu_to_le32(*total_len);
+	/*
+	 * secondary channels don't have the hostname field populated
+	 * use the hostname field in the primary channel instead
+	 */
+	pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
+	offset += smb2_size_netname_ctxt(pserver);
+
+	offset += ALIGN8(sizeof(struct smb2_posix_neg_context));
+	if (server->compression.requested)
+		offset += ALIGN8(sizeof(struct smb2_compression_capabilities_context));
+	if (enable_negotiate_signing)
+		offset += smb2_size_signing_ctxt();
+	return offset;
+}
 
-	build_preauth_ctxt((struct smb2_preauth_neg_context *)pneg_ctxt);
-	ctxt_len = ALIGN8(sizeof(struct smb2_preauth_neg_context));
-	*total_len += ctxt_len;
-	pneg_ctxt += ctxt_len;
+static void
+assemble_neg_contexts(struct smb_message *smb, struct TCP_Server_Info *server)
+{
+	struct smb2_negotiate_req *req;
+	struct TCP_Server_Info *pserver;
+	const char *hostname;
+	unsigned int neg_context_count = 2;
 
-	build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt);
-	ctxt_len = ALIGN8(sizeof(struct smb2_encryption_neg_context));
-	*total_len += ctxt_len;
-	pneg_ctxt += ctxt_len;
+	build_preauth_ctxt(smb);
+	build_encrypt_ctxt(smb);
 
 	/*
 	 * secondary channels don't have the hostname field populated
@@ -934,47 +990,36 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
 	pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
 	cifs_server_lock(pserver);
 	hostname = pserver->hostname;
-	if (hostname && (hostname[0] != 0)) {
-		ctxt_len = build_netname_ctxt((struct smb2_netname_neg_context *)pneg_ctxt,
-					      hostname);
-		*total_len += ctxt_len;
-		pneg_ctxt += ctxt_len;
-		neg_context_count = 3;
-	} else
-		neg_context_count = 2;
+	if (hostname && hostname[0]) {
+		build_netname_ctxt(smb, hostname);
+		neg_context_count++;
+	}
 	cifs_server_unlock(pserver);
 
-	build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
-	*total_len += sizeof(struct smb2_posix_neg_context);
-	pneg_ctxt += sizeof(struct smb2_posix_neg_context);
+	build_posix_ctxt(smb);
 	neg_context_count++;
 
 	if (server->compression.requested) {
-		build_compression_ctxt((struct smb2_compression_capabilities_context *)
-				pneg_ctxt);
-		ctxt_len = ALIGN8(sizeof(struct smb2_compression_capabilities_context));
-		*total_len += ctxt_len;
-		pneg_ctxt += ctxt_len;
+		build_compression_ctxt(smb);
 		neg_context_count++;
 	}
 
 	if (enable_negotiate_signing) {
-		ctxt_len = build_signing_ctxt((struct smb2_signing_capabilities *)
-				pneg_ctxt);
-		*total_len += ctxt_len;
-		pneg_ctxt += ctxt_len;
+		build_signing_ctxt(smb);
 		neg_context_count++;
 	}
 
 	/* check for and add transport_capabilities and signing capabilities */
+	req = smb->request;
 	req->NegotiateContextCount = cpu_to_le16(neg_context_count);
-
 }
 
 /* If invalid preauth context warn but use what we requested, SHA-512 */
-static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt)
+static void decode_preauth_context(struct smb2_neg_context *neg)
 {
-	unsigned int len = le16_to_cpu(ctxt->DataLength);
+	struct smb2_preauth_neg_context *ctxt =
+		container_of(neg, struct smb2_preauth_neg_context, neg);
+	unsigned int len = le16_to_cpu(ctxt->neg.DataLength);
 
 	/*
 	 * Caller checked that DataLength remains within SMB boundary. We still
@@ -994,9 +1039,11 @@ static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt)
 }
 
 static void decode_compress_ctx(struct TCP_Server_Info *server,
-			 struct smb2_compression_capabilities_context *ctxt)
+				struct smb2_neg_context *neg)
 {
-	unsigned int len = le16_to_cpu(ctxt->DataLength);
+	struct smb2_compression_capabilities_context *ctxt =
+		container_of(neg, struct smb2_compression_capabilities_context, neg);
+	unsigned int len = le16_to_cpu(ctxt->neg.DataLength);
 	__le16 alg;
 
 	server->compression.enabled = false;
@@ -1029,9 +1076,11 @@ static void decode_compress_ctx(struct TCP_Server_Info *server,
 }
 
 static int decode_encrypt_ctx(struct TCP_Server_Info *server,
-			      struct smb2_encryption_neg_context *ctxt)
+			      struct smb2_neg_context *neg)
 {
-	unsigned int len = le16_to_cpu(ctxt->DataLength);
+	struct smb2_encryption_neg_context *ctxt =
+		container_of(neg, struct smb2_encryption_neg_context, neg);
+	unsigned int len = le16_to_cpu(ctxt->neg.DataLength);
 
 	cifs_dbg(FYI, "decode SMB3.11 encryption neg context of len %d\n", len);
 	/*
@@ -1081,9 +1130,11 @@ static int decode_encrypt_ctx(struct TCP_Server_Info *server,
 }
 
 static void decode_signing_ctx(struct TCP_Server_Info *server,
-			       struct smb2_signing_capabilities *pctxt)
+			       struct smb2_neg_context *neg)
 {
-	unsigned int len = le16_to_cpu(pctxt->DataLength);
+	struct smb2_signing_capabilities *pctxt =
+		container_of(neg, struct smb2_signing_capabilities, neg);
+	unsigned int len = le16_to_cpu(pctxt->neg.DataLength);
 
 	/*
 	 * Caller checked that DataLength remains within SMB boundary. We still
@@ -1110,11 +1161,12 @@ static void decode_signing_ctx(struct TCP_Server_Info *server,
 }
 
 
-static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
-				     struct TCP_Server_Info *server,
-				     unsigned int len_of_smb)
+static int smb311_decode_neg_context(struct smb_message *smb,
+				     struct TCP_Server_Info *server)
 {
+	struct smb2_negotiate_rsp *rsp = smb->response;
 	struct smb2_neg_context *pctx;
+	unsigned int len_of_smb = smb->response_len;
 	unsigned int offset = le32_to_cpu(rsp->NegotiateContextOffset);
 	unsigned int ctxt_cnt = le16_to_cpu(rsp->NegotiateContextCount);
 	unsigned int len_of_ctxts, i;
@@ -1147,23 +1199,26 @@ static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
 		if (clen > len_of_ctxts)
 			break;
 
-		if (pctx->ContextType == SMB2_PREAUTH_INTEGRITY_CAPABILITIES)
-			decode_preauth_context(
-				(struct smb2_preauth_neg_context *)pctx);
-		else if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES)
-			rc = decode_encrypt_ctx(server,
-				(struct smb2_encryption_neg_context *)pctx);
-		else if (pctx->ContextType == SMB2_COMPRESSION_CAPABILITIES)
-			decode_compress_ctx(server,
-				(struct smb2_compression_capabilities_context *)pctx);
-		else if (pctx->ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE)
+		switch (pctx->ContextType) {
+		case SMB2_PREAUTH_INTEGRITY_CAPABILITIES:
+			decode_preauth_context(pctx);
+			break;
+		case SMB2_ENCRYPTION_CAPABILITIES:
+			rc = decode_encrypt_ctx(server, pctx);
+			break;
+		case SMB2_COMPRESSION_CAPABILITIES:
+			decode_compress_ctx(server, pctx);
+			break;
+		case SMB2_POSIX_EXTENSIONS_AVAILABLE:
 			server->posix_ext_supported = true;
-		else if (pctx->ContextType == SMB2_SIGNING_CAPABILITIES)
-			decode_signing_ctx(server,
-				(struct smb2_signing_capabilities *)pctx);
-		else
+			break;
+		case SMB2_SIGNING_CAPABILITIES:
+			decode_signing_ctx(server, pctx);
+			break;
+		default:
 			cifs_server_dbg(VFS, "unknown negcontext of type %d ignored\n",
 				le16_to_cpu(pctx->ContextType));
+		}
 		if (rc)
 			break;
 
@@ -1248,17 +1303,16 @@ SMB2_negotiate(const unsigned int xid,
 	       struct cifs_ses *ses,
 	       struct TCP_Server_Info *server)
 {
-	struct smb_rqst rqst;
 	struct smb2_negotiate_req *req;
 	struct smb2_negotiate_rsp *rsp;
-	struct kvec iov[1];
-	struct kvec rsp_iov;
+	struct smb_message *smb;
+	const char *vs;
+	size_t offset, num_dialects;
 	int rc;
-	int resp_buftype;
 	int blob_offset, blob_length;
 	char *security_blob;
 	int flags = CIFS_NEG_OP;
-	unsigned int total_len;
+	enum { DEF, ANY3, SPEC } version;
 
 	cifs_dbg(FYI, "Negotiate protocol\n");
 
@@ -1267,36 +1321,67 @@ SMB2_negotiate(const unsigned int xid,
 		return -EIO;
 	}
 
-	rc = smb2_plain_req_init(SMB2_NEGOTIATE, NULL, server,
-				 (void **) &req, &total_len);
+	rc = smb2_reconnect(SMB2_SESSION_SETUP, NULL, server, false);
 	if (rc)
 		return rc;
 
+	/* Calculate how much space we need for a Negotiate Request message.
+	 * We can't do this exactly as the hostname might change, but we don't
+	 * want to hold the lock across the allocation.
+	 */
+	vs = server->vals->version_string;
+	if (strcmp(vs, SMB3ANY_VERSION_STRING) == 0) {
+		version = ANY3;
+		num_dialects = 3;
+	} else if (strcmp(vs, SMBDEFAULT_VERSION_STRING) == 0) {
+		version = DEF;
+		num_dialects = 4;
+	} else {
+		version = SPEC;
+		num_dialects = 1;
+	}
+
+	offset = sizeof(struct smb2_negotiate_req);
+	offset += sizeof(req->Dialects[0]) * num_dialects;
+
+	if ((server->vals->protocol_id == SMB311_PROT_ID) ||
+	    (version == ANY3) ||
+	    (version == DEF))
+		offset = smb2_size_neg_contexts(server, offset);
+
+	smb = smb2_create_request(SMB2_NEGOTIATE, server, NULL,
+				  sizeof(*req), offset, 0,
+				  SMB2_REQ_HEAD);
+	if (!smb)
+		return -ENOMEM;
+
+	/* Fill in the message. */
+	req = smb->request;
 	req->hdr.SessionId = 0;
+	req->NegotiateContextOffset = cpu_to_be32(smb->ext_offset);
 
 	memset(server->preauth_sha_hash, 0, SMB2_PREAUTH_HASH_SIZE);
 	memset(ses->preauth_sha_hash, 0, SMB2_PREAUTH_HASH_SIZE);
 
-	if (strcmp(server->vals->version_string,
-		   SMB3ANY_VERSION_STRING) == 0) {
+	switch (version) {
+	case ANY3:
 		req->Dialects[0] = cpu_to_le16(SMB30_PROT_ID);
 		req->Dialects[1] = cpu_to_le16(SMB302_PROT_ID);
 		req->Dialects[2] = cpu_to_le16(SMB311_PROT_ID);
 		req->DialectCount = cpu_to_le16(3);
-		total_len += 6;
-	} else if (strcmp(server->vals->version_string,
-		   SMBDEFAULT_VERSION_STRING) == 0) {
+		break;
+	case DEF:
 		req->Dialects[0] = cpu_to_le16(SMB21_PROT_ID);
 		req->Dialects[1] = cpu_to_le16(SMB30_PROT_ID);
 		req->Dialects[2] = cpu_to_le16(SMB302_PROT_ID);
 		req->Dialects[3] = cpu_to_le16(SMB311_PROT_ID);
 		req->DialectCount = cpu_to_le16(4);
-		total_len += 8;
-	} else {
+		break;
+	case SPEC:
 		/* otherwise send specific dialect */
 		req->Dialects[0] = cpu_to_le16(server->vals->protocol_id);
 		req->DialectCount = cpu_to_le16(1);
-		total_len += 2;
+		break;
 	}
 
 	/* only one of SMB2 signing flags may be set in SMB2 request */
@@ -1312,97 +1397,108 @@ SMB2_negotiate(const unsigned int xid,
 		req->Capabilities |= cpu_to_le32(SMB2_GLOBAL_CAP_MULTI_CHANNEL);
 
 	/* ClientGUID must be zero for SMB2.02 dialect */
-	if (server->vals->protocol_id == SMB20_PROT_ID)
+	if (server->vals->protocol_id == SMB20_PROT_ID) {
 		memset(req->ClientGUID, 0, SMB2_CLIENT_GUID_SIZE);
-	else {
+	} else {
 		memcpy(req->ClientGUID, server->client_guid,
 			SMB2_CLIENT_GUID_SIZE);
 		if ((server->vals->protocol_id == SMB311_PROT_ID) ||
-		    (strcmp(server->vals->version_string,
-		     SMB3ANY_VERSION_STRING) == 0) ||
-		    (strcmp(server->vals->version_string,
-		     SMBDEFAULT_VERSION_STRING) == 0))
-			assemble_neg_contexts(req, server, &total_len);
+		    (version == ANY3) ||
+		    (version == DEF))
+			assemble_neg_contexts(smb, server);
 	}
-	iov[0].iov_base = (char *)req;
-	iov[0].iov_len = total_len;
 
-	memset(&rqst, 0, sizeof(struct smb_rqst));
-	rqst.rq_iov = iov;
-	rqst.rq_nvec = 1;
+	rc = smb_send_recv_messages(xid, ses, server, smb, flags);
+	smb_clear_request(smb);
 
-	rc = cifs_send_recv(xid, ses, server,
-			    &rqst, &resp_buftype, flags, &rsp_iov);
-	cifs_small_buf_release(req);
-	rsp = (struct smb2_negotiate_rsp *)rsp_iov.iov_base;
 	/*
 	 * No tcon so can't do
 	 * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]);
 	 */
-	if (rc == -EOPNOTSUPP) {
-		cifs_server_dbg(VFS, "Dialect not supported by server. Consider  specifying vers=1.0 or vers=2.0 on mount for accessing older servers\n");
-		goto neg_exit;
-	} else if (rc != 0)
+	if (rc != 0) {
+		if (rc == -EOPNOTSUPP)
+			cifs_server_dbg(VFS, "Dialect not supported by server. Consider  specifying vers=1.0 or vers=2.0 on mount for accessing older servers\n");
 		goto neg_exit;
+	}
 
+	/* ________________________________________
+	 * Decode the response.
+	 */
+	rsp = (struct smb2_negotiate_rsp *)smb->response;
+
+	int dialect_revision = le16_to_cpu(rsp->DialectRevision);
 	rc = -EIO;
-	if (strcmp(server->vals->version_string,
-		   SMB3ANY_VERSION_STRING) == 0) {
-		if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) {
+	switch (version) {
+	case ANY3:
+		switch (dialect_revision) {
+		case SMB20_PROT_ID:
 			cifs_server_dbg(VFS,
 				"SMB2 dialect returned but not requested\n");
 			goto neg_exit;
-		} else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) {
+		case SMB21_PROT_ID:
 			cifs_server_dbg(VFS,
 				"SMB2.1 dialect returned but not requested\n");
 			goto neg_exit;
-		} else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) {
+		case SMB311_PROT_ID:
 			/* ops set to 3.0 by default for default so update */
 			server->ops = &smb311_operations;
 			server->vals = &smb311_values;
+			break;
 		}
-	} else if (strcmp(server->vals->version_string,
-		   SMBDEFAULT_VERSION_STRING) == 0) {
-		if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID)) {
+		break;
+	case DEF:
+		switch (dialect_revision) {
+		case SMB20_PROT_ID:
 			cifs_server_dbg(VFS,
 				"SMB2 dialect returned but not requested\n");
 			goto neg_exit;
-		} else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) {
+		case SMB21_PROT_ID:
 			/* ops set to 3.0 by default for default so update */
 			server->ops = &smb21_operations;
 			server->vals = &smb21_values;
-		} else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) {
+			break;
+		case SMB311_PROT_ID:
 			server->ops = &smb311_operations;
 			server->vals = &smb311_values;
+			break;
 		}
-	} else if (le16_to_cpu(rsp->DialectRevision) !=
-				server->vals->protocol_id) {
-		/* if requested single dialect ensure returned dialect matched */
-		cifs_server_dbg(VFS, "Invalid 0x%x dialect returned: not requested\n",
-				le16_to_cpu(rsp->DialectRevision));
-		goto neg_exit;
+		break;
+	default:
+		if (dialect_revision != server->vals->protocol_id) {
+			/* if requested single dialect ensure returned dialect matched */
+			cifs_server_dbg(VFS, "Invalid 0x%x dialect returned: not requested\n",
+					dialect_revision);
+			goto neg_exit;
+		}
+		break;
 	}
 
 	cifs_dbg(FYI, "mode 0x%x\n", rsp->SecurityMode);
 
-	if (rsp->DialectRevision == cpu_to_le16(SMB20_PROT_ID))
+	switch (dialect_revision) {
+	case SMB20_PROT_ID:
 		cifs_dbg(FYI, "negotiated smb2.0 dialect\n");
-	else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID))
+		break;
+	case SMB21_PROT_ID:
 		cifs_dbg(FYI, "negotiated smb2.1 dialect\n");
-	else if (rsp->DialectRevision == cpu_to_le16(SMB30_PROT_ID))
+		break;
+	case SMB30_PROT_ID:
 		cifs_dbg(FYI, "negotiated smb3.0 dialect\n");
-	else if (rsp->DialectRevision == cpu_to_le16(SMB302_PROT_ID))
+		break;
+	case SMB302_PROT_ID:
 		cifs_dbg(FYI, "negotiated smb3.02 dialect\n");
-	else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID))
+		break;
+	case SMB311_PROT_ID:
 		cifs_dbg(FYI, "negotiated smb3.1.1 dialect\n");
-	else {
+		break;
+	default:
 		cifs_server_dbg(VFS, "Invalid dialect returned by server 0x%x\n",
-				le16_to_cpu(rsp->DialectRevision));
+				dialect_revision);
 		goto neg_exit;
 	}
 
 	rc = 0;
-	server->dialect = le16_to_cpu(rsp->DialectRevision);
+	server->dialect = dialect_revision;
 
 	/*
 	 * Keep a copy of the hash after negprot. This hash will be
@@ -1461,10 +1557,9 @@ SMB2_negotiate(const unsigned int xid,
 			rc = -EIO;
 	}
 
-	if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) {
+	if (server->dialect == SMB311_PROT_ID) {
 		if (rsp->NegotiateContextCount)
-			rc = smb311_decode_neg_context(rsp, server,
-						       rsp_iov.iov_len);
+			rc = smb311_decode_neg_context(smb, server);
 		else
 			cifs_server_dbg(VFS, "Missing expected negotiate contexts\n");
 	}
@@ -1472,7 +1567,7 @@ SMB2_negotiate(const unsigned int xid,
 	if (server->cipher_type && !rc)
 		rc = smb3_crypto_aead_allocate(server);
 neg_exit:
-	free_rsp_buf(resp_buftype, rsp);
+	smb_put_messages(smb);
 	return rc;
 }
 
diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h
index 7da40d229ab5..e3b888140b59 100644
--- a/fs/smb/common/smb2pdu.h
+++ b/fs/smb/common/smb2pdu.h
@@ -455,9 +455,7 @@ struct smb2_neg_context {
 #define MIN_PREAUTH_CTXT_DATA_LEN 6
 
 struct smb2_preauth_neg_context {
-	__le16	ContextType; /* 1 */
-	__le16	DataLength;
-	__le32	Reserved;
+	struct smb2_neg_context neg;
 	__le16	HashAlgorithmCount; /* 1 */
 	__le16	SaltLength;
 	__le16	HashAlgorithms; /* HashAlgorithms[0] since only one defined */
@@ -473,9 +471,7 @@ struct smb2_preauth_neg_context {
 /* Min encrypt context data is one cipher so 2 bytes + 2 byte count field */
 #define MIN_ENCRYPT_CTXT_DATA_LEN	4
 struct smb2_encryption_neg_context {
-	__le16	ContextType; /* 2 */
-	__le16	DataLength;
-	__le32	Reserved;
+	struct smb2_neg_context neg;
 	/* CipherCount usually 2, but can be 3 when AES256-GCM enabled */
 	__le16	CipherCount; /* AES128-GCM and AES128-CCM by default */
 	__le16	Ciphers[];
@@ -495,9 +491,7 @@ struct smb2_encryption_neg_context {
 #define SMB2_COMPRESSION_CAPABILITIES_FLAG_CHAINED	cpu_to_le32(0x00000001)
 
 struct smb2_compression_capabilities_context {
-	__le16	ContextType; /* 3 */
-	__le16  DataLength;
-	__le32	Reserved;
+	struct smb2_neg_context neg;
 	__le16	CompressionAlgorithmCount;
 	__le16	Padding;
 	__le32	Flags;
@@ -511,9 +505,7 @@ struct smb2_compression_capabilities_context {
  * Its struct simply contains NetName, an array of Unicode characters
  */
 struct smb2_netname_neg_context {
-	__le16	ContextType; /* 5 */
-	__le16	DataLength;
-	__le32	Reserved;
+	struct smb2_neg_context neg;
 	__le16	NetName[]; /* hostname of target converted to UCS-2 */
 } __packed;
 
@@ -567,9 +559,7 @@ struct smb2_rdma_transform_capabilities_context {
 #define SIGNING_ALG_AES_GMAC_LE    cpu_to_le16(2)
 
 struct smb2_signing_capabilities {
-	__le16	ContextType; /* 8 */
-	__le16	DataLength;
-	__le32	Reserved;
+	struct smb2_neg_context neg;
 	__le16	SigningAlgorithmCount;
 	__le16	SigningAlgorithms[];
 	/*  Followed by padding to 8 byte boundary (required by some servers) */
@@ -577,9 +567,7 @@ struct smb2_signing_capabilities {
 
 #define POSIX_CTXT_DATA_LEN	16
 struct smb2_posix_neg_context {
-	__le16	ContextType; /* 0x100 */
-	__le16	DataLength;
-	__le32	Reserved;
+	struct smb2_neg_context neg;
 	__u8	Name[16]; /* POSIX ctxt GUID 93AD25509CB411E7B42383DE968BCD7C */
 } __packed;
 
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 1ed2bcba649f..af5187d1101e 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -774,10 +774,10 @@ static int smb2_get_dos_mode(struct kstat *stat, int attribute)
 static void build_preauth_ctxt(struct smb2_preauth_neg_context *pneg_ctxt,
 			       __le16 hash_id)
 {
-	pneg_ctxt->ContextType = SMB2_PREAUTH_INTEGRITY_CAPABILITIES;
-	pneg_ctxt->DataLength = cpu_to_le16(38);
+	pneg_ctxt->neg.ContextType = SMB2_PREAUTH_INTEGRITY_CAPABILITIES;
+	pneg_ctxt->neg.DataLength = cpu_to_le16(38);
+	pneg_ctxt->neg.Reserved = cpu_to_le32(0);
 	pneg_ctxt->HashAlgorithmCount = cpu_to_le16(1);
-	pneg_ctxt->Reserved = cpu_to_le32(0);
 	pneg_ctxt->SaltLength = cpu_to_le16(SMB311_SALT_SIZE);
 	get_random_bytes(pneg_ctxt->Salt, SMB311_SALT_SIZE);
 	pneg_ctxt->HashAlgorithms = hash_id;
@@ -786,9 +786,9 @@ static void build_preauth_ctxt(struct smb2_preauth_neg_context *pneg_ctxt,
 static void build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt,
 			       __le16 cipher_type)
 {
-	pneg_ctxt->ContextType = SMB2_ENCRYPTION_CAPABILITIES;
-	pneg_ctxt->DataLength = cpu_to_le16(4);
-	pneg_ctxt->Reserved = cpu_to_le32(0);
+	pneg_ctxt->neg.ContextType = SMB2_ENCRYPTION_CAPABILITIES;
+	pneg_ctxt->neg.DataLength = cpu_to_le16(4);
+	pneg_ctxt->neg.Reserved = cpu_to_le32(0);
 	pneg_ctxt->CipherCount = cpu_to_le16(1);
 	pneg_ctxt->Ciphers[0] = cipher_type;
 }
@@ -796,19 +796,19 @@ static void build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt,
 static void build_sign_cap_ctxt(struct smb2_signing_capabilities *pneg_ctxt,
 				__le16 sign_algo)
 {
-	pneg_ctxt->ContextType = SMB2_SIGNING_CAPABILITIES;
-	pneg_ctxt->DataLength =
+	pneg_ctxt->neg.ContextType = SMB2_SIGNING_CAPABILITIES;
+	pneg_ctxt->neg.DataLength =
 		cpu_to_le16((sizeof(struct smb2_signing_capabilities) + 2)
 			- sizeof(struct smb2_neg_context));
-	pneg_ctxt->Reserved = cpu_to_le32(0);
+	pneg_ctxt->neg.Reserved = cpu_to_le32(0);
 	pneg_ctxt->SigningAlgorithmCount = cpu_to_le16(1);
 	pneg_ctxt->SigningAlgorithms[0] = sign_algo;
 }
 
 static void build_posix_ctxt(struct smb2_posix_neg_context *pneg_ctxt)
 {
-	pneg_ctxt->ContextType = SMB2_POSIX_EXTENSIONS_AVAILABLE;
-	pneg_ctxt->DataLength = cpu_to_le16(POSIX_CTXT_DATA_LEN);
+	pneg_ctxt->neg.ContextType = SMB2_POSIX_EXTENSIONS_AVAILABLE;
+	pneg_ctxt->neg.DataLength = cpu_to_le16(POSIX_CTXT_DATA_LEN);
 	/* SMB2_CREATE_TAG_POSIX is "0x93AD25509CB411E7B42383DE968BCD7C" */
 	pneg_ctxt->Name[0] = 0x93;
 	pneg_ctxt->Name[1] = 0xAD;


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 25/31] cifs: Convert SMB2 Session Setup request
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (23 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 24/31] cifs: Convert SMB2 Negotiate Protocol request David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 26/31] cifs: Convert SMB2 Logoff request David Howells
                   ` (9 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/ntlmssp.h |  20 +--
 fs/smb/client/sess.c    | 271 ++++++++++++++++++++++------------------
 fs/smb/client/smb2pdu.c | 172 ++++++++++---------------
 3 files changed, 226 insertions(+), 237 deletions(-)

diff --git a/fs/smb/client/ntlmssp.h b/fs/smb/client/ntlmssp.h
index 875de43b72de..5ca249f1c51c 100644
--- a/fs/smb/client/ntlmssp.h
+++ b/fs/smb/client/ntlmssp.h
@@ -123,7 +123,7 @@ typedef struct _CHALLENGE_MESSAGE {
 	   do not set the version is present flag */
 } __attribute__((packed)) CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE;
 
-typedef struct _AUTHENTICATE_MESSAGE {
+struct ntlmssp_authenticate_message {
 	__u8 Signature[sizeof(NTLMSSP_SIGNATURE)];
 	__le32 MessageType;  /* NtLmsAuthenticate = 3 */
 	SECURITY_BUFFER LmChallengeResponse;
@@ -136,7 +136,7 @@ typedef struct _AUTHENTICATE_MESSAGE {
 	struct	ntlmssp_version Version;
 	/* SECURITY_BUFFER */
 	char UserString[];
-} __attribute__((packed)) AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE;
+} __attribute__((packed));
 
 /*
  * Size of the session key (crypto key encrypted with the password
@@ -147,11 +147,11 @@ int build_ntlmssp_negotiate_blob(unsigned char **pbuffer, u16 *buflen,
 				 struct cifs_ses *ses,
 				 struct TCP_Server_Info *server,
 				 const struct nls_table *nls_cp);
-int build_ntlmssp_smb3_negotiate_blob(unsigned char **pbuffer, u16 *buflen,
-				 struct cifs_ses *ses,
-				 struct TCP_Server_Info *server,
-				 const struct nls_table *nls_cp);
-int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen,
-			struct cifs_ses *ses,
-			struct TCP_Server_Info *server,
-			const struct nls_table *nls_cp);
+int build_ntlmssp_smb3_negotiate_blob(struct smb_message *smb,
+				      struct cifs_ses *ses,
+				      struct TCP_Server_Info *server,
+				      const struct nls_table *nls_cp);
+int build_ntlmssp_auth_blob(struct smb_message *smb,
+			    struct cifs_ses *ses,
+			    struct TCP_Server_Info *server,
+			    const struct nls_table *nls_cp);
diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c
index 330bc3d25bad..8063cf06ea9f 100644
--- a/fs/smb/client/sess.c
+++ b/fs/smb/client/sess.c
@@ -966,32 +966,86 @@ int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
 	return 0;
 }
 
-static int size_of_ntlmssp_blob(struct cifs_ses *ses, int base_size)
+static int size_of_ntlmssp_blob(struct cifs_ses *ses, int base_size,
+				const struct nls_table *nls_cp)
 {
 	int sz = base_size + ses->auth_key.len
 		- CIFS_SESS_KEY_SIZE + CIFS_CPHTXT_SIZE + 2;
 
 	if (ses->domainName)
-		sz += sizeof(__le16) * strnlen(ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
+		sz += cifs_size_strtoUTF16(ses->domainName, CIFS_MAX_DOMAINNAME_LEN,
+					   nls_cp);
 	else
 		sz += sizeof(__le16);
 
 	if (ses->user_name)
-		sz += sizeof(__le16) * strnlen(ses->user_name, CIFS_MAX_USERNAME_LEN);
+		sz += cifs_size_strtoUTF16(ses->user_name, CIFS_MAX_USERNAME_LEN,
+					   nls_cp);
 	else
 		sz += sizeof(__le16);
 
 	if (ses->workstation_name[0])
-		sz += sizeof(__le16) * strnlen(ses->workstation_name,
-					       ntlmssp_workstation_name_size(ses));
+		sz += cifs_size_strtoUTF16(ses->workstation_name,
+					   ntlmssp_workstation_name_size(ses),
+					   nls_cp);
 	else
 		sz += sizeof(__le16);
 
 	return sz;
 }
 
+static void cifs_append_security_string(struct smb_message *smb,
+					SECURITY_BUFFER *pbuf,
+					const char *str_value,
+					int str_length,
+					unsigned char **pcur,
+					const struct nls_table *nls_cp)
+{
+	int len;
+
+	if (!str_value) {
+		pbuf->BufferOffset = cpu_to_le32(smb->offset);
+		pbuf->Length = 0;
+		pbuf->MaximumLength = 0;
+		*(__le16 *)*pcur = 0;
+		smb->offset += 2;
+		pcur += 2;
+	} else {
+		len = cifs_strtoUTF16((__le16 *)*pcur,
+				      str_value,
+				      str_length,
+				      nls_cp);
+		len *= sizeof(__le16);
+		pbuf->BufferOffset = cpu_to_le32(smb->offset);
+		pbuf->Length = cpu_to_le16(len);
+		pbuf->MaximumLength = cpu_to_le16(len);
+		smb->offset += len;
+		pcur += len;
+	}
+}
+
+static void cifs_append_security_blob(struct smb_message *smb,
+				      SECURITY_BUFFER *pbuf,
+				      const void *content,
+				      int len,
+				      unsigned char **pcur)
+{
+	if (!content) {
+		pbuf->BufferOffset	= cpu_to_le32(smb->offset);
+		pbuf->Length		= 0;
+		pbuf->MaximumLength	= 0;
+	} else {
+		memcpy(pcur, content, len);
+		pbuf->BufferOffset	= cpu_to_le32(smb->offset);
+		pbuf->Length		= cpu_to_le16(len);
+		pbuf->MaximumLength	= cpu_to_le16(len);
+		smb->offset += len;
+		pcur += len;
+	}
+}
+
 static inline void cifs_security_buffer_from_str(SECURITY_BUFFER *pbuf,
-						 char *str_value,
+						 const char *str_value,
 						 int str_length,
 						 unsigned char *pstart,
 						 unsigned char **pcur,
@@ -1038,7 +1092,7 @@ int build_ntlmssp_negotiate_blob(unsigned char **pbuffer,
 	unsigned char *tmp;
 	int len;
 
-	len = size_of_ntlmssp_blob(ses, sizeof(NEGOTIATE_MESSAGE));
+	len = size_of_ntlmssp_blob(ses, sizeof(NEGOTIATE_MESSAGE), nls_cp);
 	*pbuffer = kmalloc(len, GFP_KERNEL);
 	if (!*pbuffer) {
 		rc = -ENOMEM;
@@ -1088,173 +1142,148 @@ int build_ntlmssp_negotiate_blob(unsigned char **pbuffer,
  * supported by modern servers. For safety limit to SMB3 or later
  * See notes in MS-NLMP Section 2.2.2.1 e.g.
  */
-int build_ntlmssp_smb3_negotiate_blob(unsigned char **pbuffer,
-				 u16 *buflen,
-				 struct cifs_ses *ses,
-				 struct TCP_Server_Info *server,
-				 const struct nls_table *nls_cp)
+int build_ntlmssp_smb3_negotiate_blob(struct smb_message *smb,
+				      struct cifs_ses *ses,
+				      struct TCP_Server_Info *server,
+				      const struct nls_table *nls_cp)
 {
-	int rc = 0;
-	struct negotiate_message *sec_blob;
-	__u32 flags;
+	struct negotiate_message *neg_msg;
 	unsigned char *tmp;
+	__u32 flags;
+	void *blob;
 	int len;
+	int rc = 0;
 
-	len = size_of_ntlmssp_blob(ses, sizeof(struct negotiate_message));
-	*pbuffer = kmalloc(len, GFP_KERNEL);
-	if (!*pbuffer) {
+	len = size_of_ntlmssp_blob(ses, sizeof(*neg_msg), nls_cp);
+	blob = cifs_allocate_tx_buf(server, len);
+	if (!blob) {
 		rc = -ENOMEM;
 		cifs_dbg(VFS, "Error %d during NTLMSSP allocation\n", rc);
-		*buflen = 0;
 		goto setup_ntlm_smb3_neg_ret;
 	}
-	sec_blob = (struct negotiate_message *)*pbuffer;
 
-	memset(*pbuffer, 0, sizeof(struct negotiate_message));
-	memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
-	sec_blob->MessageType = NtLmNegotiate;
+	smb_add_segment_to_tx_buf(smb, blob, len);
+	smb->offset = sizeof(*neg_msg);
 
 	/* BB is NTLMV2 session security format easier to use here? */
-	flags = NTLMSSP_NEGOTIATE_56 |	NTLMSSP_REQUEST_TARGET |
-		NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
-		NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC |
-		NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_SEAL |
-		NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_VERSION;
+	flags = NTLMSSP_NEGOTIATE_56		| NTLMSSP_REQUEST_TARGET |
+		NTLMSSP_NEGOTIATE_128		| NTLMSSP_NEGOTIATE_UNICODE |
+		NTLMSSP_NEGOTIATE_NTLM		| NTLMSSP_NEGOTIATE_EXTENDED_SEC |
+		NTLMSSP_NEGOTIATE_ALWAYS_SIGN	| NTLMSSP_NEGOTIATE_SEAL |
+		NTLMSSP_NEGOTIATE_SIGN		| NTLMSSP_NEGOTIATE_VERSION;
 	if (!server->session_estab || ses->ntlmssp->sesskey_per_smbsess)
 		flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
 
-	sec_blob->Version.ProductMajorVersion = LINUX_VERSION_MAJOR;
-	sec_blob->Version.ProductMinorVersion = LINUX_VERSION_PATCHLEVEL;
-	sec_blob->Version.ProductBuild = cpu_to_le16(SMB3_PRODUCT_BUILD);
-	sec_blob->Version.NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3;
+	neg_msg = (struct negotiate_message *)blob;
+	*neg_msg = (struct negotiate_message){
+		.Signature			= NTLMSSP_SIGNATURE,
+		.MessageType			= NtLmNegotiate,
+		.NegotiateFlags			= cpu_to_le32(flags),
+		.Version.ProductMajorVersion	= LINUX_VERSION_MAJOR,
+		.Version.ProductMinorVersion	= LINUX_VERSION_PATCHLEVEL,
+		.Version.ProductBuild		= cpu_to_le16(SMB3_PRODUCT_BUILD),
+		.Version.NTLMRevisionCurrent	= NTLMSSP_REVISION_W2K3,
+	};
 
-	tmp = *pbuffer + sizeof(struct negotiate_message);
 	ses->ntlmssp->client_flags = flags;
-	sec_blob->NegotiateFlags = cpu_to_le32(flags);
+	tmp = blob + sizeof(struct negotiate_message);
 
 	/* these fields should be null in negotiate phase MS-NLMP 3.1.5.1.1 */
-	cifs_security_buffer_from_str(&sec_blob->DomainName,
-				      NULL,
-				      CIFS_MAX_DOMAINNAME_LEN,
-				      *pbuffer, &tmp,
-				      nls_cp);
+	cifs_append_security_string(smb, &neg_msg->DomainName,
+				    NULL, CIFS_MAX_DOMAINNAME_LEN,
+				    &tmp, nls_cp);
 
-	cifs_security_buffer_from_str(&sec_blob->WorkstationName,
-				      NULL,
-				      CIFS_MAX_WORKSTATION_LEN,
-				      *pbuffer, &tmp,
-				      nls_cp);
-
-	*buflen = tmp - *pbuffer;
+	cifs_append_security_string(smb, &neg_msg->WorkstationName,
+				    NULL, CIFS_MAX_WORKSTATION_LEN,
+				    &tmp, nls_cp);
 setup_ntlm_smb3_neg_ret:
 	return rc;
 }
 
 
 /* See MS-NLMP 2.2.1.3 */
-int build_ntlmssp_auth_blob(unsigned char **pbuffer,
-					u16 *buflen,
-				   struct cifs_ses *ses,
-				   struct TCP_Server_Info *server,
-				   const struct nls_table *nls_cp)
+int build_ntlmssp_auth_blob(struct smb_message *smb,
+			    struct cifs_ses *ses,
+			    struct TCP_Server_Info *server,
+			    const struct nls_table *nls_cp)
 {
-	int rc;
-	AUTHENTICATE_MESSAGE *sec_blob;
-	__u32 flags;
+	struct ntlmssp_authenticate_message *auth_msg;
 	unsigned char *tmp;
+	__u32 flags;
+	void *blob;
 	int len;
+	int rc;
 
 	rc = setup_ntlmv2_rsp(ses, nls_cp);
 	if (rc) {
 		cifs_dbg(VFS, "Error %d during NTLMSSP authentication\n", rc);
-		*buflen = 0;
 		goto setup_ntlmv2_ret;
 	}
 
-	len = size_of_ntlmssp_blob(ses, sizeof(AUTHENTICATE_MESSAGE));
-	*pbuffer = kmalloc(len, GFP_KERNEL);
-	if (!*pbuffer) {
+	len = size_of_ntlmssp_blob(ses, sizeof(*auth_msg), nls_cp);
+	blob = cifs_allocate_tx_buf(server, len);
+	if (!blob) {
 		rc = -ENOMEM;
 		cifs_dbg(VFS, "Error %d during NTLMSSP allocation\n", rc);
-		*buflen = 0;
 		goto setup_ntlmv2_ret;
 	}
-	sec_blob = (AUTHENTICATE_MESSAGE *)*pbuffer;
 
-	memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
-	sec_blob->MessageType = NtLmAuthenticate;
+	smb_add_segment_to_tx_buf(smb, blob, len);
+	smb->offset = sizeof(*auth_msg);
 
 	/* send version information in ntlmssp authenticate also */
-	flags = ses->ntlmssp->server_flags | NTLMSSP_REQUEST_TARGET |
-		NTLMSSP_NEGOTIATE_TARGET_INFO | NTLMSSP_NEGOTIATE_VERSION |
+	flags = ses->ntlmssp->server_flags	| NTLMSSP_REQUEST_TARGET |
+		NTLMSSP_NEGOTIATE_TARGET_INFO	| NTLMSSP_NEGOTIATE_VERSION |
 		NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED;
 
-	sec_blob->Version.ProductMajorVersion = LINUX_VERSION_MAJOR;
-	sec_blob->Version.ProductMinorVersion = LINUX_VERSION_PATCHLEVEL;
-	sec_blob->Version.ProductBuild = cpu_to_le16(SMB3_PRODUCT_BUILD);
-	sec_blob->Version.NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3;
+	auth_msg = blob;
+	*auth_msg = (struct ntlmssp_authenticate_message){
+		.Signature			= NTLMSSP_SIGNATURE,
+		.MessageType			= NtLmAuthenticate,
+		.NegotiateFlags			= cpu_to_le32(flags),
+		.Version.ProductMajorVersion	= LINUX_VERSION_MAJOR,
+		.Version.ProductMinorVersion	= LINUX_VERSION_PATCHLEVEL,
+		.Version.ProductBuild		= cpu_to_le16(SMB3_PRODUCT_BUILD),
+		.Version.NTLMRevisionCurrent	= NTLMSSP_REVISION_W2K3,
+	};
 
-	tmp = *pbuffer + sizeof(AUTHENTICATE_MESSAGE);
-	sec_blob->NegotiateFlags = cpu_to_le32(flags);
+	tmp = blob + sizeof(*auth_msg);
 
-	sec_blob->LmChallengeResponse.BufferOffset =
-				cpu_to_le32(sizeof(AUTHENTICATE_MESSAGE));
-	sec_blob->LmChallengeResponse.Length = 0;
-	sec_blob->LmChallengeResponse.MaximumLength = 0;
+	cifs_append_security_blob(smb, &auth_msg->LmChallengeResponse,
+				  NULL, 0, &tmp);
 
-	sec_blob->NtChallengeResponse.BufferOffset =
-				cpu_to_le32(tmp - *pbuffer);
-	if (ses->user_name != NULL) {
-		memcpy(tmp, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
-				ses->auth_key.len - CIFS_SESS_KEY_SIZE);
-		tmp += ses->auth_key.len - CIFS_SESS_KEY_SIZE;
+	/* Only send an NT Response for anonymous access */
+	if (ses->user_name)
+		cifs_append_security_blob(smb, &auth_msg->NtChallengeResponse,
+					  ses->auth_key.response + CIFS_SESS_KEY_SIZE,
+					  ses->auth_key.len - CIFS_SESS_KEY_SIZE,
+					  &tmp);
+	else
+		cifs_append_security_blob(smb, &auth_msg->NtChallengeResponse,
+					  NULL, 0, &tmp);
 
-		sec_blob->NtChallengeResponse.Length =
-				cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE);
-		sec_blob->NtChallengeResponse.MaximumLength =
-				cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE);
-	} else {
-		/*
-		 * don't send an NT Response for anonymous access
-		 */
-		sec_blob->NtChallengeResponse.Length = 0;
-		sec_blob->NtChallengeResponse.MaximumLength = 0;
-	}
+	cifs_append_security_string(smb, &auth_msg->DomainName,
+				    ses->domainName, CIFS_MAX_DOMAINNAME_LEN,
+				    &tmp, nls_cp);
 
-	cifs_security_buffer_from_str(&sec_blob->DomainName,
-				      ses->domainName,
-				      CIFS_MAX_DOMAINNAME_LEN,
-				      *pbuffer, &tmp,
-				      nls_cp);
+	cifs_append_security_string(smb, &auth_msg->UserName,
+				    ses->user_name, CIFS_MAX_USERNAME_LEN,
+				    &tmp, nls_cp);
 
-	cifs_security_buffer_from_str(&sec_blob->UserName,
-				      ses->user_name,
-				      CIFS_MAX_USERNAME_LEN,
-				      *pbuffer, &tmp,
-				      nls_cp);
-
-	cifs_security_buffer_from_str(&sec_blob->WorkstationName,
-				      ses->workstation_name,
-				      ntlmssp_workstation_name_size(ses),
-				      *pbuffer, &tmp,
-				      nls_cp);
+	cifs_append_security_string(smb, &auth_msg->WorkstationName,
+				    ses->workstation_name,
+				    ntlmssp_workstation_name_size(ses),
+				    &tmp, nls_cp);
 
 	if ((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) &&
 	    (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess) &&
-	    !calc_seckey(ses)) {
-		memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE);
-		sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - *pbuffer);
-		sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE);
-		sec_blob->SessionKey.MaximumLength =
-				cpu_to_le16(CIFS_CPHTXT_SIZE);
-		tmp += CIFS_CPHTXT_SIZE;
-	} else {
-		sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - *pbuffer);
-		sec_blob->SessionKey.Length = 0;
-		sec_blob->SessionKey.MaximumLength = 0;
-	}
-
-	*buflen = tmp - *pbuffer;
+	    !calc_seckey(ses))
+		cifs_append_security_blob(smb, &auth_msg->SessionKey,
+					  ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE,
+					  &tmp);
+	else
+		cifs_append_security_blob(smb, &auth_msg->SessionKey,
+					  NULL, 0, &tmp);
 setup_ntlmv2_ret:
 	return rc;
 }
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index f1b6d36fe7cd..685af9c0cdcb 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -1740,33 +1740,29 @@ struct SMB2_sess_data {
 	void (*func)(struct SMB2_sess_data *);
 	int result;
 	u64 previous_session;
-
-	/* we will send the SMB in three pieces:
-	 * a fixed length beginning part, an optional
-	 * SPNEGO blob (which can be zero length), and a
-	 * last part which will include the strings
-	 * and rest of bcc area. This allows us to avoid
-	 * a large buffer 17K allocation
-	 */
-	int buf0_type;
-	struct kvec iov[2];
 };
 
-static int
-SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
+static struct smb_message *
+SMB2_create_session_request(struct SMB2_sess_data *sess_data)
 {
-	int rc;
+	struct smb_message *smb;
 	struct cifs_ses *ses = sess_data->ses;
 	struct TCP_Server_Info *server = sess_data->server;
 	struct smb2_sess_setup_req *req;
-	unsigned int total_len;
 	bool is_binding = false;
 
-	rc = smb2_plain_req_init(SMB2_SESSION_SETUP, NULL, server,
-				 (void **) &req,
-				 &total_len);
-	if (rc)
-		return rc;
+	/* We will send the SMB in three pieces:
+	 * - a fixed length beginning part,
+	 * - an optional SPNEGO blob (which can be zero length), and
+	 * - a last part which will include the strings and rest of bcc area.
+	 * This allows us to avoid a large buffer 17K allocation
+	 */
+	smb = smb2_create_request(SMB2_SESSION_SETUP, server, NULL,
+				  sizeof(*req), sizeof(*req), 0,
+				  SMB2_REQ_DYNAMIC |
+				  SMB2_REQ_SENSITIVE);
+	if (!smb)
+		return NULL;
 
 	spin_lock(&ses->ses_lock);
 	is_binding = (ses->ses_status == SES_GOOD);
@@ -1815,55 +1811,25 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
 
 	req->Channel = 0; /* MBZ */
 
-	sess_data->iov[0].iov_base = (char *)req;
-	/* 1 for pad */
-	sess_data->iov[0].iov_len = total_len - 1;
-	/*
-	 * This variable will be used to clear the buffer
-	 * allocated above in case of any error in the calling function.
-	 */
-	sess_data->buf0_type = CIFS_SMALL_BUFFER;
-
-	return 0;
-}
-
-static void
-SMB2_sess_free_buffer(struct SMB2_sess_data *sess_data)
-{
-	struct kvec *iov = sess_data->iov;
-
-	/* iov[1] is already freed by caller */
-	if (sess_data->buf0_type != CIFS_NO_BUFFER && iov[0].iov_base)
-		memzero_explicit(iov[0].iov_base, iov[0].iov_len);
-
-	free_rsp_buf(sess_data->buf0_type, iov[0].iov_base);
-	sess_data->buf0_type = CIFS_NO_BUFFER;
+	/* Testing shows that buffer offset must be at location of Buffer[0] */
+	req->SecurityBufferOffset = cpu_to_le16(sizeof(*req));
+	req->SecurityBufferLength = 0;
+	return smb;
 }
 
 static int
-SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)
+SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data,
+		      struct smb_message *smb)
 {
 	int rc;
-	struct smb_rqst rqst;
-	struct smb2_sess_setup_req *req = sess_data->iov[0].iov_base;
-	struct kvec rsp_iov = { NULL, 0 };
+	struct smb2_sess_setup_req *req = smb->request;
 
-	/* Testing shows that buffer offset must be at location of Buffer[0] */
-	req->SecurityBufferOffset =
-		cpu_to_le16(sizeof(struct smb2_sess_setup_req));
-	req->SecurityBufferLength = cpu_to_le16(sess_data->iov[1].iov_len);
-
-	memset(&rqst, 0, sizeof(struct smb_rqst));
-	rqst.rq_iov = sess_data->iov;
-	rqst.rq_nvec = 2;
+	req->SecurityBufferLength = cpu_to_le16(smb->total_len - sizeof(*req));
 
 	/* BB add code to build os and lm fields */
-	rc = cifs_send_recv(sess_data->xid, sess_data->ses,
-			    sess_data->server,
-			    &rqst,
-			    &sess_data->buf0_type,
-			    CIFS_LOG_ERROR | CIFS_SESS_OP, &rsp_iov);
-	cifs_small_buf_release(sess_data->iov[0].iov_base);
+	rc = smb_send_recv_messages(sess_data->xid, sess_data->ses, sess_data->server,
+				    smb, CIFS_LOG_ERROR | CIFS_SESS_OP);
+	smb_clear_request(smb);
 	if (rc == 0)
 		sess_data->ses->expired_pwd = false;
 	else if ((rc == -EACCES) || (rc == -EKEYEXPIRED) || (rc == -EKEYREVOKED)) {
@@ -1875,8 +1841,6 @@ SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)
 		sess_data->ses->expired_pwd = true;
 	}
 
-	memcpy(&sess_data->iov[0], &rsp_iov, sizeof(struct kvec));
-
 	return rc;
 }
 
@@ -1911,16 +1875,18 @@ SMB2_sess_establish_session(struct SMB2_sess_data *sess_data)
 static void
 SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
 {
-	int rc;
-	struct cifs_ses *ses = sess_data->ses;
+	struct smb2_sess_setup_rsp *rsp = NULL;
 	struct TCP_Server_Info *server = sess_data->server;
 	struct cifs_spnego_msg *msg;
+	struct smb_message *smb = NULL;
+	struct cifs_ses *ses = sess_data->ses;
 	struct key *spnego_key = NULL;
-	struct smb2_sess_setup_rsp *rsp = NULL;
+	void *key_buf = NULL;
 	bool is_binding = false;
+	int rc = -ENOMEM;
 
-	rc = SMB2_sess_alloc_buffer(sess_data);
-	if (rc)
+	smb = SMB2_create_session_request(sess_data);
+	if (!smb)
 		goto out;
 
 	spnego_key = cifs_get_spnego_key(ses, server);
@@ -1962,14 +1928,21 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
 		ses->auth_key.len = msg->sesskey_len;
 	}
 
-	sess_data->iov[1].iov_base = msg->data + msg->sesskey_len;
-	sess_data->iov[1].iov_len = msg->secblob_len;
+	/* Copy the key data here so that we can pass it to MSG_SPLICE_PAGES
+	 * and the need to copy the whole message.
+	 */
+	key_buf = cifs_allocate_tx_buf(server, msg->secblob_len);
+	if (!key_buf)
+		goto out;
+
+	memcpy(key_buf, msg->data + msg->sesskey_len, msg->secblob_len);
+	smb_add_segment_to_tx_buf(smb, key_buf, msg->secblob_len);
 
-	rc = SMB2_sess_sendreceive(sess_data);
+	rc = SMB2_sess_sendreceive(sess_data, smb);
 	if (rc)
 		goto out_put_spnego_key;
 
-	rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base;
+	rsp = (struct smb2_sess_setup_rsp *)smb->response;
 	/* keep session id and flags if binding */
 	if (!is_binding) {
 		ses->Suid = le64_to_cpu(rsp->hdr.SessionId);
@@ -1985,10 +1958,11 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
 		ses->auth_key.response = NULL;
 		ses->auth_key.len = 0;
 	}
+
 out:
+	smb_put_messages(smb);
 	sess_data->result = rc;
 	sess_data->func = NULL;
-	SMB2_sess_free_buffer(sess_data);
 }
 #else
 static void
@@ -2006,14 +1980,13 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data);
 static void
 SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
 {
-	int rc;
-	struct cifs_ses *ses = sess_data->ses;
-	struct TCP_Server_Info *server = sess_data->server;
 	struct smb2_sess_setup_rsp *rsp = NULL;
-	unsigned char *ntlmssp_blob = NULL;
+	struct TCP_Server_Info *server = sess_data->server;
+	struct smb_message *smb = NULL;
+	struct cifs_ses *ses = sess_data->ses;
 	bool use_spnego = false; /* else use raw ntlmssp */
-	u16 blob_length = 0;
 	bool is_binding = false;
+	int rc = -ENOMEM;
 
 	/*
 	 * If memory allocation is successful, caller of this function
@@ -2026,13 +1999,12 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
 	}
 	ses->ntlmssp->sesskey_per_smbsess = true;
 
-	rc = SMB2_sess_alloc_buffer(sess_data);
-	if (rc)
+	smb = SMB2_create_session_request(sess_data);
+	if (!smb)
 		goto out_err;
 
-	rc = build_ntlmssp_smb3_negotiate_blob(&ntlmssp_blob,
-					  &blob_length, ses, server,
-					  sess_data->nls_cp);
+	rc = build_ntlmssp_smb3_negotiate_blob(smb, ses, server,
+					       sess_data->nls_cp);
 	if (rc)
 		goto out;
 
@@ -2042,15 +2014,12 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
 		rc = -EOPNOTSUPP;
 		goto out;
 	}
-	sess_data->iov[1].iov_base = ntlmssp_blob;
-	sess_data->iov[1].iov_len = blob_length;
 
-	rc = SMB2_sess_sendreceive(sess_data);
-	rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base;
+	rc = SMB2_sess_sendreceive(sess_data, smb);
+	rsp = (struct smb2_sess_setup_rsp *)smb->response;
 
 	/* If true, rc here is expected and not an error */
-	if (sess_data->buf0_type != CIFS_NO_BUFFER &&
-		rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED)
+	if (rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED)
 		rc = 0;
 
 	if (rc)
@@ -2081,14 +2050,13 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
 	}
 
 out:
-	kfree_sensitive(ntlmssp_blob);
-	SMB2_sess_free_buffer(sess_data);
 	if (!rc) {
 		sess_data->result = 0;
 		sess_data->func = SMB2_sess_auth_rawntlmssp_authenticate;
 		return;
 	}
 out_err:
+	smb_put_messages(smb);
 	kfree_sensitive(ses->ntlmssp);
 	ses->ntlmssp = NULL;
 	sess_data->result = rc;
@@ -2098,26 +2066,23 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
 static void
 SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data)
 {
-	int rc;
+	struct smb_message *smb;
 	struct cifs_ses *ses = sess_data->ses;
 	struct TCP_Server_Info *server = sess_data->server;
 	struct smb2_sess_setup_req *req;
 	struct smb2_sess_setup_rsp *rsp = NULL;
-	unsigned char *ntlmssp_blob = NULL;
 	bool use_spnego = false; /* else use raw ntlmssp */
-	u16 blob_length = 0;
 	bool is_binding = false;
+	int rc = -ENOMEM;
 
-	rc = SMB2_sess_alloc_buffer(sess_data);
-	if (rc)
+	smb = SMB2_create_session_request(sess_data);
+	if (!smb)
 		goto out;
 
-	req = (struct smb2_sess_setup_req *) sess_data->iov[0].iov_base;
+	req = smb->request;
 	req->hdr.SessionId = cpu_to_le64(ses->Suid);
 
-	rc = build_ntlmssp_auth_blob(&ntlmssp_blob, &blob_length,
-				     ses, server,
-				     sess_data->nls_cp);
+	rc = build_ntlmssp_auth_blob(smb, ses, server, sess_data->nls_cp);
 	if (rc) {
 		cifs_dbg(FYI, "build_ntlmssp_auth_blob failed %d\n", rc);
 		goto out;
@@ -2129,14 +2094,12 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data)
 		rc = -EOPNOTSUPP;
 		goto out;
 	}
-	sess_data->iov[1].iov_base = ntlmssp_blob;
-	sess_data->iov[1].iov_len = blob_length;
 
-	rc = SMB2_sess_sendreceive(sess_data);
+	rc = SMB2_sess_sendreceive(sess_data, smb);
 	if (rc)
 		goto out;
 
-	rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base;
+	rsp = (struct smb2_sess_setup_rsp *)smb->response;
 
 	spin_lock(&ses->ses_lock);
 	is_binding = (ses->ses_status == SES_GOOD);
@@ -2165,8 +2128,6 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data)
 	}
 #endif
 out:
-	kfree_sensitive(ntlmssp_blob);
-	SMB2_sess_free_buffer(sess_data);
 	kfree_sensitive(ses->ntlmssp);
 	ses->ntlmssp = NULL;
 	sess_data->result = rc;
@@ -2224,7 +2185,6 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
 	sess_data->xid = xid;
 	sess_data->ses = ses;
 	sess_data->server = server;
-	sess_data->buf0_type = CIFS_NO_BUFFER;
 	sess_data->nls_cp = (struct nls_table *) nls_cp;
 	sess_data->previous_session = ses->Suid;
 


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 26/31] cifs: Convert SMB2 Logoff request
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (24 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 25/31] cifs: Convert SMB2 Session Setup request David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 27/31] cifs: Convert SMB2 Tree Connect request David Howells
                   ` (8 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/smb2pdu.c | 31 +++++++++----------------------
 1 file changed, 9 insertions(+), 22 deletions(-)

diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 685af9c0cdcb..c63c62cd6638 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -2212,15 +2212,10 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
 int
 SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
 {
-	struct smb_rqst rqst;
-	struct smb2_logoff_req *req; /* response is also trivial struct */
-	int rc = 0;
 	struct TCP_Server_Info *server;
-	int flags = 0;
-	unsigned int total_len;
-	struct kvec iov[1];
-	struct kvec rsp_iov;
-	int resp_buf_type;
+	struct smb2_logoff_req *req; /* response is also trivial struct */
+	struct smb_message *smb = NULL;
+	int rc = 0, flags = 0;
 
 	cifs_dbg(FYI, "disconnect session %p\n", ses);
 
@@ -2237,10 +2232,10 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
 	}
 	spin_unlock(&ses->chan_lock);
 
-	rc = smb2_plain_req_init(SMB2_LOGOFF, NULL, ses->server,
-				 (void **) &req, &total_len);
-	if (rc)
-		return rc;
+	smb = smb2_create_request(SMB2_LOGOFF, server, NULL,
+				  sizeof(*req), sizeof(*req), 0, 0);
+	if (!smb)
+		return -ENOMEM;
 
 	 /* since no tcon, smb2_init can not do this, so do here */
 	req->hdr.SessionId = cpu_to_le64(ses->Suid);
@@ -2252,21 +2247,13 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
 
 	flags |= CIFS_NO_RSP_BUF;
 
-	iov[0].iov_base = (char *)req;
-	iov[0].iov_len = total_len;
-
-	memset(&rqst, 0, sizeof(struct smb_rqst));
-	rqst.rq_iov = iov;
-	rqst.rq_nvec = 1;
-
-	rc = cifs_send_recv(xid, ses, ses->server,
-			    &rqst, &resp_buf_type, flags, &rsp_iov);
-	cifs_small_buf_release(req);
+	rc = smb_send_recv_messages(xid, ses, ses->server, smb, flags);
 	/*
 	 * No tcon so can't do
 	 * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]);
 	 */
 
+	smb_put_messages(smb);
 smb2_session_already_dead:
 	return rc;
 }


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 27/31] cifs: Convert SMB2 Tree Connect request
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (25 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 26/31] cifs: Convert SMB2 Logoff request David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 28/31] cifs: Convert SMB2 Tree Disconnect request David Howells
                   ` (7 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/smb2pdu.c | 71 +++++++++++++++--------------------------
 1 file changed, 25 insertions(+), 46 deletions(-)

diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index c63c62cd6638..4300ae311ee2 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -2277,57 +2277,43 @@ int
 SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
 	  struct cifs_tcon *tcon, const struct nls_table *cp)
 {
-	struct smb_rqst rqst;
+	struct TCP_Server_Info *server = cifs_pick_channel(ses);
 	struct smb2_tree_connect_req *req;
 	struct smb2_tree_connect_rsp *rsp = NULL;
-	struct kvec iov[2];
-	struct kvec rsp_iov = { NULL, 0 };
-	int rc = 0;
-	int resp_buftype;
-	int unc_path_len;
-	__le16 *unc_path = NULL;
+	struct smb_message *smb = NULL;
+	int unc_path_size;
 	int flags = 0;
-	unsigned int total_len;
-	struct TCP_Server_Info *server = cifs_pick_channel(ses);
+	int rc = 0;
 
 	cifs_dbg(FYI, "TCON\n");
 
 	if (!server || !tree)
 		return -EIO;
 
-	unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL);
-	if (unc_path == NULL)
-		return -ENOMEM;
-
-	unc_path_len = cifs_strtoUTF16(unc_path, tree, strlen(tree), cp);
-	if (unc_path_len <= 0) {
-		kfree(unc_path);
-		return -EINVAL;
-	}
-	unc_path_len *= 2;
+	unc_path_size = cifs_size_strtoUTF16(tree, INT_MAX, cp);
 
 	/* SMB2 TREE_CONNECT request must be called with TreeId == 0 */
 	tcon->tid = 0;
 	atomic_set(&tcon->num_remote_opens, 0);
-	rc = smb2_plain_req_init(SMB2_TREE_CONNECT, tcon, server,
-				 (void **) &req, &total_len);
-	if (rc) {
-		kfree(unc_path);
-		return rc;
-	}
+
+	smb = smb2_create_request(SMB2_TREE_CONNECT, server, tcon,
+				  sizeof(*req), sizeof(*req) + unc_path_size, 0,
+				  SMB2_REQ_DYNAMIC);
+	if (!smb)
+		return -ENOMEM;
 
 	if (smb3_encryption_required(tcon))
 		flags |= CIFS_TRANSFORM_REQ;
 
-	iov[0].iov_base = (char *)req;
-	/* 1 for pad */
-	iov[0].iov_len = total_len - 1;
-
 	/* Testing shows that buffer offset must be at location of Buffer[0] */
-	req->PathOffset = cpu_to_le16(sizeof(struct smb2_tree_connect_req));
-	req->PathLength = cpu_to_le16(unc_path_len);
-	iov[1].iov_base = unc_path;
-	iov[1].iov_len = unc_path_len;
+	req->PathOffset = cpu_to_le16(smb->ext_offset);
+	req->PathLength = cpu_to_le16(unc_path_size);
+
+	rc = cifs_strtoUTF16(smb->request + smb->ext_offset, tree, strlen(tree), cp);
+	if (rc <= 0) {
+		rc = -EINVAL;
+		goto tcon_exit;
+	}
 
 	/*
 	 * 3.11 tcon req must be signed if not encrypted. See MS-SMB2 3.2.4.1.1
@@ -2341,22 +2327,17 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
 	    ((ses->user_name != NULL) || (ses->sectype == Kerberos)))
 		req->hdr.Flags |= SMB2_FLAGS_SIGNED;
 
-	memset(&rqst, 0, sizeof(struct smb_rqst));
-	rqst.rq_iov = iov;
-	rqst.rq_nvec = 2;
-
 	/* Need 64 for max size write so ask for more in case not there yet */
 	if (server->credits >= server->max_credits)
 		req->hdr.CreditRequest = cpu_to_le16(0);
 	else
 		req->hdr.CreditRequest = cpu_to_le16(
-			min_t(int, server->max_credits -
-			      server->credits, 64));
+			min_t(int, server->max_credits - server->credits, 64));
 
-	rc = cifs_send_recv(xid, ses, server,
-			    &rqst, &resp_buftype, flags, &rsp_iov);
-	cifs_small_buf_release(req);
-	rsp = (struct smb2_tree_connect_rsp *)rsp_iov.iov_base;
+	rc = smb_send_recv_messages(xid, ses, server, smb, flags);
+	smb_clear_request(smb);
+
+	rsp = (struct smb2_tree_connect_rsp *)smb->response;
 	trace_smb3_tcon(xid, tcon->tid, ses->Suid, tree, rc);
 	if ((rc != 0) || (rsp == NULL)) {
 		cifs_stats_fail_inc(tcon, SMB2_TREE_CONNECT);
@@ -2403,9 +2384,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
 		if (tcon->share_flags & SMB2_SHAREFLAG_ISOLATED_TRANSPORT)
 			server->nosharesock = true;
 tcon_exit:
-
-	free_rsp_buf(resp_buftype, rsp);
-	kfree(unc_path);
+	smb_put_messages(smb);
 	return rc;
 
 tcon_error_exit:


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 28/31] cifs: Convert SMB2 Tree Disconnect request
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (26 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 27/31] cifs: Convert SMB2 Tree Connect request David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 29/31] cifs: Rearrange Create request subfuncs David Howells
                   ` (6 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/smb2pdu.c | 31 ++++++++++---------------------
 1 file changed, 10 insertions(+), 21 deletions(-)

diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 4300ae311ee2..9357c4953d9f 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -2396,16 +2396,12 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
 int
 SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
 {
-	struct smb_rqst rqst;
 	struct smb2_tree_disconnect_req *req; /* response is trivial */
-	int rc = 0;
+	struct smb_message *smb = NULL;
 	struct cifs_ses *ses = tcon->ses;
 	struct TCP_Server_Info *server = cifs_pick_channel(ses);
 	int flags = 0;
-	unsigned int total_len;
-	struct kvec iov[1];
-	struct kvec rsp_iov;
-	int resp_buf_type;
+	int rc = 0;
 
 	cifs_dbg(FYI, "Tree Disconnect\n");
 
@@ -2423,33 +2419,26 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
 
 	invalidate_all_cached_dirs(tcon);
 
-	rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT, tcon, server,
-				 (void **) &req,
-				 &total_len);
-	if (rc)
-		return rc;
+	smb = smb2_create_request(SMB2_TREE_DISCONNECT, server, tcon,
+				  sizeof(*req), sizeof(*req), 0,
+				  SMB2_REQ_DYNAMIC);
+	if (!smb)
+		return -ENOMEM;
 
 	if (smb3_encryption_required(tcon))
 		flags |= CIFS_TRANSFORM_REQ;
 
 	flags |= CIFS_NO_RSP_BUF;
 
-	iov[0].iov_base = (char *)req;
-	iov[0].iov_len = total_len;
-
-	memset(&rqst, 0, sizeof(struct smb_rqst));
-	rqst.rq_iov = iov;
-	rqst.rq_nvec = 1;
-
-	rc = cifs_send_recv(xid, ses, server,
-			    &rqst, &resp_buf_type, flags, &rsp_iov);
-	cifs_small_buf_release(req);
+	rc = smb_send_recv_messages(xid, ses, server, smb, flags);
+	smb_clear_request(smb);
 	if (rc) {
 		cifs_stats_fail_inc(tcon, SMB2_TREE_DISCONNECT);
 		trace_smb3_tdis_err(xid, tcon->tid, ses->Suid, rc);
 	}
 	trace_smb3_tdis_done(xid, tcon->tid, ses->Suid);
 
+	smb_put_messages(smb);
 	return rc;
 }
 


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 29/31] cifs: Rearrange Create request subfuncs
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (27 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 28/31] cifs: Convert SMB2 Tree Disconnect request David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 30/31] cifs: Convert SMB2 Posix Mkdir request David Howells
                   ` (5 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/smb2pdu.c | 357 ++++++++++++++++++++--------------------
 1 file changed, 178 insertions(+), 179 deletions(-)

diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 9357c4953d9f..85486748dd7b 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -1228,61 +1228,6 @@ static int smb311_decode_neg_context(struct smb_message *smb,
 	return rc;
 }
 
-static struct create_posix *
-create_posix_buf(umode_t mode)
-{
-	struct create_posix *buf;
-
-	buf = kzalloc(sizeof(struct create_posix),
-			GFP_KERNEL);
-	if (!buf)
-		return NULL;
-
-	buf->ccontext.DataOffset =
-		cpu_to_le16(offsetof(struct create_posix, Mode));
-	buf->ccontext.DataLength = cpu_to_le32(4);
-	buf->ccontext.NameOffset =
-		cpu_to_le16(offsetof(struct create_posix, Name));
-	buf->ccontext.NameLength = cpu_to_le16(16);
-
-	/* SMB2_CREATE_TAG_POSIX is "0x93AD25509CB411E7B42383DE968BCD7C" */
-	buf->Name[0] = 0x93;
-	buf->Name[1] = 0xAD;
-	buf->Name[2] = 0x25;
-	buf->Name[3] = 0x50;
-	buf->Name[4] = 0x9C;
-	buf->Name[5] = 0xB4;
-	buf->Name[6] = 0x11;
-	buf->Name[7] = 0xE7;
-	buf->Name[8] = 0xB4;
-	buf->Name[9] = 0x23;
-	buf->Name[10] = 0x83;
-	buf->Name[11] = 0xDE;
-	buf->Name[12] = 0x96;
-	buf->Name[13] = 0x8B;
-	buf->Name[14] = 0xCD;
-	buf->Name[15] = 0x7C;
-	buf->Mode = cpu_to_le32(mode);
-	cifs_dbg(FYI, "mode on posix create 0%o\n", mode);
-	return buf;
-}
-
-static int
-add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode)
-{
-	unsigned int num = *num_iovec;
-
-	iov[num].iov_base = create_posix_buf(mode);
-	if (mode == ACL_NO_MODE)
-		cifs_dbg(FYI, "%s: no mode\n", __func__);
-	if (iov[num].iov_base == NULL)
-		return -ENOMEM;
-	iov[num].iov_len = sizeof(struct create_posix);
-	*num_iovec = num + 1;
-	return 0;
-}
-
-
 /*
  *
  *	SMB2 Worker functions follow:
@@ -2443,6 +2388,60 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
 }
 
 
+static struct create_posix *
+create_posix_buf(umode_t mode)
+{
+	struct create_posix *buf;
+
+	buf = kzalloc(sizeof(struct create_posix),
+			GFP_KERNEL);
+	if (!buf)
+		return NULL;
+
+	buf->ccontext.DataOffset =
+		cpu_to_le16(offsetof(struct create_posix, Mode));
+	buf->ccontext.DataLength = cpu_to_le32(4);
+	buf->ccontext.NameOffset =
+		cpu_to_le16(offsetof(struct create_posix, Name));
+	buf->ccontext.NameLength = cpu_to_le16(16);
+
+	/* SMB2_CREATE_TAG_POSIX is "0x93AD25509CB411E7B42383DE968BCD7C" */
+	buf->Name[0] = 0x93;
+	buf->Name[1] = 0xAD;
+	buf->Name[2] = 0x25;
+	buf->Name[3] = 0x50;
+	buf->Name[4] = 0x9C;
+	buf->Name[5] = 0xB4;
+	buf->Name[6] = 0x11;
+	buf->Name[7] = 0xE7;
+	buf->Name[8] = 0xB4;
+	buf->Name[9] = 0x23;
+	buf->Name[10] = 0x83;
+	buf->Name[11] = 0xDE;
+	buf->Name[12] = 0x96;
+	buf->Name[13] = 0x8B;
+	buf->Name[14] = 0xCD;
+	buf->Name[15] = 0x7C;
+	buf->Mode = cpu_to_le32(mode);
+	cifs_dbg(FYI, "mode on posix create 0%o\n", mode);
+	return buf;
+}
+
+static int
+add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode)
+{
+	unsigned int num = *num_iovec;
+
+	iov[num].iov_base = create_posix_buf(mode);
+	if (mode == ACL_NO_MODE)
+		cifs_dbg(FYI, "%s: no mode\n", __func__);
+	if (iov[num].iov_base == NULL)
+		return -ENOMEM;
+	iov[num].iov_len = sizeof(struct create_posix);
+	*num_iovec = num + 1;
+	return 0;
+}
+
 static struct create_durable *
 create_durable_buf(void)
 {
@@ -2491,130 +2490,6 @@ create_reconnect_durable_buf(struct cifs_fid *fid)
 	return buf;
 }
 
-static void
-parse_query_id_ctxt(struct create_context *cc, struct smb2_file_all_info *buf)
-{
-	struct create_disk_id_rsp *pdisk_id = (struct create_disk_id_rsp *)cc;
-
-	cifs_dbg(FYI, "parse query id context 0x%llx 0x%llx\n",
-		pdisk_id->DiskFileId, pdisk_id->VolumeId);
-	buf->IndexNumber = pdisk_id->DiskFileId;
-}
-
-static void
-parse_posix_ctxt(struct create_context *cc, struct smb2_file_all_info *info,
-		 struct create_posix_rsp *posix)
-{
-	int sid_len;
-	u8 *beg = (u8 *)cc + le16_to_cpu(cc->DataOffset);
-	u8 *end = beg + le32_to_cpu(cc->DataLength);
-	u8 *sid;
-
-	memset(posix, 0, sizeof(*posix));
-
-	posix->nlink = le32_to_cpu(*(__le32 *)(beg + 0));
-	posix->reparse_tag = le32_to_cpu(*(__le32 *)(beg + 4));
-	posix->mode = le32_to_cpu(*(__le32 *)(beg + 8));
-
-	sid = beg + 12;
-	sid_len = posix_info_sid_size(sid, end);
-	if (sid_len < 0) {
-		cifs_dbg(VFS, "bad owner sid in posix create response\n");
-		return;
-	}
-	memcpy(&posix->owner, sid, sid_len);
-
-	sid = sid + sid_len;
-	sid_len = posix_info_sid_size(sid, end);
-	if (sid_len < 0) {
-		cifs_dbg(VFS, "bad group sid in posix create response\n");
-		return;
-	}
-	memcpy(&posix->group, sid, sid_len);
-
-	cifs_dbg(FYI, "nlink=%d mode=%o reparse_tag=%x\n",
-		 posix->nlink, posix->mode, posix->reparse_tag);
-}
-
-int smb2_parse_contexts(struct TCP_Server_Info *server,
-			struct kvec *rsp_iov,
-			__u16 *epoch,
-			char *lease_key, __u8 *oplock,
-			struct smb2_file_all_info *buf,
-			struct create_posix_rsp *posix)
-{
-	struct smb2_create_rsp *rsp = rsp_iov->iov_base;
-	struct create_context *cc;
-	size_t rem, off, len;
-	size_t doff, dlen;
-	size_t noff, nlen;
-	char *name;
-	static const char smb3_create_tag_posix[] = {
-		0x93, 0xAD, 0x25, 0x50, 0x9C,
-		0xB4, 0x11, 0xE7, 0xB4, 0x23, 0x83,
-		0xDE, 0x96, 0x8B, 0xCD, 0x7C
-	};
-
-	*oplock = 0;
-
-	off = le32_to_cpu(rsp->CreateContextsOffset);
-	rem = le32_to_cpu(rsp->CreateContextsLength);
-	if (check_add_overflow(off, rem, &len) || len > rsp_iov->iov_len)
-		return -EINVAL;
-	cc = (struct create_context *)((u8 *)rsp + off);
-
-	/* Initialize inode number to 0 in case no valid data in qfid context */
-	if (buf)
-		buf->IndexNumber = 0;
-
-	while (rem >= sizeof(*cc)) {
-		doff = le16_to_cpu(cc->DataOffset);
-		dlen = le32_to_cpu(cc->DataLength);
-		if (check_add_overflow(doff, dlen, &len) || len > rem)
-			return -EINVAL;
-
-		noff = le16_to_cpu(cc->NameOffset);
-		nlen = le16_to_cpu(cc->NameLength);
-		if (noff + nlen > doff)
-			return -EINVAL;
-
-		name = (char *)cc + noff;
-		switch (nlen) {
-		case 4:
-			if (!strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4)) {
-				*oplock = server->ops->parse_lease_buf(cc, epoch,
-								       lease_key);
-			} else if (buf &&
-				   !strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 4)) {
-				parse_query_id_ctxt(cc, buf);
-			}
-			break;
-		case 16:
-			if (posix && !memcmp(name, smb3_create_tag_posix, 16))
-				parse_posix_ctxt(cc, buf, posix);
-			break;
-		default:
-			cifs_dbg(FYI, "%s: unhandled context (nlen=%zu dlen=%zu)\n",
-				 __func__, nlen, dlen);
-			if (IS_ENABLED(CONFIG_CIFS_DEBUG2))
-				cifs_dump_mem("context data: ", cc, dlen);
-			break;
-		}
-
-		off = le32_to_cpu(cc->Next);
-		if (!off)
-			break;
-		if (check_sub_overflow(rem, off, &rem))
-			return -EINVAL;
-		cc = (struct create_context *)((u8 *)cc + off);
-	}
-
-	if (rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE)
-		*oplock = rsp->OplockLevel;
-
-	return 0;
-}
-
 static int
 add_lease_context(struct TCP_Server_Info *server,
 		  struct smb2_create_req *req,
@@ -3383,6 +3258,130 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
 	return 0;
 }
 
+static void
+parse_query_id_ctxt(struct create_context *cc, struct smb2_file_all_info *buf)
+{
+	struct create_disk_id_rsp *pdisk_id = (struct create_disk_id_rsp *)cc;
+
+	cifs_dbg(FYI, "parse query id context 0x%llx 0x%llx\n",
+		pdisk_id->DiskFileId, pdisk_id->VolumeId);
+	buf->IndexNumber = pdisk_id->DiskFileId;
+}
+
+static void
+parse_posix_ctxt(struct create_context *cc, struct smb2_file_all_info *info,
+		 struct create_posix_rsp *posix)
+{
+	int sid_len;
+	u8 *beg = (u8 *)cc + le16_to_cpu(cc->DataOffset);
+	u8 *end = beg + le32_to_cpu(cc->DataLength);
+	u8 *sid;
+
+	memset(posix, 0, sizeof(*posix));
+
+	posix->nlink = le32_to_cpu(*(__le32 *)(beg + 0));
+	posix->reparse_tag = le32_to_cpu(*(__le32 *)(beg + 4));
+	posix->mode = le32_to_cpu(*(__le32 *)(beg + 8));
+
+	sid = beg + 12;
+	sid_len = posix_info_sid_size(sid, end);
+	if (sid_len < 0) {
+		cifs_dbg(VFS, "bad owner sid in posix create response\n");
+		return;
+	}
+	memcpy(&posix->owner, sid, sid_len);
+
+	sid = sid + sid_len;
+	sid_len = posix_info_sid_size(sid, end);
+	if (sid_len < 0) {
+		cifs_dbg(VFS, "bad group sid in posix create response\n");
+		return;
+	}
+	memcpy(&posix->group, sid, sid_len);
+
+	cifs_dbg(FYI, "nlink=%d mode=%o reparse_tag=%x\n",
+		 posix->nlink, posix->mode, posix->reparse_tag);
+}
+
+int smb2_parse_contexts(struct TCP_Server_Info *server,
+			struct kvec *rsp_iov,
+			__u16 *epoch,
+			char *lease_key, __u8 *oplock,
+			struct smb2_file_all_info *buf,
+			struct create_posix_rsp *posix)
+{
+	struct smb2_create_rsp *rsp = rsp_iov->iov_base;
+	struct create_context *cc;
+	size_t rem, off, len;
+	size_t doff, dlen;
+	size_t noff, nlen;
+	char *name;
+	static const char smb3_create_tag_posix[] = {
+		0x93, 0xAD, 0x25, 0x50, 0x9C,
+		0xB4, 0x11, 0xE7, 0xB4, 0x23, 0x83,
+		0xDE, 0x96, 0x8B, 0xCD, 0x7C
+	};
+
+	*oplock = 0;
+
+	off = le32_to_cpu(rsp->CreateContextsOffset);
+	rem = le32_to_cpu(rsp->CreateContextsLength);
+	if (check_add_overflow(off, rem, &len) || len > rsp_iov->iov_len)
+		return -EINVAL;
+	cc = (struct create_context *)((u8 *)rsp + off);
+
+	/* Initialize inode number to 0 in case no valid data in qfid context */
+	if (buf)
+		buf->IndexNumber = 0;
+
+	while (rem >= sizeof(*cc)) {
+		doff = le16_to_cpu(cc->DataOffset);
+		dlen = le32_to_cpu(cc->DataLength);
+		if (check_add_overflow(doff, dlen, &len) || len > rem)
+			return -EINVAL;
+
+		noff = le16_to_cpu(cc->NameOffset);
+		nlen = le16_to_cpu(cc->NameLength);
+		if (noff + nlen > doff)
+			return -EINVAL;
+
+		name = (char *)cc + noff;
+		switch (nlen) {
+		case 4:
+			if (!strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4)) {
+				*oplock = server->ops->parse_lease_buf(cc, epoch,
+								       lease_key);
+			} else if (buf &&
+				   !strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 4)) {
+				parse_query_id_ctxt(cc, buf);
+			}
+			break;
+		case 16:
+			if (posix && !memcmp(name, smb3_create_tag_posix, 16))
+				parse_posix_ctxt(cc, buf, posix);
+			break;
+		default:
+			cifs_dbg(FYI, "%s: unhandled context (nlen=%zu dlen=%zu)\n",
+				 __func__, nlen, dlen);
+			if (IS_ENABLED(CONFIG_CIFS_DEBUG2))
+				cifs_dump_mem("context data: ", cc, dlen);
+			break;
+		}
+
+		off = le32_to_cpu(cc->Next);
+		if (!off)
+			break;
+		if (check_sub_overflow(rem, off, &rem))
+			return -EINVAL;
+		cc = (struct create_context *)((u8 *)cc + off);
+	}
+
+	if (rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE)
+		*oplock = rsp->OplockLevel;
+
+	return 0;
+}
+
 /* rq_iov[0] is the request and is released by cifs_small_buf_release().
  * All other vectors are freed by kfree().
  */


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 30/31] cifs: Convert SMB2 Posix Mkdir request
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (28 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 29/31] cifs: Rearrange Create request subfuncs David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-06 20:36 ` [RFC PATCH 31/31] cifs: Convert SMB2 Open request David Howells
                   ` (4 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/smb2pdu.c | 244 ++++++++++++++++++++++------------------
 1 file changed, 137 insertions(+), 107 deletions(-)

diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 85486748dd7b..9fc55b315474 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -2388,16 +2388,8 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
 }
 
 
-static struct create_posix *
-create_posix_buf(umode_t mode)
+static void fill_posix_buf(struct create_posix *buf, umode_t mode)
 {
-	struct create_posix *buf;
-
-	buf = kzalloc(sizeof(struct create_posix),
-			GFP_KERNEL);
-	if (!buf)
-		return NULL;
-
 	buf->ccontext.DataOffset =
 		cpu_to_le16(offsetof(struct create_posix, Mode));
 	buf->ccontext.DataLength = cpu_to_le32(4);
@@ -2424,20 +2416,25 @@ create_posix_buf(umode_t mode)
 	buf->Name[15] = 0x7C;
 	buf->Mode = cpu_to_le32(mode);
 	cifs_dbg(FYI, "mode on posix create 0%o\n", mode);
-	return buf;
 }
 
 static int
 add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode)
 {
+	struct create_posix *buf;
 	unsigned int num = *num_iovec;
 
-	iov[num].iov_base = create_posix_buf(mode);
 	if (mode == ACL_NO_MODE)
 		cifs_dbg(FYI, "%s: no mode\n", __func__);
-	if (iov[num].iov_base == NULL)
+
+	buf = kzalloc(sizeof(struct create_posix), GFP_KERNEL);
+	if (!buf)
 		return -ENOMEM;
-	iov[num].iov_len = sizeof(struct create_posix);
+
+	fill_posix_buf(buf, mode);
+
+	iov[num].iov_base = buf;
+	iov[num].iov_len  = sizeof(struct create_posix);
 	*num_iovec = num + 1;
 	return 0;
 }
@@ -2906,72 +2903,140 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len,
 	return 0;
 }
 
+struct smb2_create_layout {
+	const struct nls_table *cp;
+	u16		offset;		/* Running offset for assembly */
+	u16		path_len;	/* Length of utf16 path (or 0) */
+	u16		treename_len;	/* Length of DFS prefix (or 0) */
+	u16		name_len;	/* Total name length */
+	u16		name_offset;	/* Offset in message of name */
+	u16		contexts_offset; /* Offset in message contexts */
+	u16		contexts_len;	/* Length of contexts (or 0) */
+	u16		posix_offset;	/* Offset in message of posix context */
+	u8		name_pad;	/* Amount of name padding needed */
+};
+
+static int smb311_posix_mkdir_layout(struct cifs_tcon *tcon,
+				     struct smb2_create_layout *lay)
+{
+	size_t offset = lay->offset;
+	size_t tmp;
+	bool has_contexts = false;
+
+	/* [MS-SMB2] 2.2.13 NameOffset: If SMB2_FLAGS_DFS_OPERATIONS
+	 * is set in the Flags field of the SMB2 header, the file name
+	 * includes a prefix that will be processed during DFS name
+	 * normalization as specified in section 3.3.5.9. Otherwise,
+	 * the file name is relative to the share that is identified
+	 * by the TreeId in the SMB2 header.
+	 */
+	lay->name_offset = offset;
+	if (tcon->share_flags & SHI1005_FLAGS_DFS) {
+		const char *treename = tcon->tree_name;
+		int treename_len;
+
+		/* skip leading "\\" */
+		if (!(treename[0] == '\\' && treename[1] == '\\'))
+			return -EINVAL;
+
+		treename_len = cifs_size_strtoUTF16(treename + 2, INT_MAX, lay->cp);
+
+		lay->treename_len = treename_len;
+		lay->name_len = treename_len;
+		if (lay->path_len)
+			lay->name_len += 2 + lay->path_len;
+	} else {
+		lay->name_len = lay->path_len;
+	}
+
+	offset += lay->name_len;
+	tmp = offset;
+	offset = ALIGN8(offset);
+	lay->name_pad = offset - tmp;
+	lay->contexts_offset = offset;
+
+	if (tcon->posix_extensions) {
+		/* resource #3: posix buf */
+		offset += sizeof(struct create_posix);
+		has_contexts = true;
+	}
+
+	if (has_contexts)
+		lay->contexts_len = offset - lay->contexts_offset;
+	else
+		lay->contexts_offset = 0;
+
+	lay->offset = offset;
+	return 0;
+}
+
 int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
 			       umode_t mode, struct cifs_tcon *tcon,
 			       const char *full_path,
 			       struct cifs_sb_info *cifs_sb)
 {
-	struct smb_rqst rqst;
+	struct TCP_Server_Info *server;
 	struct smb2_create_req *req;
 	struct smb2_create_rsp *rsp = NULL;
+	struct smb_message *smb = NULL;
 	struct cifs_ses *ses = tcon->ses;
-	struct kvec iov[3]; /* make sure at least one for each open context */
-	struct kvec rsp_iov = {NULL, 0};
-	int resp_buftype;
-	int uni_path_len;
-	__le16 *copy_path = NULL;
-	int copy_size;
-	int rc = 0;
-	unsigned int n_iov = 2;
+	__le16 *utf16_path = NULL;
 	__u32 file_attributes = 0;
-	char *pc_buf = NULL;
+	int retries = 0, cur_sleep = 1, path_len;
 	int flags = 0;
-	unsigned int total_len;
-	__le16 *utf16_path = NULL;
-	struct TCP_Server_Info *server;
-	int retries = 0, cur_sleep = 1;
+	int rc = 0;
+
+	/* resource #1: path allocation */
+	utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
+	if (!utf16_path)
+		return -ENOMEM;
+	path_len = UniStrlen(utf16_path);
 
 replay_again:
 	/* reinitialize for possible replay */
 	flags = 0;
-	n_iov = 2;
 	server = cifs_pick_channel(ses);
 
 	cifs_dbg(FYI, "mkdir\n");
 
-	/* resource #1: path allocation */
-	utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
-	if (!utf16_path)
-		return -ENOMEM;
-
-	if (!ses || !server) {
+	if (!server) {
 		rc = -EIO;
 		goto err_free_path;
 	}
 
+	struct smb2_create_layout layout = {
+		.offset		= sizeof(struct smb2_create_req),
+		.path_len	= path_len,
+		.cp		= cifs_sb->local_nls,
+	};
+	rc = smb311_posix_mkdir_layout(tcon, &layout);
+	if (rc < 0)
+		goto err_free_path;
+
 	/* resource #2: request */
-	rc = smb2_plain_req_init(SMB2_CREATE, tcon, server,
-				 (void **) &req, &total_len);
-	if (rc)
+	rc = -ENOMEM;
+	smb = smb2_create_request(SMB2_CREATE, server, tcon,
+				  sizeof(*req), layout.offset, 0,
+				  SMB2_REQ_DYNAMIC);
+	if (!smb)
 		goto err_free_path;
 
 
 	if (smb3_encryption_required(tcon))
 		flags |= CIFS_TRANSFORM_REQ;
 
-	req->ImpersonationLevel = IL_IMPERSONATION;
-	req->DesiredAccess = cpu_to_le32(FILE_WRITE_ATTRIBUTES);
+	req->ImpersonationLevel	= IL_IMPERSONATION;
+	req->DesiredAccess	= cpu_to_le32(FILE_WRITE_ATTRIBUTES);
 	/* File attributes ignored on open (used in create though) */
-	req->FileAttributes = cpu_to_le32(file_attributes);
-	req->ShareAccess = FILE_SHARE_ALL_LE;
-	req->CreateDisposition = cpu_to_le32(FILE_CREATE);
-	req->CreateOptions = cpu_to_le32(CREATE_NOT_FILE);
-
-	iov[0].iov_base = (char *)req;
-	/* -1 since last byte is buf[0] which is sent below (path) */
-	iov[0].iov_len = total_len - 1;
-
-	req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req));
+	req->FileAttributes	= cpu_to_le32(file_attributes);
+	req->ShareAccess	= FILE_SHARE_ALL_LE;
+	req->CreateDisposition	= cpu_to_le32(FILE_CREATE);
+	req->CreateOptions	= cpu_to_le32(CREATE_NOT_FILE);
+	req->NameOffset		= cpu_to_le16(layout.name_offset);
+	req->NameLength		= cpu_to_le16(layout.name_len);
+	req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
+	req->CreateContextsOffset = cpu_to_le32(layout.contexts_offset);
+	req->CreateContextsLength = cpu_to_le32(layout.contexts_len);
 
 	/* [MS-SMB2] 2.2.13 NameOffset:
 	 * If SMB2_FLAGS_DFS_OPERATIONS is set in the Flags field of
@@ -2981,78 +3046,48 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
 	 * the share that is identified by the TreeId in the SMB2
 	 * header.
 	 */
+	__le16 *name = smb->request + layout.name_offset;
+
 	if (tcon->share_flags & SHI1005_FLAGS_DFS) {
-		int name_len;
+		int tmp;
 
 		req->hdr.Flags |= SMB2_FLAGS_DFS_OPERATIONS;
-		rc = alloc_path_with_tree_prefix(&copy_path, &copy_size,
-						 &name_len,
-						 tcon->tree_name, utf16_path);
-		if (rc)
-			goto err_free_req;
 
-		req->NameLength = cpu_to_le16(name_len * 2);
-		uni_path_len = copy_size;
-		/* free before overwriting resource */
-		kfree(utf16_path);
-		utf16_path = copy_path;
-	} else {
-		uni_path_len = (2 * UniStrnlen((wchar_t *)utf16_path, PATH_MAX)) + 2;
-		/* MUST set path len (NameLength) to 0 opening root of share */
-		req->NameLength = cpu_to_le16(uni_path_len - 2);
-		if (uni_path_len % 8 != 0) {
-			copy_size = roundup(uni_path_len, 8);
-			copy_path = kzalloc(copy_size, GFP_KERNEL);
-			if (!copy_path) {
-				rc = -ENOMEM;
-				goto err_free_req;
-			}
-			memcpy((char *)copy_path, (const char *)utf16_path,
-			       uni_path_len);
-			uni_path_len = copy_size;
-			/* free before overwriting resource */
-			kfree(utf16_path);
-			utf16_path = copy_path;
+		tmp = cifs_strtoUTF16(name, tcon->tree_name + 2, INT_MAX,
+				      layout.cp);
+		WARN_ON(tmp != layout.treename_len);
+		name += tmp;
+		if (layout.path_len) {
+			*name++ = cpu_to_le16('\\');
+			memcpy(name, utf16_path, layout.path_len);
 		}
+	} else {
+		memcpy(name, utf16_path, layout.path_len);
 	}
 
-	iov[1].iov_len = uni_path_len;
-	iov[1].iov_base = utf16_path;
-	req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
+	if (layout.name_pad)
+		memset(smb->request + layout.name_offset + layout.name_len,
+		       0, layout.name_pad);
 
-	if (tcon->posix_extensions) {
+	if (tcon->posix_extensions)
 		/* resource #3: posix buf */
-		rc = add_posix_context(iov, &n_iov, mode);
-		if (rc)
-			goto err_free_req;
-		req->CreateContextsOffset = cpu_to_le32(
-			sizeof(struct smb2_create_req) +
-			iov[1].iov_len);
-		le32_add_cpu(&req->CreateContextsLength, iov[n_iov-1].iov_len);
-		pc_buf = iov[n_iov-1].iov_base;
-	}
-
-
-	memset(&rqst, 0, sizeof(struct smb_rqst));
-	rqst.rq_iov = iov;
-	rqst.rq_nvec = n_iov;
+		fill_posix_buf(smb->request + layout.posix_offset, mode);
 
 	/* no need to inc num_remote_opens because we close it just below */
 	trace_smb3_posix_mkdir_enter(xid, tcon->tid, ses->Suid, full_path, CREATE_NOT_FILE,
 				    FILE_WRITE_ATTRIBUTES);
 
 	if (retries)
-		smb2_set_replay(server, &rqst);
+		smb2_set_replay_smb(server, smb);
 
 	/* resource #4: response buffer */
-	rc = cifs_send_recv(xid, ses, server,
-			    &rqst, &resp_buftype, flags, &rsp_iov);
+	rc = smb_send_recv_messages(xid, ses, server, smb, flags);
 	if (rc) {
 		cifs_stats_fail_inc(tcon, SMB2_CREATE);
 		trace_smb3_posix_mkdir_err(xid, tcon->tid, ses->Suid,
 					   CREATE_NOT_FILE,
 					   FILE_WRITE_ATTRIBUTES, rc);
-		goto err_free_rsp_buf;
+		goto err_free_req;
 	}
 
 	/*
@@ -3060,10 +3095,9 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
 	 * adding check below is slightly safer long term (and quiets Coverity
 	 * warning)
 	 */
-	rsp = (struct smb2_create_rsp *)rsp_iov.iov_base;
+	rsp = (struct smb2_create_rsp *)smb->response;
 	if (rsp == NULL) {
 		rc = -EIO;
-		kfree(pc_buf);
 		goto err_free_req;
 	}
 
@@ -3074,18 +3108,14 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
 
 	/* Eventually save off posix specific response info and timestamps */
 
-err_free_rsp_buf:
-	free_rsp_buf(resp_buftype, rsp_iov.iov_base);
-	kfree(pc_buf);
 err_free_req:
-	cifs_small_buf_release(req);
+	smb_put_messages(smb);
 err_free_path:
-	kfree(utf16_path);
-
 	if (is_replayable_error(rc) &&
 	    smb2_should_replay(tcon, &retries, &cur_sleep))
 		goto replay_again;
 
+	kfree(utf16_path);
 	return rc;
 }
 


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [RFC PATCH 31/31] cifs: Convert SMB2 Open request
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (29 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 30/31] cifs: Convert SMB2 Posix Mkdir request David Howells
@ 2025-08-06 20:36 ` David Howells
  2025-08-07  5:23 ` [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator Stefan Metzmacher
                   ` (3 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-06 20:36 UTC (permalink / raw)
  To: Steve French
  Cc: David Howells, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/cached_dir.c |  41 +-
 fs/smb/client/cifsglob.h   |   5 +-
 fs/smb/client/smb2inode.c  |   6 +-
 fs/smb/client/smb2ops.c    |  34 +-
 fs/smb/client/smb2pdu.c    | 877 +++++++++++++++----------------------
 fs/smb/client/smb2proto.h  |  29 +-
 6 files changed, 399 insertions(+), 593 deletions(-)

diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
index 368e870624da..e4534f6b31da 100644
--- a/fs/smb/client/cached_dir.c
+++ b/fs/smb/client/cached_dir.c
@@ -141,9 +141,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
 	struct cifs_open_parms oparms;
 	struct smb2_create_rsp *o_rsp = NULL;
 	struct smb2_query_info_rsp *qi_rsp = NULL;
-	int resp_buftype[2];
-	struct smb_rqst rqst[2];
-	struct kvec rsp_iov[2];
+	struct smb_message *smb;
 	struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
 	struct kvec qi_iov[1];
 	int rc, flags = 0;
@@ -260,29 +258,20 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
 
 	server->ops->new_lease_key(pfid);
 
-	memset(rqst, 0, sizeof(rqst));
-	resp_buftype[0] = resp_buftype[1] = CIFS_NO_BUFFER;
-	memset(rsp_iov, 0, sizeof(rsp_iov));
-
 	/* Open */
-	memset(&open_iov, 0, sizeof(open_iov));
-	rqst[0].rq_iov = open_iov;
-	rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
-
 	oparms = (struct cifs_open_parms) {
-		.tcon = tcon,
-		.path = path,
-		.create_options = cifs_create_options(cifs_sb, CREATE_NOT_FILE),
-		.desired_access =  FILE_READ_DATA | FILE_READ_ATTRIBUTES |
-				   FILE_READ_EA,
-		.disposition = FILE_OPEN,
-		.fid = pfid,
-		.lease_flags = lease_flags,
-		.replay = !!(retries),
+		.tcon		= tcon,
+		.path		= path,
+		.create_options	= cifs_create_options(cifs_sb, CREATE_NOT_FILE),
+		.desired_access	= FILE_READ_DATA | FILE_READ_ATTRIBUTES |
+				  FILE_READ_EA,
+		.disposition	= FILE_OPEN,
+		.fid		= pfid,
+		.lease_flags	= lease_flags,
+		.replay		= !!(retries),
 	};
 
-	rc = SMB2_open_init(tcon, server,
-			    &rqst[0], &oplock, &oparms, utf16_path);
+	smb = SMB2_open_init(tcon, server, &oplock, &oparms, utf16_path);
 	if (rc)
 		goto oshr_free;
 	smb2_set_next_command(tcon, &rqst[0]);
@@ -336,10 +325,10 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
 		goto oshr_free;
 	}
 
-	rc = smb2_parse_contexts(server, rsp_iov,
-				 &oparms.fid->epoch,
-				 oparms.fid->lease_key,
-				 &oplock, NULL, NULL);
+	rc = smb2_parse_create_response(server, rsp_iov,
+					&oparms.fid->epoch,
+					oparms.fid->lease_key,
+					&oplock, NULL, NULL);
 	if (rc) {
 		spin_unlock(&cfids->cfid_list_lock);
 		goto oshr_free;
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 0cc71f504c68..b96c45f57c2b 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -554,8 +554,9 @@ struct smb_version_operations {
 	/* set oplock level for the inode */
 	void (*set_oplock_level)(struct cifsInodeInfo *cinode, __u32 oplock, __u16 epoch,
 				 bool *purge_cache);
-	/* create lease context buffer for CREATE request */
-	char * (*create_lease_buf)(u8 *lease_key, u8 oplock, u8 *parent_lease_key, __le32 le_flags);
+	/* Fill in a lease context buffer for CREATE request */
+	void (*fill_lease_buf)(struct smb_message *smb, const u8 *lease_key, u8 oplock,
+			       const u8 *parent_lease_key, __le32 le_flags);
 	/* parse lease context buffer and return oplock/epoch info */
 	__u8 (*parse_lease_buf)(void *buf, __u16 *epoch, char *lkey);
 	ssize_t (*copychunk_range)(const unsigned int,
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
index 2a3e46b8e15a..c5041fa94779 100644
--- a/fs/smb/client/smb2inode.c
+++ b/fs/smb/client/smb2inode.c
@@ -663,9 +663,9 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
 		idata->fi.DeletePending = 0;
 		idata->fi.Directory = !!(le32_to_cpu(create_rsp->FileAttributes) & ATTR_DIRECTORY);
 
-		/* smb2_parse_contexts() fills idata->fi.IndexNumber */
-		rc = smb2_parse_contexts(server, &rsp_iov[0], &oparms->fid->epoch,
-					 oparms->fid->lease_key, &oplock, &idata->fi, NULL);
+		/* smb2_parse_create_response() fills idata->fi.IndexNumber */
+		rc = smb2_parse_create_response(server, &rsp_iov[0], &oparms->fid->epoch,
+						oparms->fid->lease_key, &oplock, &idata->fi, NULL);
 		if (rc)
 			cifs_dbg(VFS, "rc: %d parsing context of compound op\n", rc);
 	}
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 9db383ec22e8..7c30475054b8 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -4086,14 +4086,11 @@ map_oplock_to_lease(u8 oplock)
 	return 0;
 }
 
-static char *
-smb2_create_lease_buf(u8 *lease_key, u8 oplock, u8 *parent_lease_key, __le32 flags)
+static void
+smb2_fill_lease_buf(struct smb_message *smb, const u8 *lease_key, u8 oplock,
+		    const u8 *parent_lease_key, __le32 flags)
 {
-	struct create_lease *buf;
-
-	buf = kzalloc(sizeof(struct create_lease), GFP_KERNEL);
-	if (!buf)
-		return NULL;
+	struct create_lease *buf = cifs_begin_extension(smb);
 
 	memcpy(&buf->lcontext.LeaseKey, lease_key, SMB2_LEASE_KEY_SIZE);
 	buf->lcontext.LeaseState = map_oplock_to_lease(oplock);
@@ -4109,17 +4106,14 @@ smb2_create_lease_buf(u8 *lease_key, u8 oplock, u8 *parent_lease_key, __le32 fla
 	buf->Name[1] = 'q';
 	buf->Name[2] = 'L';
 	buf->Name[3] = 's';
-	return (char *)buf;
+	cifs_end_extension(smb, sizeof(*buf));
 }
 
-static char *
-smb3_create_lease_buf(u8 *lease_key, u8 oplock, u8 *parent_lease_key, __le32 flags)
+static void
+smb3_fill_lease_buf(struct smb_message *smb, const u8 *lease_key, u8 oplock,
+		    const u8 *parent_lease_key, __le32 flags)
 {
-	struct create_lease_v2 *buf;
-
-	buf = kzalloc(sizeof(struct create_lease_v2), GFP_KERNEL);
-	if (!buf)
-		return NULL;
+	struct create_lease_v2 *buf = cifs_begin_extension(smb);
 
 	memcpy(&buf->lcontext.LeaseKey, lease_key, SMB2_LEASE_KEY_SIZE);
 	buf->lcontext.LeaseState = map_oplock_to_lease(oplock);
@@ -4138,7 +4132,7 @@ smb3_create_lease_buf(u8 *lease_key, u8 oplock, u8 *parent_lease_key, __le32 fla
 	buf->Name[1] = 'q';
 	buf->Name[2] = 'L';
 	buf->Name[3] = 's';
-	return (char *)buf;
+	cifs_end_extension(smb, sizeof(*buf));
 }
 
 static __u8
@@ -5263,7 +5257,7 @@ struct smb_version_operations smb20_operations = {
 	.calc_signature = smb2_calc_signature,
 	.is_read_op = smb2_is_read_op,
 	.set_oplock_level = smb2_set_oplock_level,
-	.create_lease_buf = smb2_create_lease_buf,
+	.fill_lease_buf = smb2_fill_lease_buf,
 	.parse_lease_buf = smb2_parse_lease_buf,
 	.copychunk_range = smb2_copychunk_range,
 	.wp_retry_size = smb2_wp_retry_size,
@@ -5366,7 +5360,7 @@ struct smb_version_operations smb21_operations = {
 	.calc_signature = smb2_calc_signature,
 	.is_read_op = smb21_is_read_op,
 	.set_oplock_level = smb21_set_oplock_level,
-	.create_lease_buf = smb2_create_lease_buf,
+	.fill_lease_buf = smb2_fill_lease_buf,
 	.parse_lease_buf = smb2_parse_lease_buf,
 	.copychunk_range = smb2_copychunk_range,
 	.wp_retry_size = smb2_wp_retry_size,
@@ -5476,7 +5470,7 @@ struct smb_version_operations smb30_operations = {
 	.set_integrity  = smb3_set_integrity,
 	.is_read_op = smb21_is_read_op,
 	.set_oplock_level = smb3_set_oplock_level,
-	.create_lease_buf = smb3_create_lease_buf,
+	.fill_lease_buf = smb3_fill_lease_buf,
 	.parse_lease_buf = smb3_parse_lease_buf,
 	.copychunk_range = smb2_copychunk_range,
 	.duplicate_extents = smb2_duplicate_extents,
@@ -5592,7 +5586,7 @@ struct smb_version_operations smb311_operations = {
 	.set_integrity  = smb3_set_integrity,
 	.is_read_op = smb21_is_read_op,
 	.set_oplock_level = smb3_set_oplock_level,
-	.create_lease_buf = smb3_create_lease_buf,
+	.fill_lease_buf = smb3_fill_lease_buf,
 	.parse_lease_buf = smb3_parse_lease_buf,
 	.copychunk_range = smb2_copychunk_range,
 	.duplicate_extents = smb2_duplicate_extents,
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 9fc55b315474..e9827aeab43f 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -2387,298 +2387,179 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
 	return rc;
 }
 
-
-static void fill_posix_buf(struct create_posix *buf, umode_t mode)
+/*
+ * Begin a create context record.  This fills in the chain pointer on the
+ * previous record if there was one.
+ */
+static void *cifs_begin_ccontext(struct smb_message *smb)
 {
-	buf->ccontext.DataOffset =
-		cpu_to_le16(offsetof(struct create_posix, Mode));
-	buf->ccontext.DataLength = cpu_to_le32(4);
-	buf->ccontext.NameOffset =
-		cpu_to_le16(offsetof(struct create_posix, Name));
-	buf->ccontext.NameLength = cpu_to_le16(16);
+	struct create_context_hdr *ccontext = cifs_begin_extension(smb);
 
-	/* SMB2_CREATE_TAG_POSIX is "0x93AD25509CB411E7B42383DE968BCD7C" */
-	buf->Name[0] = 0x93;
-	buf->Name[1] = 0xAD;
-	buf->Name[2] = 0x25;
-	buf->Name[3] = 0x50;
-	buf->Name[4] = 0x9C;
-	buf->Name[5] = 0xB4;
-	buf->Name[6] = 0x11;
-	buf->Name[7] = 0xE7;
-	buf->Name[8] = 0xB4;
-	buf->Name[9] = 0x23;
-	buf->Name[10] = 0x83;
-	buf->Name[11] = 0xDE;
-	buf->Name[12] = 0x96;
-	buf->Name[13] = 0x8B;
-	buf->Name[14] = 0xCD;
-	buf->Name[15] = 0x7C;
-	buf->Mode = cpu_to_le32(mode);
-	cifs_dbg(FYI, "mode on posix create 0%o\n", mode);
+	if (smb->latest_record) {
+		struct create_context_hdr *latest = smb->request + smb->latest_record;
+
+		latest->Next = cpu_to_le32(smb->offset - smb->latest_record);
+	}
+	smb->latest_record = smb->offset;
+	return ccontext;
 }
 
-static int
-add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode)
+#define CREATE_CONTEXT_HDR(ptr, name, data, namelen) {			\
+		.NameOffset = cpu_to_le16(offsetof(ptr, name)),		\
+		.NameLength = cpu_to_le16(namelen),			\
+		.DataOffset = cpu_to_le16(offsetof(ptr, data)),		\
+		.DataLength = cpu_to_le32(sizeof_field(ptr, data)),	\
+	}
+
+static void fill_posix_context(struct smb_message *smb, umode_t mode)
 {
-	struct create_posix *buf;
-	unsigned int num = *num_iovec;
+	struct create_posix *buf = cifs_begin_ccontext(smb);
 
 	if (mode == ACL_NO_MODE)
 		cifs_dbg(FYI, "%s: no mode\n", __func__);
 
-	buf = kzalloc(sizeof(struct create_posix), GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	fill_posix_buf(buf, mode);
-
-	iov[num].iov_base = buf;
-	iov[num].iov_len  = sizeof(struct create_posix);
-	*num_iovec = num + 1;
-	return 0;
+	*buf = (struct create_posix){
+		.ccontext = CREATE_CONTEXT_HDR(struct create_posix, Name, Mode, 16),
+		/* SMB2_CREATE_TAG_POSIX is "0x93AD25509CB411E7B42383DE968BCD7C" */
+		.Name = {
+			0x93, 0xAD, 0x25, 0x50, 0x9C, 0xB4, 0x11, 0xE7,
+			0xB4, 0x23, 0x83, 0xDE, 0x96, 0x8B, 0xCD, 0x7C
+		},
+		.Mode = cpu_to_le32(mode),
+	};
+	cifs_dbg(FYI, "mode on posix create 0%o\n", mode);
+	cifs_end_extension(smb, sizeof(*buf));
 }
 
-static struct create_durable *
-create_durable_buf(void)
+static void fill_lease_context(struct TCP_Server_Info *server,
+			       struct smb2_create_req *req,
+			       struct smb_message *smb,
+			       u8 *lease_key,
+			       __u8 *oplock,
+			       u8 *parent_lease_key,
+			       __le32 flags)
 {
-	struct create_durable *buf;
-
-	buf = kzalloc(sizeof(struct create_durable), GFP_KERNEL);
-	if (!buf)
-		return NULL;
-
-	buf->ccontext.DataOffset = cpu_to_le16(offsetof
-					(struct create_durable, Data));
-	buf->ccontext.DataLength = cpu_to_le32(16);
-	buf->ccontext.NameOffset = cpu_to_le16(offsetof
-				(struct create_durable, Name));
-	buf->ccontext.NameLength = cpu_to_le16(4);
-	/* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DHnQ" */
-	buf->Name[0] = 'D';
-	buf->Name[1] = 'H';
-	buf->Name[2] = 'n';
-	buf->Name[3] = 'Q';
-	return buf;
+	req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_LEASE;
+	server->ops->fill_lease_buf(smb, lease_key, *oplock,
+				    parent_lease_key, flags);
 }
 
-static struct create_durable *
-create_reconnect_durable_buf(struct cifs_fid *fid)
+static void fill_durable_v1_context(struct smb_message *smb)
 {
-	struct create_durable *buf;
+	struct create_durable *buf = cifs_begin_ccontext(smb);
 
-	buf = kzalloc(sizeof(struct create_durable), GFP_KERNEL);
-	if (!buf)
-		return NULL;
-
-	buf->ccontext.DataOffset = cpu_to_le16(offsetof
-					(struct create_durable, Data));
-	buf->ccontext.DataLength = cpu_to_le32(16);
-	buf->ccontext.NameOffset = cpu_to_le16(offsetof
-				(struct create_durable, Name));
-	buf->ccontext.NameLength = cpu_to_le16(4);
-	buf->Data.Fid.PersistentFileId = fid->persistent_fid;
-	buf->Data.Fid.VolatileFileId = fid->volatile_fid;
-	/* SMB2_CREATE_DURABLE_HANDLE_RECONNECT is "DHnC" */
-	buf->Name[0] = 'D';
-	buf->Name[1] = 'H';
-	buf->Name[2] = 'n';
-	buf->Name[3] = 'C';
-	return buf;
+	*buf = (struct create_durable){
+		.ccontext = CREATE_CONTEXT_HDR(struct create_durable, Name, Data, 4),
+		/* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DHnQ" */
+		.Name = {'D', 'H', 'n', 'Q' },
+	};
+	cifs_end_extension(smb, sizeof(*buf));
 }
 
-static int
-add_lease_context(struct TCP_Server_Info *server,
-		  struct smb2_create_req *req,
-		  struct kvec *iov,
-		  unsigned int *num_iovec,
-		  u8 *lease_key,
-		  __u8 *oplock,
-		  u8 *parent_lease_key,
-		  __le32 flags)
+static void fill_reconnect_durable_context(struct smb_message *smb,
+					   struct cifs_open_parms *oparms)
 {
-	unsigned int num = *num_iovec;
+	struct create_durable *buf = cifs_begin_ccontext(smb);
+	struct cifs_fid *fid = oparms->fid;
 
-	iov[num].iov_base = server->ops->create_lease_buf(lease_key, *oplock,
-							  parent_lease_key, flags);
-	if (iov[num].iov_base == NULL)
-		return -ENOMEM;
-	iov[num].iov_len = server->vals->create_lease_size;
-	req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_LEASE;
-	*num_iovec = num + 1;
-	return 0;
+	/* indicate that we don't need to relock the file */
+	oparms->reconnect = false;
+
+	*buf = (struct create_durable){
+		.ccontext = CREATE_CONTEXT_HDR(struct create_durable, Name, Data, 4),
+		/* SMB2_CREATE_DURABLE_HANDLE_RECONNECT is "DHnC" */
+		.Name = {'D', 'H', 'n', 'C' },
+		.Data.Fid.PersistentFileId	= fid->persistent_fid,
+		.Data.Fid.VolatileFileId	= fid->volatile_fid,
+	};
+	cifs_end_extension(smb, sizeof(*buf));
 }
 
-static struct create_durable_v2 *
-create_durable_v2_buf(struct cifs_open_parms *oparms)
+static void fill_durable_v2_context(struct smb_message *smb,
+				    struct cifs_open_parms *oparms)
 {
-	struct cifs_fid *pfid = oparms->fid;
-	struct create_durable_v2 *buf;
+	struct create_durable_v2 *buf = cifs_begin_ccontext(smb);
+	struct cifs_fid *fid = oparms->fid;
 
-	buf = kzalloc(sizeof(struct create_durable_v2), GFP_KERNEL);
-	if (!buf)
-		return NULL;
+	*buf = (struct create_durable_v2){
+		.ccontext = CREATE_CONTEXT_HDR(struct create_durable_v2, Name, dcontext, 4),
+		/* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DH2Q" */
+		.Name = {'D', 'H', '2', 'Q' },
 
-	buf->ccontext.DataOffset = cpu_to_le16(offsetof
-					(struct create_durable_v2, dcontext));
-	buf->ccontext.DataLength = cpu_to_le32(sizeof(struct durable_context_v2));
-	buf->ccontext.NameOffset = cpu_to_le16(offsetof
-				(struct create_durable_v2, Name));
-	buf->ccontext.NameLength = cpu_to_le16(4);
-
-	/*
-	 * NB: Handle timeout defaults to 0, which allows server to choose
-	 * (most servers default to 120 seconds) and most clients default to 0.
-	 * This can be overridden at mount ("handletimeout=") if the user wants
-	 * a different persistent (or resilient) handle timeout for all opens
-	 * on a particular SMB3 mount.
-	 */
-	buf->dcontext.Timeout = cpu_to_le32(oparms->tcon->handle_timeout);
-	buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT);
+		/*
+		 * NB: Handle timeout defaults to 0, which allows server to
+		 * choose (most servers default to 120 seconds) and most
+		 * clients default to 0.  This can be overridden at mount
+		 * ("handletimeout=") if the user wants a different persistent
+		 * (or resilient) handle timeout for all opens on a particular
+		 * SMB3 mount.
+		 */
+		.dcontext.Timeout = cpu_to_le32(oparms->tcon->handle_timeout),
+		.dcontext.Flags	  = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT),
+	};
 
 	/* for replay, we should not overwrite the existing create guid */
 	if (!oparms->replay) {
 		generate_random_uuid(buf->dcontext.CreateGuid);
-		memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16);
-	} else
-		memcpy(buf->dcontext.CreateGuid, pfid->create_guid, 16);
-
-	/* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DH2Q" */
-	buf->Name[0] = 'D';
-	buf->Name[1] = 'H';
-	buf->Name[2] = '2';
-	buf->Name[3] = 'Q';
-	return buf;
-}
-
-static struct create_durable_handle_reconnect_v2 *
-create_reconnect_durable_v2_buf(struct cifs_fid *fid)
-{
-	struct create_durable_handle_reconnect_v2 *buf;
-
-	buf = kzalloc(sizeof(struct create_durable_handle_reconnect_v2),
-			GFP_KERNEL);
-	if (!buf)
-		return NULL;
-
-	buf->ccontext.DataOffset =
-		cpu_to_le16(offsetof(struct create_durable_handle_reconnect_v2,
-				     dcontext));
-	buf->ccontext.DataLength =
-		cpu_to_le32(sizeof(struct durable_reconnect_context_v2));
-	buf->ccontext.NameOffset =
-		cpu_to_le16(offsetof(struct create_durable_handle_reconnect_v2,
-			    Name));
-	buf->ccontext.NameLength = cpu_to_le16(4);
-
-	buf->dcontext.Fid.PersistentFileId = fid->persistent_fid;
-	buf->dcontext.Fid.VolatileFileId = fid->volatile_fid;
-	buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT);
-	memcpy(buf->dcontext.CreateGuid, fid->create_guid, 16);
-
-	/* SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 is "DH2C" */
-	buf->Name[0] = 'D';
-	buf->Name[1] = 'H';
-	buf->Name[2] = '2';
-	buf->Name[3] = 'C';
-	return buf;
-}
-
-static int
-add_durable_v2_context(struct kvec *iov, unsigned int *num_iovec,
-		    struct cifs_open_parms *oparms)
-{
-	unsigned int num = *num_iovec;
+		memcpy(fid->create_guid, buf->dcontext.CreateGuid, 16);
+	} else {
+		memcpy(buf->dcontext.CreateGuid, fid->create_guid, 16);
+	}
 
-	iov[num].iov_base = create_durable_v2_buf(oparms);
-	if (iov[num].iov_base == NULL)
-		return -ENOMEM;
-	iov[num].iov_len = sizeof(struct create_durable_v2);
-	*num_iovec = num + 1;
-	return 0;
+	cifs_end_extension(smb, sizeof(*buf));
 }
 
-static int
-add_durable_reconnect_v2_context(struct kvec *iov, unsigned int *num_iovec,
-		    struct cifs_open_parms *oparms)
+static void fill_durable_reconnect_v2_context(struct smb_message *smb,
+					      struct cifs_open_parms *oparms)
 {
-	unsigned int num = *num_iovec;
+	struct create_durable_handle_reconnect_v2 *buf = cifs_begin_ccontext(smb);
+	struct cifs_fid *fid = oparms->fid;
 
 	/* indicate that we don't need to relock the file */
 	oparms->reconnect = false;
 
-	iov[num].iov_base = create_reconnect_durable_v2_buf(oparms->fid);
-	if (iov[num].iov_base == NULL)
-		return -ENOMEM;
-	iov[num].iov_len = sizeof(struct create_durable_handle_reconnect_v2);
-	*num_iovec = num + 1;
-	return 0;
+	*buf = (struct create_durable_handle_reconnect_v2){
+		.ccontext = CREATE_CONTEXT_HDR(struct create_durable_handle_reconnect_v2,
+					       Name, dcontext, 4),
+		/* SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 is "DH2C" */
+		.Name = {'D', 'H', '2', 'C' },
+		.dcontext.Fid.PersistentFileId	= fid->persistent_fid,
+		.dcontext.Fid.VolatileFileId	= fid->volatile_fid,
+		.dcontext.Flags			= cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT),
+	};
+
+	memcpy(buf->dcontext.CreateGuid, fid->create_guid, 16);
+	cifs_end_extension(smb, sizeof(*buf));
 }
 
-static int
-add_durable_context(struct kvec *iov, unsigned int *num_iovec,
-		    struct cifs_open_parms *oparms, bool use_persistent)
+static void
+fill_durable_context(struct smb_message *smb,
+		     struct cifs_open_parms *oparms, bool use_persistent)
 {
-	unsigned int num = *num_iovec;
-
 	if (use_persistent) {
 		if (oparms->reconnect)
-			return add_durable_reconnect_v2_context(iov, num_iovec,
-								oparms);
-		else
-			return add_durable_v2_context(iov, num_iovec, oparms);
+			return fill_durable_reconnect_v2_context(smb, oparms);
+		return fill_durable_v2_context(smb, oparms);
 	}
 
-	if (oparms->reconnect) {
-		iov[num].iov_base = create_reconnect_durable_buf(oparms->fid);
-		/* indicate that we don't need to relock the file */
-		oparms->reconnect = false;
-	} else
-		iov[num].iov_base = create_durable_buf();
-	if (iov[num].iov_base == NULL)
-		return -ENOMEM;
-	iov[num].iov_len = sizeof(struct create_durable);
-	*num_iovec = num + 1;
-	return 0;
+	if (oparms->reconnect)
+		return fill_reconnect_durable_context(smb, oparms);
+	return fill_durable_v1_context(smb);
 }
 
 /* See MS-SMB2 2.2.13.2.7 */
-static struct crt_twarp_ctxt *
-create_twarp_buf(__u64 timewarp)
+static void fill_twarp_context(struct smb_message *smb, __u64 timewarp)
 {
-	struct crt_twarp_ctxt *buf;
-
-	buf = kzalloc(sizeof(struct crt_twarp_ctxt), GFP_KERNEL);
-	if (!buf)
-		return NULL;
-
-	buf->ccontext.DataOffset = cpu_to_le16(offsetof
-					(struct crt_twarp_ctxt, Timestamp));
-	buf->ccontext.DataLength = cpu_to_le32(8);
-	buf->ccontext.NameOffset = cpu_to_le16(offsetof
-				(struct crt_twarp_ctxt, Name));
-	buf->ccontext.NameLength = cpu_to_le16(4);
-	/* SMB2_CREATE_TIMEWARP_TOKEN is "TWrp" */
-	buf->Name[0] = 'T';
-	buf->Name[1] = 'W';
-	buf->Name[2] = 'r';
-	buf->Name[3] = 'p';
-	buf->Timestamp = cpu_to_le64(timewarp);
-	return buf;
-}
+	struct crt_twarp_ctxt *buf = cifs_begin_ccontext(smb);
 
-/* See MS-SMB2 2.2.13.2.7 */
-static int
-add_twarp_context(struct kvec *iov, unsigned int *num_iovec, __u64 timewarp)
-{
-	unsigned int num = *num_iovec;
+	*buf = (struct crt_twarp_ctxt){
+		.ccontext = CREATE_CONTEXT_HDR(struct crt_twarp_ctxt, Name, Timestamp, 4),
+		/* SMB2_CREATE_TIMEWARP_TOKEN is "TWrp" */
+		.Name		= {'T', 'W', 'r', 'p' },
+		.Timestamp	= cpu_to_le64(timewarp),
+	};
 
-	iov[num].iov_base = create_twarp_buf(timewarp);
-	if (iov[num].iov_base == NULL)
-		return -ENOMEM;
-	iov[num].iov_len = sizeof(struct crt_twarp_ctxt);
-	*num_iovec = num + 1;
-	return 0;
+	cifs_end_extension(smb, sizeof(*buf));
 }
 
 /* See http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx */
@@ -2706,26 +2587,21 @@ static void setup_owner_group_sids(char *buf)
 }
 
 /* See MS-SMB2 2.2.13.2.2 and MS-DTYP 2.4.6 */
-static struct crt_sd_ctxt *
-create_sd_buf(umode_t mode, bool set_owner, unsigned int *len)
+static void fill_sd_context(struct smb_message *smb, umode_t mode, bool set_owner)
 {
-	struct crt_sd_ctxt *buf;
+	struct crt_sd_ctxt *buf = cifs_begin_extension(smb);
 	__u8 *ptr, *aclptr;
 	unsigned int acelen, acl_size, ace_count;
 	unsigned int owner_offset = 0;
 	unsigned int group_offset = 0;
+	unsigned int len;
 	struct smb3_acl acl = {};
 
-	*len = ALIGN8(sizeof(struct crt_sd_ctxt) + (sizeof(struct smb_ace) * 4));
+	len = ALIGN8(sizeof(struct crt_sd_ctxt) + (sizeof(struct smb_ace) * 4));
 
-	if (set_owner) {
+	if (set_owner)
 		/* sizeof(struct owner_group_sids) is already multiple of 8 so no need to round */
-		*len += sizeof(struct owner_group_sids);
-	}
-
-	buf = kzalloc(*len, GFP_KERNEL);
-	if (buf == NULL)
-		return buf;
+		len += sizeof(struct owner_group_sids);
 
 	ptr = (__u8 *)&buf[1];
 	if (set_owner) {
@@ -2791,33 +2667,15 @@ create_sd_buf(umode_t mode, bool set_owner, unsigned int *len)
 	memcpy(aclptr, &acl, sizeof(struct smb3_acl));
 
 	buf->ccontext.DataLength = cpu_to_le32(ptr - (__u8 *)&buf->sd);
-	*len = ALIGN8((unsigned int)(ptr - (__u8 *)buf));
-
-	return buf;
-}
-
-static int
-add_sd_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode, bool set_owner)
-{
-	unsigned int num = *num_iovec;
-	unsigned int len = 0;
-
-	iov[num].iov_base = create_sd_buf(mode, set_owner, &len);
-	if (iov[num].iov_base == NULL)
-		return -ENOMEM;
-	iov[num].iov_len = len;
-	*num_iovec = num + 1;
-	return 0;
+	len = ALIGN8((unsigned int)(ptr - (__u8 *)buf));
+	cifs_end_extension(smb, len);
+	cifs_pad_to_8(smb);
 }
 
-static struct crt_query_id_ctxt *
-create_query_id_buf(void)
+/* See MS-SMB2 2.2.13.2.9 */
+static void fill_query_id_context(struct smb_message *smb)
 {
-	struct crt_query_id_ctxt *buf;
-
-	buf = kzalloc(sizeof(struct crt_query_id_ctxt), GFP_KERNEL);
-	if (!buf)
-		return NULL;
+	struct crt_query_id_ctxt *buf = cifs_begin_extension(smb);
 
 	buf->ccontext.DataOffset = cpu_to_le16(0);
 	buf->ccontext.DataLength = cpu_to_le32(0);
@@ -2829,78 +2687,19 @@ create_query_id_buf(void)
 	buf->Name[1] = 'F';
 	buf->Name[2] = 'i';
 	buf->Name[3] = 'd';
-	return buf;
-}
-
-/* See MS-SMB2 2.2.13.2.9 */
-static int
-add_query_id_context(struct kvec *iov, unsigned int *num_iovec)
-{
-	unsigned int num = *num_iovec;
-
-	iov[num].iov_base = create_query_id_buf();
-	if (iov[num].iov_base == NULL)
-		return -ENOMEM;
-	iov[num].iov_len = sizeof(struct crt_query_id_ctxt);
-	*num_iovec = num + 1;
-	return 0;
+	cifs_end_extension(smb, sizeof(*buf));
 }
 
-static void add_ea_context(struct cifs_open_parms *oparms,
-			   struct kvec *rq_iov, unsigned int *num_iovs)
+static void fill_ea_context(struct smb_message *smb, const struct cifs_open_parms *oparms)
 {
-	struct kvec *iov = oparms->ea_cctx;
+	const struct kvec *iov = oparms->ea_cctx;
 
 	if (iov && iov->iov_base && iov->iov_len) {
-		rq_iov[(*num_iovs)++] = *iov;
-		memset(iov, 0, sizeof(*iov));
-	}
-}
-
-static int
-alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len,
-			    const char *treename, const __le16 *path)
-{
-	int treename_len, path_len;
-	struct nls_table *cp;
-	const __le16 sep[] = {cpu_to_le16('\\'), cpu_to_le16(0x0000)};
+		void *p = cifs_begin_extension(smb);
 
-	/*
-	 * skip leading "\\"
-	 */
-	treename_len = strlen(treename);
-	if (treename_len < 2 || !(treename[0] == '\\' && treename[1] == '\\'))
-		return -EINVAL;
-
-	treename += 2;
-	treename_len -= 2;
-
-	path_len = UniStrnlen((wchar_t *)path, PATH_MAX);
-
-	/* make room for one path separator only if @path isn't empty */
-	*out_len = treename_len + (path[0] ? 1 : 0) + path_len;
-
-	/*
-	 * final path needs to be 8-byte aligned as specified in
-	 * MS-SMB2 2.2.13 SMB2 CREATE Request.
-	 */
-	*out_size = ALIGN8(*out_len * sizeof(__le16));
-	*out_path = kzalloc(*out_size + sizeof(__le16) /* null */, GFP_KERNEL);
-	if (!*out_path)
-		return -ENOMEM;
-
-	cp = load_nls_default();
-	cifs_strtoUTF16(*out_path, treename, treename_len, cp);
-
-	/* Do not append the separator if the path is empty */
-	if (path[0] != cpu_to_le16(0x0000)) {
-		UniStrcat((wchar_t *)*out_path, (wchar_t *)sep);
-		UniStrcat((wchar_t *)*out_path, (wchar_t *)path);
+		memcpy(p, iov->iov_base, iov->iov_len);
+		cifs_end_extension(smb, iov->iov_len);
 	}
-
-	unload_nls(cp);
-
-	return 0;
 }
 
 struct smb2_create_layout {
@@ -2912,7 +2711,6 @@ struct smb2_create_layout {
 	u16		name_offset;	/* Offset in message of name */
 	u16		contexts_offset; /* Offset in message contexts */
 	u16		contexts_len;	/* Length of contexts (or 0) */
-	u16		posix_offset;	/* Offset in message of posix context */
 	u8		name_pad;	/* Amount of name padding needed */
 };
 
@@ -2920,8 +2718,6 @@ static int smb311_posix_mkdir_layout(struct cifs_tcon *tcon,
 				     struct smb2_create_layout *lay)
 {
 	size_t offset = lay->offset;
-	size_t tmp;
-	bool has_contexts = false;
 
 	/* [MS-SMB2] 2.2.13 NameOffset: If SMB2_FLAGS_DFS_OPERATIONS
 	 * is set in the Flags field of the SMB2 header, the file name
@@ -2950,22 +2746,17 @@ static int smb311_posix_mkdir_layout(struct cifs_tcon *tcon,
 	}
 
 	offset += lay->name_len;
-	tmp = offset;
-	offset = ALIGN8(offset);
-	lay->name_pad = offset - tmp;
+	offset = ALIGN(offset, 8);
 	lay->contexts_offset = offset;
 
-	if (tcon->posix_extensions) {
+	if (tcon->posix_extensions)
 		/* resource #3: posix buf */
 		offset += sizeof(struct create_posix);
-		has_contexts = true;
-	}
 
-	if (has_contexts)
-		lay->contexts_len = offset - lay->contexts_offset;
+	if (offset == lay->contexts_offset)
+		lay->contexts_offset = 0; /* None */
 	else
-		lay->contexts_offset = 0;
-
+		lay->contexts_len = offset - lay->contexts_offset;
 	lay->offset = offset;
 	return 0;
 }
@@ -3065,13 +2856,12 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
 		memcpy(name, utf16_path, layout.path_len);
 	}
 
-	if (layout.name_pad)
-		memset(smb->request + layout.name_offset + layout.name_len,
-		       0, layout.name_pad);
+	smb->offset = layout.name_offset + layout.name_len;
+	cifs_pad_to_8(smb);
 
 	if (tcon->posix_extensions)
 		/* resource #3: posix buf */
-		fill_posix_buf(smb->request + layout.posix_offset, mode);
+		fill_posix_context(smb, mode);
 
 	/* no need to inc num_remote_opens because we close it just below */
 	trace_smb3_posix_mkdir_enter(xid, tcon->tid, ses->Suid, full_path, CREATE_NOT_FILE,
@@ -3119,81 +2909,185 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
 	return rc;
 }
 
-int
-SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
-	       struct smb_rqst *rqst, __u8 *oplock,
-	       struct cifs_open_parms *oparms, __le16 *path)
+/*
+ * Calculate the request size and layout for an "open" (i.e. Create) request.
+ */
+static int smb2_lay_out_open(const struct cifs_tcon *tcon,
+			     const struct TCP_Server_Info *server,
+			     __u8 oplock,
+			     const struct cifs_open_parms *oparms,
+			     struct smb2_create_layout *lay)
+{
+	size_t offset = lay->offset, csize, tmp;
+
+	/* [MS-SMB2] 2.2.13 NameOffset: If SMB2_FLAGS_DFS_OPERATIONS
+	 * is set in the Flags field of the SMB2 header, the file name
+	 * includes a prefix that will be processed during DFS name
+	 * normalization as specified in section 3.3.5.9. Otherwise,
+	 * the file name is relative to the share that is identified
+	 * by the TreeId in the SMB2 header.
+	 */
+	lay->name_offset = offset;
+	if (tcon->share_flags & SHI1005_FLAGS_DFS) {
+		const char *treename = tcon->tree_name;
+		int treename_len;
+
+		/* skip leading "\\" */
+		if (!(treename[0] == '\\' && treename[1] == '\\'))
+			return -EINVAL;
+
+		treename_len = cifs_size_strtoUTF16(treename + 2, INT_MAX, lay->cp);
+
+		lay->treename_len = treename_len;
+		lay->name_len = treename_len;
+		if (lay->path_len)
+			lay->name_len += 2 + lay->path_len;
+	} else {
+		lay->name_len = lay->path_len;
+	}
+
+	offset += lay->name_len;
+	tmp = offset;
+	offset = round_up(offset, 8);
+	lay->name_pad = offset - tmp;
+	lay->contexts_offset = offset;
+
+	/* TODO: This bit of code is very suspicious. */
+	if (!(server->capabilities & SMB2_GLOBAL_CAP_LEASING) ||
+	    oplock == SMB2_OPLOCK_LEVEL_NONE)
+		;
+	else if (!(server->capabilities & SMB2_GLOBAL_CAP_DIRECTORY_LEASING) &&
+		 (oparms->create_options & CREATE_NOT_FILE))
+		; /* no srv lease support */
+	else
+		offset = ALIGN(offset, 8) + server->vals->create_lease_size;
+
+	if (oplock == SMB2_OPLOCK_LEVEL_BATCH) {
+		if (!tcon->use_persistent)
+			csize = sizeof(struct create_durable);
+		else if (oparms->reconnect)
+			csize = sizeof(struct create_durable_handle_reconnect_v2);
+		else
+			csize = sizeof(struct create_durable_v2);
+		offset = ALIGN(offset, 8) + csize;
+	}
+
+	if (tcon->posix_extensions)
+		offset = ALIGN(offset, 8) + sizeof(struct create_posix);
+	if (tcon->snapshot_time)
+		offset = ALIGN(offset, 8) + sizeof(struct crt_twarp_ctxt);
+
+	if (oparms->disposition != FILE_OPEN && oparms->cifs_sb) {
+		bool set_mode;
+		bool set_owner;
+
+		set_mode = (oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) &&
+			(oparms->mode != ACL_NO_MODE);
+
+		set_owner = oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL;
+
+		if (set_owner || set_mode) {
+			csize = sizeof(struct crt_sd_ctxt) + sizeof(struct smb_ace) * 4;
+			csize = round_up(csize, 8);
+
+			if (set_owner) {
+				/* sizeof(struct owner_group_sids) is already
+				 * multiple of 8 so no need to round */
+				csize += sizeof(struct owner_group_sids);
+			}
+		}
+		offset = ALIGN(offset, 8) + csize;
+	}
+
+	offset = ALIGN(offset, 8) + sizeof(struct crt_query_id_ctxt);
+
+	/* TODO: Pass down the desired EA list and render directly into the buffer. */
+	if (oparms->ea_cctx->iov_base && oparms->ea_cctx->iov_len)
+		offset = ALIGN(offset, 8) + oparms->ea_cctx->iov_len;
+
+	if (tcon->posix_extensions)
+		offset = ALIGN(offset, 8) + sizeof(struct create_posix);
+
+	lay->contexts_len = offset - lay->contexts_offset;
+	lay->offset = offset;
+	return 0;
+}
+
+struct smb_message *SMB2_open_init(struct cifs_tcon *tcon,
+				   struct TCP_Server_Info *server, __u8 *oplock,
+				   struct cifs_open_parms *oparms, __le16 *path)
 {
 	struct smb2_create_req *req;
-	unsigned int n_iov = 2;
+	struct smb_message *smb;
 	__u32 file_attributes = 0;
-	int copy_size;
-	int uni_path_len;
-	unsigned int total_len;
-	struct kvec *iov = rqst->rq_iov;
-	__le16 *copy_path;
 	int rc;
 
-	rc = smb2_plain_req_init(SMB2_CREATE, tcon, server,
-				 (void **) &req, &total_len);
-	if (rc)
-		return rc;
+	if (!server->oplocks || tcon->no_lease)
+		*oplock = SMB2_OPLOCK_LEVEL_NONE;
 
-	iov[0].iov_base = (char *)req;
-	/* -1 since last byte is buf[0] which is sent below (path) */
-	iov[0].iov_len = total_len - 1;
+	struct smb2_create_layout layout = {
+		.cp		= oparms->cifs_sb->local_nls,
+		.offset		= sizeof(struct smb2_create_req),
+		.path_len	= UniStrnlen((wchar_t *)path, PATH_MAX) * 2,
+	};
+
+	rc = smb2_lay_out_open(tcon, server, *oplock, oparms, &layout);
+	if (rc < 0)
+		return ERR_PTR(rc);
+
+	smb = smb2_create_request(SMB2_CREATE, server, tcon,
+				  sizeof(*req), layout.offset, 0,
+				  SMB2_REQ_DYNAMIC);
+	if (!smb)
+		return ERR_PTR(-ENOMEM);
 
 	if (oparms->create_options & CREATE_OPTION_READONLY)
 		file_attributes |= ATTR_READONLY;
 	if (oparms->create_options & CREATE_OPTION_SPECIAL)
 		file_attributes |= ATTR_SYSTEM;
 
-	req->ImpersonationLevel = IL_IMPERSONATION;
-	req->DesiredAccess = cpu_to_le32(oparms->desired_access);
+	req->ImpersonationLevel	= IL_IMPERSONATION;
+	req->DesiredAccess	= cpu_to_le32(oparms->desired_access);
 	/* File attributes ignored on open (used in create though) */
-	req->FileAttributes = cpu_to_le32(file_attributes);
-	req->ShareAccess = FILE_SHARE_ALL_LE;
-
-	req->CreateDisposition = cpu_to_le32(oparms->disposition);
-	req->CreateOptions = cpu_to_le32(oparms->create_options & CREATE_OPTIONS_MASK);
-	req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req));
+	req->FileAttributes	= cpu_to_le32(file_attributes);
+	req->ShareAccess	= FILE_SHARE_ALL_LE;
+	req->CreateDisposition	= cpu_to_le32(oparms->disposition);
+	req->CreateOptions	= cpu_to_le32(oparms->create_options & CREATE_OPTIONS_MASK);
+	req->NameOffset		= cpu_to_le16(layout.name_offset);
+	req->NameLength		= cpu_to_le16(layout.name_len);
+	req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
+	req->CreateContextsOffset = cpu_to_le32(layout.contexts_offset);
+	req->CreateContextsLength = cpu_to_le32(layout.contexts_len);
 
 	/* [MS-SMB2] 2.2.13 NameOffset:
-	 * If SMB2_FLAGS_DFS_OPERATIONS is set in the Flags field of
-	 * the SMB2 header, the file name includes a prefix that will
-	 * be processed during DFS name normalization as specified in
-	 * section 3.3.5.9. Otherwise, the file name is relative to
-	 * the share that is identified by the TreeId in the SMB2
-	 * header.
+	 * If SMB2_FLAGS_DFS_OPERATIONS is set in the Flags field of the SMB2
+	 * header, the file name includes a prefix that will be processed
+	 * during DFS name normalization as specified in section
+	 * 3.3.5.9. Otherwise, the file name is relative to the share that is
+	 * identified by the TreeId in the SMB2 header.
 	 */
+	__le16 *name = smb->request + layout.name_offset;
+
 	if (tcon->share_flags & SHI1005_FLAGS_DFS) {
-		int name_len;
+		int tmp;
 
 		req->hdr.Flags |= SMB2_FLAGS_DFS_OPERATIONS;
-		rc = alloc_path_with_tree_prefix(&copy_path, &copy_size,
-						 &name_len,
-						 tcon->tree_name, path);
-		if (rc)
-			return rc;
-		req->NameLength = cpu_to_le16(name_len * 2);
-		uni_path_len = copy_size;
-		path = copy_path;
-	} else {
-		uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2;
-		/* MUST set path len (NameLength) to 0 opening root of share */
-		req->NameLength = cpu_to_le16(uni_path_len - 2);
-		copy_size = ALIGN8(uni_path_len);
-		copy_path = kzalloc(copy_size, GFP_KERNEL);
-		if (!copy_path)
-			return -ENOMEM;
-		memcpy((char *)copy_path, (const char *)path,
-		       uni_path_len);
-		uni_path_len = copy_size;
-		path = copy_path;
+
+		tmp = cifs_strtoUTF16(name, tcon->tree_name + 2, INT_MAX,
+				      layout.cp);
+		WARN_ON(tmp != layout.treename_len);
+		name += tmp;
+		if (layout.path_len) {
+			*name++ = cpu_to_le16('\\');
+			memcpy(name, path, layout.path_len);
+		}
+	} else if (layout.path_len) {
+		memcpy(name, path, layout.path_len);
 	}
 
-	iov[1].iov_len = uni_path_len;
-	iov[1].iov_base = path;
+	smb->offset = layout.name_offset + layout.name_len;
+	cifs_pad_to_8(smb);
+	WARN_ON_ONCE(smb->offset != layout.contexts_offset);
 
 	if ((!server->oplocks) || (tcon->no_lease))
 		*oplock = SMB2_OPLOCK_LEVEL_NONE;
@@ -3205,32 +3099,21 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
 		  (oparms->create_options & CREATE_NOT_FILE))
 		req->RequestedOplockLevel = *oplock; /* no srv lease support */
 	else {
-		rc = add_lease_context(server, req, iov, &n_iov,
-				       oparms->fid->lease_key, oplock,
-				       oparms->fid->parent_lease_key,
-				       oparms->lease_flags);
-		if (rc)
-			return rc;
+		fill_lease_context(server, req, smb,
+				   oparms->fid->lease_key, oplock,
+				   oparms->fid->parent_lease_key,
+				   oparms->lease_flags);
 	}
 
-	if (*oplock == SMB2_OPLOCK_LEVEL_BATCH) {
-		rc = add_durable_context(iov, &n_iov, oparms,
-					tcon->use_persistent);
-		if (rc)
-			return rc;
-	}
+	if (*oplock == SMB2_OPLOCK_LEVEL_BATCH)
+		fill_durable_context(smb, oparms, tcon->use_persistent);
 
-	if (tcon->posix_extensions) {
-		rc = add_posix_context(iov, &n_iov, oparms->mode);
-		if (rc)
-			return rc;
-	}
+	if (tcon->posix_extensions)
+		fill_posix_context(smb, oparms->mode);
 
 	if (tcon->snapshot_time) {
 		cifs_dbg(FYI, "adding snapshot context\n");
-		rc = add_twarp_context(iov, &n_iov, tcon->snapshot_time);
-		if (rc)
-			return rc;
+		fill_twarp_context(smb, tcon->snapshot_time);
 	}
 
 	if ((oparms->disposition != FILE_OPEN) && (oparms->cifs_sb)) {
@@ -3252,40 +3135,13 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
 
 		if (set_owner | set_mode) {
 			cifs_dbg(FYI, "add sd with mode 0x%x\n", oparms->mode);
-			rc = add_sd_context(iov, &n_iov, oparms->mode, set_owner);
-			if (rc)
-				return rc;
+			fill_sd_context(smb, oparms->mode, set_owner);
 		}
 	}
 
-	add_query_id_context(iov, &n_iov);
-	add_ea_context(oparms, iov, &n_iov);
-
-	if (n_iov > 2) {
-		/*
-		 * We have create contexts behind iov[1] (the file
-		 * name), point at them from the main create request
-		 */
-		req->CreateContextsOffset = cpu_to_le32(
-			sizeof(struct smb2_create_req) +
-			iov[1].iov_len);
-		req->CreateContextsLength = 0;
-
-		for (unsigned int i = 2; i < (n_iov-1); i++) {
-			struct kvec *v = &iov[i];
-			size_t len = v->iov_len;
-			struct create_context *cctx =
-				(struct create_context *)v->iov_base;
-
-			cctx->Next = cpu_to_le32(len);
-			le32_add_cpu(&req->CreateContextsLength, len);
-		}
-		le32_add_cpu(&req->CreateContextsLength,
-			     iov[n_iov-1].iov_len);
-	}
-
-	rqst->rq_nvec = n_iov;
-	return 0;
+	fill_query_id_context(smb);
+	fill_ea_context(smb, oparms);
+	return smb;
 }
 
 static void
@@ -3333,14 +3189,14 @@ parse_posix_ctxt(struct create_context *cc, struct smb2_file_all_info *info,
 		 posix->nlink, posix->mode, posix->reparse_tag);
 }
 
-int smb2_parse_contexts(struct TCP_Server_Info *server,
-			struct kvec *rsp_iov,
-			__u16 *epoch,
-			char *lease_key, __u8 *oplock,
-			struct smb2_file_all_info *buf,
-			struct create_posix_rsp *posix)
+int smb2_parse_create_response(struct TCP_Server_Info *server,
+			       struct smb_message *smb,
+			       __u16 *epoch,
+			       char *lease_key, __u8 *oplock,
+			       struct smb2_file_all_info *buf,
+			       struct create_posix_rsp *posix)
 {
-	struct smb2_create_rsp *rsp = rsp_iov->iov_base;
+	struct smb2_create_rsp *rsp = smb->response;
 	struct create_context *cc;
 	size_t rem, off, len;
 	size_t doff, dlen;
@@ -3356,7 +3212,7 @@ int smb2_parse_contexts(struct TCP_Server_Info *server,
 
 	off = le32_to_cpu(rsp->CreateContextsOffset);
 	rem = le32_to_cpu(rsp->CreateContextsLength);
-	if (check_add_overflow(off, rem, &len) || len > rsp_iov->iov_len)
+	if (check_add_overflow(off, rem, &len) || len > smb->response_len)
 		return -EINVAL;
 	cc = (struct create_context *)((u8 *)rsp + off);
 
@@ -3412,39 +3268,18 @@ int smb2_parse_contexts(struct TCP_Server_Info *server,
 	return 0;
 }
 
-/* rq_iov[0] is the request and is released by cifs_small_buf_release().
- * All other vectors are freed by kfree().
- */
-void
-SMB2_open_free(struct smb_rqst *rqst)
-{
-	int i;
-
-	if (rqst && rqst->rq_iov) {
-		cifs_small_buf_release(rqst->rq_iov[0].iov_base);
-		for (i = 1; i < rqst->rq_nvec; i++)
-			if (rqst->rq_iov[i].iov_base != smb2_padding)
-				kfree(rqst->rq_iov[i].iov_base);
-	}
-}
-
-int
-SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
-	  __u8 *oplock, struct smb2_file_all_info *buf,
-	  struct create_posix_rsp *posix,
-	  struct kvec *err_iov, int *buftype)
+int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
+	      __u8 *oplock, struct smb2_file_all_info *buf,
+	      struct create_posix_rsp *posix, struct kvec *err_iov)
 {
-	struct smb_rqst rqst;
+	struct TCP_Server_Info *server;
 	struct smb2_create_rsp *rsp = NULL;
+	struct smb_message *smb;
 	struct cifs_tcon *tcon = oparms->tcon;
 	struct cifs_ses *ses = tcon->ses;
-	struct TCP_Server_Info *server;
-	struct kvec iov[SMB2_CREATE_IOV_SIZE];
-	struct kvec rsp_iov = {NULL, 0};
-	int resp_buftype = CIFS_NO_BUFFER;
-	int rc = 0;
-	int flags = 0;
 	int retries = 0, cur_sleep = 1;
+	int flags = 0;
+	int rc = 0;
 
 replay_again:
 	/* reinitialize for possible replay */
@@ -3459,34 +3294,27 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
 	if (smb3_encryption_required(tcon))
 		flags |= CIFS_TRANSFORM_REQ;
 
-	memset(&rqst, 0, sizeof(struct smb_rqst));
-	memset(&iov, 0, sizeof(iov));
-	rqst.rq_iov = iov;
-	rqst.rq_nvec = SMB2_CREATE_IOV_SIZE;
-
-	rc = SMB2_open_init(tcon, server,
-			    &rqst, oplock, oparms, path);
-	if (rc)
+	smb = SMB2_open_init(tcon, server, oplock, oparms, path);
+	if (IS_ERR(smb)) {
+		rc = PTR_ERR(smb);
+		smb = NULL;
 		goto creat_exit;
+	}
 
 	trace_smb3_open_enter(xid, tcon->tid, tcon->ses->Suid, oparms->path,
 		oparms->create_options, oparms->desired_access);
 
 	if (retries)
-		smb2_set_replay(server, &rqst);
+		smb2_set_replay_smb(server, smb);
 
-	rc = cifs_send_recv(xid, ses, server,
-			    &rqst, &resp_buftype, flags,
-			    &rsp_iov);
-	rsp = (struct smb2_create_rsp *)rsp_iov.iov_base;
+	rc = smb_send_recv_messages(xid, ses, server, smb, flags);
+	rsp = (struct smb2_create_rsp *)smb->response;
 
 	if (rc != 0) {
 		cifs_stats_fail_inc(tcon, SMB2_CREATE);
 		if (err_iov && rsp) {
-			*err_iov = rsp_iov;
-			*buftype = resp_buftype;
-			resp_buftype = CIFS_NO_BUFFER;
-			rsp = NULL;
+			err_iov->iov_base = smb->response;
+			err_iov->iov_len  = smb->response_len;
 		}
 		trace_smb3_open_err(xid, tcon->tid, ses->Suid,
 				    oparms->create_options, oparms->desired_access, rc);
@@ -3496,10 +3324,11 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
 			tcon->need_reconnect = true;
 		}
 		goto creat_exit;
-	} else if (rsp == NULL) /* unlikely to happen, but safer to check */
+	}
+	if (!rsp) /* unlikely to happen, but safer to check */
 		goto creat_exit;
-	else
-		trace_smb3_open_done(xid, rsp->PersistentFileId, tcon->tid, ses->Suid,
+
+	trace_smb3_open_done(xid, rsp->PersistentFileId, tcon->tid, ses->Suid,
 				     oparms->create_options, oparms->desired_access);
 
 	atomic_inc(&tcon->num_remote_opens);
@@ -3523,12 +3352,10 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
 	}
 
 
-	rc = smb2_parse_contexts(server, &rsp_iov, &oparms->fid->epoch,
-				 oparms->fid->lease_key, oplock, buf, posix);
+	rc = smb2_parse_create_response(server, smb, &oparms->fid->epoch,
+					oparms->fid->lease_key, oplock, buf, posix);
 creat_exit:
-	SMB2_open_free(&rqst);
-	free_rsp_buf(resp_buftype, rsp);
-
+	smb_put_messages(smb);
 	if (is_replayable_error(rc) &&
 	    smb2_should_replay(tcon, &retries, &cur_sleep))
 		goto replay_again;
diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h
index 22284a52f300..f854093dd92c 100644
--- a/fs/smb/client/smb2proto.h
+++ b/fs/smb/client/smb2proto.h
@@ -151,17 +151,12 @@ extern int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses,
 		     const char *tree, struct cifs_tcon *tcon,
 		     const struct nls_table *);
 extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon);
-extern int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms,
-		     __le16 *path, __u8 *oplock,
-		     struct smb2_file_all_info *buf,
-		     struct create_posix_rsp *posix,
-		     struct kvec *err_iov, int *resp_buftype);
-extern int SMB2_open_init(struct cifs_tcon *tcon,
-			  struct TCP_Server_Info *server,
-			  struct smb_rqst *rqst,
-			  __u8 *oplock, struct cifs_open_parms *oparms,
-			  __le16 *path);
-extern void SMB2_open_free(struct smb_rqst *rqst);
+int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
+	      __u8 *oplock, struct smb2_file_all_info *buf,
+	      struct create_posix_rsp *posix, struct kvec *err_iov);
+struct smb_message *SMB2_open_init(struct cifs_tcon *tcon,
+				   struct TCP_Server_Info *server, __u8 *oplock,
+				   struct cifs_open_parms *oparms, __le16 *path);
 extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon,
 		     u64 persistent_fid, u64 volatile_fid, u32 opcode,
 		     char *in_data, u32 indatalen, u32 maxoutlen,
@@ -276,12 +271,12 @@ extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *);
 
 extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
 					enum securityEnum);
-int smb2_parse_contexts(struct TCP_Server_Info *server,
-			struct kvec *rsp_iov,
-			__u16 *epoch,
-			char *lease_key, __u8 *oplock,
-			struct smb2_file_all_info *buf,
-			struct create_posix_rsp *posix);
+int smb2_parse_create_response(struct TCP_Server_Info *server,
+			       struct smb_message *smb,
+			       __u16 *epoch,
+			       char *lease_key, __u8 *oplock,
+			       struct smb2_file_all_info *buf,
+			       struct create_posix_rsp *posix);
 
 extern int smb3_encryption_required(const struct cifs_tcon *tcon);
 extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length,


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (30 preceding siblings ...)
  2025-08-06 20:36 ` [RFC PATCH 31/31] cifs: Convert SMB2 Open request David Howells
@ 2025-08-07  5:23 ` Stefan Metzmacher
  2025-08-07  6:24 ` David Howells
                   ` (2 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Stefan Metzmacher @ 2025-08-07  5:23 UTC (permalink / raw)
  To: David Howells, Steve French
  Cc: Paulo Alcantara, Shyam Prasad N, Tom Talpey, Wang Zhaolong,
	Mina Almasry, linux-cifs, linux-kernel

Hi David,

> The aim is to build up a list of fragments for each request using a bvecq.
> These form a segmented list and can be spliced together when assembling a
> compound request.  The segmented list can then be passed to sendmsg() with
> MSG_SPLICE_PAGES in a single call, thereby only having a single loop (in
> the TCP stack) to shovel data, not loops-over-loops.  Possibly we can
> dispense with corking also, provided we can tell TCP to flush the record
> boundaries.  (Note that this also simplifies smbd_send() for RDMA).

I didn't look at the patches in detail, but I like the simplifications
for the transport layer and that hopefully allows me to
move smbd_send() behind sendmsg() with MSG_SPLICE_PAGES in the end.

So the current situation is that we memcpy (at least) in sendmsg()
and with your patches we do a memcpy higher in the stack, but then
use MSG_SPLICE_PAGES in order to do it twice. Is that correct?

Thanks!
metze

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC PATCH 16/31] cifs: Rewrite base TCP transmission
  2025-08-06 20:36 ` [RFC PATCH 16/31] cifs: Rewrite base TCP transmission David Howells
@ 2025-08-07  5:40   ` Stefan Metzmacher
  2025-08-07 10:12   ` David Howells
  2025-08-07 10:14   ` David Howells
  2 siblings, 0 replies; 48+ messages in thread
From: Stefan Metzmacher @ 2025-08-07  5:40 UTC (permalink / raw)
  To: David Howells, Steve French
  Cc: Paulo Alcantara, Shyam Prasad N, Tom Talpey, Wang Zhaolong,
	Mina Almasry, linux-cifs, linux-kernel, netfs, linux-fsdevel

Am 06.08.25 um 22:36 schrieb David Howells:
> +int smb_sendmsg(struct TCP_Server_Info *server, struct msghdr *smb_msg,
> + size_t *sent)
> +{
> + int rc = 0;
> + int retries = 0;
> + struct socket *ssocket = server->ssocket;
> +
> + *sent = 0;
> +
> + if (server->noblocksnd)
> + smb_msg->msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
> + else
> + smb_msg->msg_flags = MSG_NOSIGNAL;
> + smb_msg->msg_flags = MSG_SPLICE_PAGES;
> +

I guess you want '|=' instead of '=' in all 3 lines?

I also think msghdr should be setup in the caller completely
or it should be a local variable in smb_sendmsg() and the caller
only passes struct iov_iter.

metze

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (31 preceding siblings ...)
  2025-08-07  5:23 ` [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator Stefan Metzmacher
@ 2025-08-07  6:24 ` David Howells
  2025-08-07  6:54   ` Stefan Metzmacher
  2025-08-07  7:12   ` David Howells
  2025-08-08 14:15 ` Enzo Matsumiya
  2025-08-08 17:25 ` David Howells
  34 siblings, 2 replies; 48+ messages in thread
From: David Howells @ 2025-08-07  6:24 UTC (permalink / raw)
  To: Stefan Metzmacher
  Cc: dhowells, Steve French, Paulo Alcantara, Shyam Prasad N,
	Tom Talpey, Wang Zhaolong, Mina Almasry, linux-cifs, linux-kernel

Stefan Metzmacher <metze@samba.org> wrote:

> So the current situation is that we memcpy (at least) in sendmsg()
> and with your patches we do a memcpy higher in the stack, but then
> use MSG_SPLICE_PAGES in order to do it twice. Is that correct?

Not twice, no.  MSG_SPLICE_PAGES allows sendmsg() to splice the supplied pages
into the sk_buffs directly, thereby avoiding a copy in the TCP layer and
cutting out the feeder loop in cifs.

However, this is meant to be an intermediate step.  I actually want to
assemble the fragment list in a bvecq in the smb_create_request() as called by
the PDU encoders, with everything aligned for crypto so that the crypto layer
doesn't copy it also.  But cleaning up the transport first should hopefully
reduce the size of the later patches.

David


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator
  2025-08-07  6:24 ` David Howells
@ 2025-08-07  6:54   ` Stefan Metzmacher
  2025-08-07  7:12   ` David Howells
  1 sibling, 0 replies; 48+ messages in thread
From: Stefan Metzmacher @ 2025-08-07  6:54 UTC (permalink / raw)
  To: David Howells
  Cc: Steve French, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Mina Almasry, linux-cifs, linux-kernel

Am 07.08.25 um 08:24 schrieb David Howells:
> Stefan Metzmacher <metze@samba.org> wrote:
> 
>> So the current situation is that we memcpy (at least) in sendmsg()
>> and with your patches we do a memcpy higher in the stack, but then
>> use MSG_SPLICE_PAGES in order to do it twice. Is that correct?
> 
> Not twice, no.  MSG_SPLICE_PAGES allows sendmsg() to splice the supplied pages
> into the sk_buffs directly, thereby avoiding a copy in the TCP layer and
> cutting out the feeder loop in cifs.

Yes, and we must be careful to not touch the pages after
calling sendmsg(MSG_SPLICE_PAGES).

And unlike MSG_ZEROCOPY tcp_sendmsg_locked() has no
no struct ubuf_info *uarg when MSG_SPLICE_PAGES is used
and there's no way to know when the pages are no longer
used by the tcp stack.

Can you explain how/where we allocate the memory and where
we unreference it in the caller of sendmsg(MSG_SPLICE_PAGES).

> However, this is meant to be an intermediate step.  I actually want to
> assemble the fragment list in a bvecq in the smb_create_request() as called by
> the PDU encoders, with everything aligned for crypto so that the crypto layer
> doesn't copy it also.  But cleaning up the transport first should hopefully
> reduce the size of the later patches.

Sounds good :-)

metze


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator
  2025-08-07  6:24 ` David Howells
  2025-08-07  6:54   ` Stefan Metzmacher
@ 2025-08-07  7:12   ` David Howells
  1 sibling, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-07  7:12 UTC (permalink / raw)
  To: Stefan Metzmacher
  Cc: dhowells, Steve French, Paulo Alcantara, Shyam Prasad N,
	Tom Talpey, Wang Zhaolong, Mina Almasry, linux-cifs, linux-kernel

Stefan Metzmacher <metze@samba.org> wrote:

> >> So the current situation is that we memcpy (at least) in sendmsg()
> >> and with your patches we do a memcpy higher in the stack, but then
> >> use MSG_SPLICE_PAGES in order to do it twice. Is that correct?
> > Not twice, no.  MSG_SPLICE_PAGES allows sendmsg() to splice the supplied
> > pages
> > into the sk_buffs directly, thereby avoiding a copy in the TCP layer and
> > cutting out the feeder loop in cifs.
> 
> Yes, and we must be careful to not touch the pages after
> calling sendmsg(MSG_SPLICE_PAGES).

Until we get a response from the server, yes, but for the protocol info that
shouldn't be an issue.  And if we're going to encrypt, we'll have to do a copy
anyway for something like Write, but we can get the encryption algo to do that
for us by giving it a separate destination buffer.

> And unlike MSG_ZEROCOPY tcp_sendmsg_locked() has no
> no struct ubuf_info *uarg when MSG_SPLICE_PAGES is used
> and there's no way to know when the pages are no longer
> used by the tcp stack.

Correct (and this is something we'll need to address), but for the moment we
can rely on page refcounts.  MSG_SPLICE_PAGES takes a ref on each page - which
is why you can't use it with slab memory.  However, if we pass in
netmem-allocated memory, that works by refcounting, so that should work.

> Can you explain how/where we allocate the memory and where
> we unreference it in the caller of sendmsg(MSG_SPLICE_PAGES).

Currently, we allocate the buffer in fs/netfs/buffer.c in
netfs_alloc_bvecq_buffer().  That just bulk allocates a bunch of pages and
adds them into a bvecq.  As they're untyped pages, we can use the refcount.  I
want to allocate netmem instead, but I haven't done that yet.

We then call sendmsg(MSG_SPLICE_PAGES) and then drop our ref on the pages.
TCP will have taken its own ref which it will drop in due course when the
skbuffs are cleaned up.

David


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC PATCH 16/31] cifs: Rewrite base TCP transmission
  2025-08-06 20:36 ` [RFC PATCH 16/31] cifs: Rewrite base TCP transmission David Howells
  2025-08-07  5:40   ` Stefan Metzmacher
@ 2025-08-07 10:12   ` David Howells
  2025-08-07 10:14   ` David Howells
  2 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-07 10:12 UTC (permalink / raw)
  To: Stefan Metzmacher
  Cc: dhowells, Steve French, Paulo Alcantara, Shyam Prasad N,
	Tom Talpey, Wang Zhaolong, Mina Almasry, linux-cifs, linux-kernel,
	netfs, linux-fsdevel

Stefan Metzmacher <metze@samba.org> wrote:

> > + if (server->noblocksnd)
> > + smb_msg->msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
> > + else
> > + smb_msg->msg_flags = MSG_NOSIGNAL;
> > + smb_msg->msg_flags = MSG_SPLICE_PAGES;
> > +
> 
> I guess you want '|=' instead of '=' in all 3 lines?

Well on the third line.  msg_flags is 0 on entry to the function.

> I also think msghdr should be setup in the caller completely
> or it should be a local variable in smb_sendmsg() and the caller
> only passes struct iov_iter.

Yeah, makes sense.

David


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC PATCH 16/31] cifs: Rewrite base TCP transmission
  2025-08-06 20:36 ` [RFC PATCH 16/31] cifs: Rewrite base TCP transmission David Howells
  2025-08-07  5:40   ` Stefan Metzmacher
  2025-08-07 10:12   ` David Howells
@ 2025-08-07 10:14   ` David Howells
  2 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-07 10:14 UTC (permalink / raw)
  To: Stefan Metzmacher
  Cc: dhowells, Steve French, Paulo Alcantara, Shyam Prasad N,
	Tom Talpey, Wang Zhaolong, Mina Almasry, linux-cifs, linux-kernel,
	netfs, linux-fsdevel

Stefan Metzmacher <metze@samba.org> wrote:

> > + smb_msg->msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;

And whilst I'm sure addition works, I would much rather that be bit-OR.

David


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (32 preceding siblings ...)
  2025-08-07  6:24 ` David Howells
@ 2025-08-08 14:15 ` Enzo Matsumiya
  2025-08-08 17:25 ` David Howells
  34 siblings, 0 replies; 48+ messages in thread
From: Enzo Matsumiya @ 2025-08-08 14:15 UTC (permalink / raw)
  To: David Howells
  Cc: Steve French, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel

Hi David,

On 08/06, David Howells wrote:
> (3) Rewrite the base TCP transmission to be able to use MSG_SPLICE_PAGES.
>
>     (a) Copy all the data involved in a message into a big buffer formed
>     	 of a sequence of pages attached to a bvecq.

Nice!

>     (b) If encrypting the message just encrypt this buffer.  Converting
>     	 this to a scatterlist is much simpler (and uses less memory) than
>     	 encrypting from the protocol elements.

This could've been done a long ago, but since you're on it... crypto API
supports in-place ops (src == dst), so you can save yet another allocation
here.

This is also possible from SMB2 side because the spec says if encryption
fails, the request should be failed as a whole.

>     (d) Compression should be a matter of vmap()'ing these pages to form
>     	 the source buffer, allocating a second buffer of pages to form a
>     	 dest buffer, also in a bvecq, vmapping that and then doing the
>     	 compression.  The first buffer can then just be replaced by the
>     	 second.

OTOH, compression can't be in-place because SMB2 says that if
compression fails, the original uncompressed request must be sent (i.e.
src must be left untouched until smb_compress() finishes).

I don't know how relevant these comments are for you and your patches,
but HTH.

Directly related to the patches: it would be great if you could handle
commented out code, either by completely removing them, or by providing
some in-code fallback mechanism (I'll reply to the patches).

Other than that, +1 for the cleanup/refactoring; I really like the new
smb_message/transport infrastructure!


Cheers,

Enzo

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC PATCH 18/31] cifs: Pass smb_message structs down into the transport layer
  2025-08-06 20:36 ` [RFC PATCH 18/31] cifs: Pass smb_message structs down into the transport layer David Howells
@ 2025-08-08 14:21   ` Enzo Matsumiya
  0 siblings, 0 replies; 48+ messages in thread
From: Enzo Matsumiya @ 2025-08-08 14:21 UTC (permalink / raw)
  To: David Howells
  Cc: Steve French, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

Hi David,

On 08/06, David Howells wrote:
> ...
> 
> static int
>-receive_encrypted_read(struct TCP_Server_Info *server, struct smb_message **smb,
>+receive_encrypted_read(struct TCP_Server_Info *server, struct smb_message **mid,
> 		       int *num_mids)
> {
>+	WARN_ON_ONCE(1);
>+	return -ENOANO; // TODO
>+#if 0
> 	char *buf = server->smallbuf;
> 	struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
> 	struct iov_iter iter;
>@@ -4753,8 +4758,8 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct smb_message **smb,
> 	dw->server = server;
>
> 	*num_mids = 1;
>-	len = min_t(unsigned int, buflen, server->vals->read_rsp_size +
>-		sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + 1;
>+	len = umin(buflen, server->vals->read_rsp_size +
>+		   sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + 1;
>
> 	rc = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1, len);
> 	if (rc < 0)
>@@ -4836,6 +4841,7 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct smb_message **smb,
> discard_data:
> 	cifs_discard_remaining_data(server);
> 	goto free_pages;
>+#endif
> }

I don't quite get why this was commented out (and also seems unrelated
to patch subject).

What problems did you have here?  Does it not work?

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC PATCH 24/31] cifs: Convert SMB2 Negotiate Protocol request
  2025-08-06 20:36 ` [RFC PATCH 24/31] cifs: Convert SMB2 Negotiate Protocol request David Howells
@ 2025-08-08 14:44   ` Enzo Matsumiya
  2025-08-08 15:10   ` David Howells
  1 sibling, 0 replies; 48+ messages in thread
From: Enzo Matsumiya @ 2025-08-08 14:44 UTC (permalink / raw)
  To: David Howells
  Cc: Steve French, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel, netfs, linux-fsdevel

On 08/06, David Howells wrote:
> ...
> 
>-static unsigned int
>-build_netname_ctxt(struct smb2_netname_neg_context *pneg_ctxt, char *hostname)
>+static size_t smb2_size_netname_ctxt(struct TCP_Server_Info *server)
> {
>+	size_t data_len;
>+
>+#if 0
> 	struct nls_table *cp = load_nls_default();
>+	const char *hostname;
>
>-	pneg_ctxt->ContextType = SMB2_NETNAME_NEGOTIATE_CONTEXT_ID;
>+	/* Only include up to first 100 bytes of server name in the NetName
>+	 * field.
>+	 */
>+	cifs_server_lock(pserver);
>+	hostname = pserver->hostname;
>+	if (hostname && hostname[0])
>+		data_len = cifs_size_strtoUTF16(hostname, 100, cp);
>+	cifs_server_unlock(pserver);
>+#else
>+	/* Now, we can't just measure the length of hostname as, unless we hold
>+	 * the lock, it may change under us, so allow maximum space for it.
>+	 */
>+	data_len = 400;
>+#endif
>+	return ALIGN8(sizeof(struct smb2_neg_context) + data_len);
>+}

Why was this commented out?  Your comment implies that you can't hold
the lock anymore there, but I couldn't find out why (with your patches
applied).

>-static void
>-assemble_neg_contexts(struct smb2_negotiate_req *req,
>-		      struct TCP_Server_Info *server, unsigned int *total_len)
>+static size_t smb2_size_neg_contexts(struct TCP_Server_Info *server,
>+				     size_t offset)
> {
>-	unsigned int ctxt_len, neg_context_count;
> 	struct TCP_Server_Info *pserver;
>-	char *pneg_ctxt;
>-	char *hostname;
>-
>-	if (*total_len > 200) {
>-		/* In case length corrupted don't want to overrun smb buffer */
>-		cifs_server_dbg(VFS, "Bad frame length assembling neg contexts\n");
>-		return;
>-	}
>
> 	/*
> 	 * round up total_len of fixed part of SMB3 negotiate request to 8
> 	 * byte boundary before adding negotiate contexts
> 	 */
>-	*total_len = ALIGN8(*total_len);
>+	offset = ALIGN8(offset);
>+	offset += ALIGN8(sizeof(struct smb2_preauth_neg_context));
>+	offset += ALIGN8(sizeof(struct smb2_encryption_neg_context));
>
>-	pneg_ctxt = (*total_len) + (char *)req;
>-	req->NegotiateContextOffset = cpu_to_le32(*total_len);
>+	/*
>+	 * secondary channels don't have the hostname field populated
>+	 * use the hostname field in the primary channel instead
>+	 */
>+	pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
>+	offset += smb2_size_netname_ctxt(pserver);

If you're keeping data_len=400 above, you could just drop
smb2_size_netname_ctxt() altogether and use
"ALIGN8(sizeof(struct smb2_neg_context) + 400)" directly here.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC PATCH 24/31] cifs: Convert SMB2 Negotiate Protocol request
  2025-08-06 20:36 ` [RFC PATCH 24/31] cifs: Convert SMB2 Negotiate Protocol request David Howells
  2025-08-08 14:44   ` Enzo Matsumiya
@ 2025-08-08 15:10   ` David Howells
  1 sibling, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-08 15:10 UTC (permalink / raw)
  To: Enzo Matsumiya
  Cc: dhowells, Steve French, Paulo Alcantara, Shyam Prasad N,
	Tom Talpey, Wang Zhaolong, Stefan Metzmacher, Mina Almasry,
	linux-cifs, linux-kernel, netfs, linux-fsdevel

Enzo Matsumiya <ematsumiya@suse.de> wrote:

> On 08/06, David Howells wrote:
> > ...
> > -static unsigned int
> >-build_netname_ctxt(struct smb2_netname_neg_context *pneg_ctxt, char *hostname)
> >+static size_t smb2_size_netname_ctxt(struct TCP_Server_Info *server)
> > {
> >+	size_t data_len;
> >+
> >+#if 0
> > 	struct nls_table *cp = load_nls_default();
> >+	const char *hostname;
> >
> >-	pneg_ctxt->ContextType = SMB2_NETNAME_NEGOTIATE_CONTEXT_ID;
> >+	/* Only include up to first 100 bytes of server name in the NetName
> >+	 * field.
> >+	 */
> >+	cifs_server_lock(pserver);
> >+	hostname = pserver->hostname;
> >+	if (hostname && hostname[0])
> >+		data_len = cifs_size_strtoUTF16(hostname, 100, cp);
> >+	cifs_server_unlock(pserver);
> >+#else
> >+	/* Now, we can't just measure the length of hostname as, unless we hold
> >+	 * the lock, it may change under us, so allow maximum space for it.
> >+	 */
> >+	data_len = 400;
> >+#endif
> >+	return ALIGN8(sizeof(struct smb2_neg_context) + data_len);
> >+}
> 
> Why was this commented out?  Your comment implies that you can't hold
> the lock anymore there, but I couldn't find out why (with your patches
> applied).

The problem is that the hostname may change - and there's a spinlock to
protect it.  However, now that I'm working out the message size before the
allocation, I need to find the size of the host name, do the alloc and then
copy the hostname in - but I can't hold the spinlock across the alloc, so the
hostname may change whilst the lock is dropped.

The obvious solution is to just allocate the maximum size for it.  It's not
that big and this command isn't used all that often.

Remember that this is a work in progress, so you may find bits like this where
I may need to reconsider what I've chosen.

> >-static void
> >-assemble_neg_contexts(struct smb2_negotiate_req *req,
> >-		      struct TCP_Server_Info *server, unsigned int *total_len)
> >+static size_t smb2_size_neg_contexts(struct TCP_Server_Info *server,
> >+				     size_t offset)
> > {
> >-	unsigned int ctxt_len, neg_context_count;
> > 	struct TCP_Server_Info *pserver;
> >-	char *pneg_ctxt;
> >-	char *hostname;
> >-
> >-	if (*total_len > 200) {
> >-		/* In case length corrupted don't want to overrun smb buffer */
> >-		cifs_server_dbg(VFS, "Bad frame length assembling neg contexts\n");
> >-		return;
> >-	}
> >
> > 	/*
> > 	 * round up total_len of fixed part of SMB3 negotiate request to 8
> > 	 * byte boundary before adding negotiate contexts
> > 	 */
> >-	*total_len = ALIGN8(*total_len);
> >+	offset = ALIGN8(offset);
> >+	offset += ALIGN8(sizeof(struct smb2_preauth_neg_context));
> >+	offset += ALIGN8(sizeof(struct smb2_encryption_neg_context));
> >
> >-	pneg_ctxt = (*total_len) + (char *)req;
> >-	req->NegotiateContextOffset = cpu_to_le32(*total_len);
> >+	/*
> >+	 * secondary channels don't have the hostname field populated
> >+	 * use the hostname field in the primary channel instead
> >+	 */
> >+	pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
> >+	offset += smb2_size_netname_ctxt(pserver);
> 
> If you're keeping data_len=400 above, you could just drop
> smb2_size_netname_ctxt() altogether and use
> "ALIGN8(sizeof(struct smb2_neg_context) + 400)" directly here.

Yeah.  Probably would make sense to do that with a comment saying why 400.

David


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator
  2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
                   ` (33 preceding siblings ...)
  2025-08-08 14:15 ` Enzo Matsumiya
@ 2025-08-08 17:25 ` David Howells
  2025-08-08 19:58   ` Enzo Matsumiya
                     ` (2 more replies)
  34 siblings, 3 replies; 48+ messages in thread
From: David Howells @ 2025-08-08 17:25 UTC (permalink / raw)
  To: Enzo Matsumiya
  Cc: dhowells, Steve French, Paulo Alcantara, Shyam Prasad N,
	Tom Talpey, Wang Zhaolong, Stefan Metzmacher, Mina Almasry,
	linux-cifs, linux-kernel

Hi Enzo,

> >     (d) Compression should be a matter of vmap()'ing these pages to form
> >     	 the source buffer, allocating a second buffer of pages to form a
> >     	 dest buffer, also in a bvecq, vmapping that and then doing the
> >     	 compression.  The first buffer can then just be replaced by the
> >     	 second.
> 
> OTOH, compression can't be in-place because SMB2 says that if
> compression fails, the original uncompressed request must be sent (i.e.
> src must be left untouched until smb_compress() finishes).

I've got a change which should achieve this, but it seems I can't test it.
None of ksmbd, samba and azure seem to support it:-/

David


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator
  2025-08-08 17:25 ` David Howells
@ 2025-08-08 19:58   ` Enzo Matsumiya
  2025-08-08 20:33   ` David Howells
  2025-08-10 23:29   ` David Howells
  2 siblings, 0 replies; 48+ messages in thread
From: Enzo Matsumiya @ 2025-08-08 19:58 UTC (permalink / raw)
  To: David Howells
  Cc: Steve French, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel

On 08/08, David Howells wrote:
>Hi Enzo,
>
>> >     (d) Compression should be a matter of vmap()'ing these pages to form
>> >     	 the source buffer, allocating a second buffer of pages to form a
>> >     	 dest buffer, also in a bvecq, vmapping that and then doing the
>> >     	 compression.  The first buffer can then just be replaced by the
>> >     	 second.
>>
>> OTOH, compression can't be in-place because SMB2 says that if
>> compression fails, the original uncompressed request must be sent (i.e.
>> src must be left untouched until smb_compress() finishes).
>
>I've got a change which should achieve this, but it seems I can't test it.
>None of ksmbd, samba and azure seem to support it:-/

Yes, Windows 11 or Windows Server 2022+ only.

Compression for ksmbd and samba have been on my TODO list for too long,
I should get back to it :/

Anyway, if you want me to test, just send me the patches.
I have your linux-fs remote as well, if that's easier.


Cheers,

Enzo

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator
  2025-08-08 17:25 ` David Howells
  2025-08-08 19:58   ` Enzo Matsumiya
@ 2025-08-08 20:33   ` David Howells
  2025-08-10 23:29   ` David Howells
  2 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2025-08-08 20:33 UTC (permalink / raw)
  To: Enzo Matsumiya
  Cc: dhowells, Steve French, Paulo Alcantara, Shyam Prasad N,
	Tom Talpey, Wang Zhaolong, Stefan Metzmacher, Mina Almasry,
	linux-cifs, linux-kernel

Enzo Matsumiya <ematsumiya@suse.de> wrote:

> Anyway, if you want me to test, just send me the patches.
> I have your linux-fs remote as well, if that's easier.

If you look at:

https://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs.git/log/?h=cifs-experimental

You can see a patch with the subject "cifs: [!] FIX transport compression".
Grab that and everything up to it.

I'm pretty certain it won't work, but I can't test it.  Well, maybe I can
force it on and look at the packet trace if wireshark can handle it.

Some things to note:

 (1) In smb_compress(), netfs_alloc_bvecq_buffer() is used to allocate the
     destination buffer and attach it to a bvecq, which it also allocates.  An
     iterator can be set on this to define part of the buffer to operate on.

 (2) vmap_bvecq() is used to map the source and the destination buffers.  It
     extracts the pages and then calls vmap() on them.

 (3) Space for the compression header is allocated by smb_send_rqst() in the
     first bvecq slot along with the rfc1002 header and transform header (if
     sealing).  A pointer is passed down to smb_compress().

 (4) It attempts to adjust the values such that the compression header is
     included in the encrypted section if also sealing.  However, it might be
     better to have smb_compress() place it in the output buffer.

 (5) If compression is successful, smb_compress() switches the original bvecq
     and the output bvecq and moves the header segment from the original to
     the output.

 (6) If the compression algo returns -EMSGSIZE, then the compression header is
     excluded from the header segment.

David


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator
  2025-08-08 17:25 ` David Howells
  2025-08-08 19:58   ` Enzo Matsumiya
  2025-08-08 20:33   ` David Howells
@ 2025-08-10 23:29   ` David Howells
  2025-08-11 12:25     ` Enzo Matsumiya
  2 siblings, 1 reply; 48+ messages in thread
From: David Howells @ 2025-08-10 23:29 UTC (permalink / raw)
  To: Enzo Matsumiya
  Cc: dhowells, Steve French, Paulo Alcantara, Shyam Prasad N,
	Tom Talpey, Wang Zhaolong, Stefan Metzmacher, Mina Almasry,
	linux-cifs, linux-kernel

Hi Enzo,

I now have encryption, compression and encryption+compression all working :-)

I've pushed my patches here:

	https://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs.git/log/?h=cifs-experimental

It should work up to "cifs: Don't use corking".

Btw, is is_compressible() actually worth doing?  It seems to copy a lot of
data (up to 4M) to an extra buffer and then do various analyses on it,
including doing a sort.

I need to extract a fix for collect_sample(), which I can do tomorrow, but it
should look something like:

/*
 * Collect some 2K samples with 2K gaps between.
 */
static int collect_sample(const struct iov_iter *source, ssize_t max, u8 *sample)
{
	struct iov_iter iter = *source;
	size_t s = 0;

	while (iov_iter_count(&iter) >= SZ_2K) {
		size_t part = umin(umin(iov_iter_count(&iter), SZ_2K), max);
		size_t n;

		n = copy_from_iter(sample + s, part, &iter);
		if (n != part)
			return -EFAULT;

		s += n;
		max -= n;

		if (iov_iter_count(&iter) < PAGE_SIZE - SZ_2K)
			break;

		iov_iter_advance(&iter, SZ_2K);
	}

	return s;
}

What's currently upstream won't work and may crash because it assumes that
ITER_XARRAY is in use - which should now never be true.

Also, there's a bug in wireshark's LZ77 decoder.  See attached patch.

David

diff --git a/epan/tvbuff_lz77.c b/epan/tvbuff_lz77.c
index a609912636..13ab5c50ed 100644
--- a/epan/tvbuff_lz77.c
+++ b/epan/tvbuff_lz77.c
@@ -68,7 +68,7 @@ static bool do_uncompress(tvbuff_t *tvb, int offset, int in_size,
 						in_off += 2;
 						if (match_len == 0) {
 							/* This case isn't documented */
-							match_len = tvb_get_letohs(tvb, offset+in_off);
+							match_len = tvb_get_letohl(tvb, offset+in_off);
 							in_off += 4;
 						}
 						if (match_len < 15+7)


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator
  2025-08-10 23:29   ` David Howells
@ 2025-08-11 12:25     ` Enzo Matsumiya
  0 siblings, 0 replies; 48+ messages in thread
From: Enzo Matsumiya @ 2025-08-11 12:25 UTC (permalink / raw)
  To: David Howells
  Cc: Steve French, Paulo Alcantara, Shyam Prasad N, Tom Talpey,
	Wang Zhaolong, Stefan Metzmacher, Mina Almasry, linux-cifs,
	linux-kernel

On 08/11, David Howells wrote:
>Hi Enzo,
>
>I now have encryption, compression and encryption+compression all working :-)
>
>I've pushed my patches here:
>
>	https://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs.git/log/?h=cifs-experimental
>
>It should work up to "cifs: Don't use corking".

Great! I'll try it out later.

>Btw, is is_compressible() actually worth doing?  It seems to copy a lot of
>data (up to 4M) to an extra buffer and then do various analyses on it,
>including doing a sort.

Compression, as a whole, is actually only worth doing if one is paying
more for network traffic than computing.  is_compressible() tries to
balance that to avoid a "compress/fail/send original" cycle, as it takes
0-4ms on a 4M payload (on my machine) whereas, without it, a failing
cycle can take up to 40ms.

>I need to extract a fix for collect_sample(), which I can do tomorrow, but it
>should look something like:
>
>/*
> * Collect some 2K samples with 2K gaps between.
> */
>static int collect_sample(const struct iov_iter *source, ssize_t max, u8 *sample)
>{
>	struct iov_iter iter = *source;
>	size_t s = 0;
>
>	while (iov_iter_count(&iter) >= SZ_2K) {
>		size_t part = umin(umin(iov_iter_count(&iter), SZ_2K), max);
>		size_t n;
>
>		n = copy_from_iter(sample + s, part, &iter);
>		if (n != part)
>			return -EFAULT;
>
>		s += n;
>		max -= n;
>
>		if (iov_iter_count(&iter) < PAGE_SIZE - SZ_2K)
>			break;
>
>		iov_iter_advance(&iter, SZ_2K);
>	}
>
>	return s;
>}
>
>What's currently upstream won't work and may crash because it assumes that
>ITER_XARRAY is in use - which should now never be true.

Yes, compression was merged when that was the only case.

>Also, there's a bug in wireshark's LZ77 decoder.  See attached patch.

Good catch :)
There are several, actually... if you vary the compression parameters
defined (min len, min/max dist, hash log) within acceptable limits,
you'll notice that, even though wireshark might show some as malformed
packets, Windows is able to decode them just fine.

I really need to reserve some time to work on this again :(


Cheers,

Enzo

^ permalink raw reply	[flat|nested] 48+ messages in thread

end of thread, other threads:[~2025-08-11 12:25 UTC | newest]

Thread overview: 48+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-06 20:36 [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator David Howells
2025-08-06 20:36 ` [RFC PATCH 01/31] iov_iter: Move ITER_DISCARD and ITER_XARRAY iteration out-of-line David Howells
2025-08-06 20:36 ` [RFC PATCH 02/31] iov_iter: Add a segmented queue of bio_vec[] David Howells
2025-08-06 20:36 ` [RFC PATCH 03/31] netfs: Provide facility to alloc buffer in a bvecq David Howells
2025-08-06 20:36 ` [RFC PATCH 04/31] cifs, nls: Provide unicode size determination func David Howells
2025-08-06 20:36 ` [RFC PATCH 05/31] cifs: Introduce an ALIGN8() macro David Howells
2025-08-06 20:36 ` [RFC PATCH 06/31] cifs: Move the SMB1 transport code out of transport.c David Howells
2025-08-06 20:36 ` [RFC PATCH 07/31] cifs: Rename mid_q_entry to smb_message David Howells
2025-08-06 20:36 ` [RFC PATCH 08/31] cifs: Keep the CPU-endian command ID around David Howells
2025-08-06 20:36 ` [RFC PATCH 09/31] cifs: Rename SMB2_xxxx_HE to SMB2_xxxx David Howells
2025-08-06 20:36 ` [RFC PATCH 10/31] cifs: Make smb1's SendReceive() wrap cifs_send_recv() David Howells
2025-08-06 20:36 ` [RFC PATCH 11/31] cifs: Fix SMB1 to not require separate kvec for the rfc1002 header David Howells
2025-08-06 20:36 ` [RFC PATCH 12/31] cifs: Replace SendReceiveBlockingLock() with SendReceive() plus flags David Howells
2025-08-06 20:36 ` [RFC PATCH 13/31] cifs: Institute message managing struct David Howells
2025-08-06 20:36 ` [RFC PATCH 14/31] cifs: Split crypt_message() into encrypt and decrypt variants David Howells
2025-08-06 20:36 ` [RFC PATCH 15/31] cifs: Use netfs_alloc/free_folioq_buffer() David Howells
2025-08-06 20:36 ` [RFC PATCH 16/31] cifs: Rewrite base TCP transmission David Howells
2025-08-07  5:40   ` Stefan Metzmacher
2025-08-07 10:12   ` David Howells
2025-08-07 10:14   ` David Howells
2025-08-06 20:36 ` [RFC PATCH 17/31] cifs: Rework smb2 decryption David Howells
2025-08-06 20:36 ` [RFC PATCH 18/31] cifs: Pass smb_message structs down into the transport layer David Howells
2025-08-08 14:21   ` Enzo Matsumiya
2025-08-06 20:36 ` [RFC PATCH 19/31] cifs: Clean up mid->callback_data and kill off mid->creator David Howells
2025-08-06 20:36 ` [RFC PATCH 20/31] cifs: Don't need state locking in smb2_get_mid_entry() David Howells
2025-08-06 20:36 ` [RFC PATCH 21/31] cifs: [DEBUG] smb_message refcounting David Howells
2025-08-06 20:36 ` [RFC PATCH 22/31] cifs: Add netmem allocation functions David Howells
2025-08-06 20:36 ` [RFC PATCH 23/31] cifs: Add more pieces to smb_message David Howells
2025-08-06 20:36 ` [RFC PATCH 24/31] cifs: Convert SMB2 Negotiate Protocol request David Howells
2025-08-08 14:44   ` Enzo Matsumiya
2025-08-08 15:10   ` David Howells
2025-08-06 20:36 ` [RFC PATCH 25/31] cifs: Convert SMB2 Session Setup request David Howells
2025-08-06 20:36 ` [RFC PATCH 26/31] cifs: Convert SMB2 Logoff request David Howells
2025-08-06 20:36 ` [RFC PATCH 27/31] cifs: Convert SMB2 Tree Connect request David Howells
2025-08-06 20:36 ` [RFC PATCH 28/31] cifs: Convert SMB2 Tree Disconnect request David Howells
2025-08-06 20:36 ` [RFC PATCH 29/31] cifs: Rearrange Create request subfuncs David Howells
2025-08-06 20:36 ` [RFC PATCH 30/31] cifs: Convert SMB2 Posix Mkdir request David Howells
2025-08-06 20:36 ` [RFC PATCH 31/31] cifs: Convert SMB2 Open request David Howells
2025-08-07  5:23 ` [RFC PATCH 00/31] netfs: [WIP] Allow the use of MSG_SPLICE_PAGES and use netmem allocator Stefan Metzmacher
2025-08-07  6:24 ` David Howells
2025-08-07  6:54   ` Stefan Metzmacher
2025-08-07  7:12   ` David Howells
2025-08-08 14:15 ` Enzo Matsumiya
2025-08-08 17:25 ` David Howells
2025-08-08 19:58   ` Enzo Matsumiya
2025-08-08 20:33   ` David Howells
2025-08-10 23:29   ` David Howells
2025-08-11 12:25     ` Enzo Matsumiya

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).