[RFC PATCH 09/36] cifs: Institute message managing struct

From: David Howells

Date: Tue May 19 2026 - 06:40:12 EST


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_trace: An ID of the command type for use in tracing.

(*) ->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@xxxxxxxxxx>
cc: Steve French <sfrench@xxxxxxxxx>
cc: Paulo Alcantara <pc@xxxxxxxxxxxxx>
cc: Shyam Prasad N <sprasad@xxxxxxxxxxxxx>
cc: Tom Talpey <tom@xxxxxxxxxx>
cc: linux-cifs@xxxxxxxxxxxxxxx
cc: netfs@xxxxxxxxxxxxxxx
cc: linux-fsdevel@xxxxxxxxxxxxxxx
---
fs/smb/client/cifsglob.h | 104 ++++++++++++++++++++++++----------
fs/smb/client/cifsproto.h | 11 ++--
fs/smb/client/connect.c | 6 +-
fs/smb/client/smb1ops.c | 2 +-
fs/smb/client/smb1transport.c | 2 +-
fs/smb/client/smb2ops.c | 2 +-
fs/smb/client/smb2transport.c | 4 +-
fs/smb/client/transport.c | 42 +++++++++++++-
8 files changed, 127 insertions(+), 46 deletions(-)

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index a5e12a2eefdd..0f876feb0dbf 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -1701,40 +1701,82 @@ typedef void (*mid_callback_t)(struct TCP_Server_Info *srv, struct smb_message *
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 */
- refcount_t refcount;
- __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 */
+ __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;
- u32 response_pdu_len;
- int mid_state; /* wish this were enum but can not pass to wait_event */
- int mid_rc; /* rc for MID_RC */
- __le16 command; /* smb command code */
- unsigned int optype; /* operation type */
- spinlock_t mid_lock;
- bool wait_cancelled:1; /* Cancelled while waiting for response */
- bool deleted_from_q:1; /* Whether Mid has been dequeued frem pending_mid_q */
- 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 optype; /* operation type */
+ spinlock_t mid_lock;
+ bool wait_cancelled:1; /* Cancelled while waiting for response */
+ bool deleted_from_q:1; /* Mid has been dequeued from pending_mid_q */
+ 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 */
+ u8 command_trace; /* enum smb_command_trace - Command trace ID */
+ __le16 command; /* smb command code */
+ s16 pre_offset; /* Offset of pre-headers from ->body (negative) */
+ unsigned int total_len; /* Total length of from hdr_offset onwards */
+ /* Response */
+ u32 response_pdu_len; /* Size of response PDU */
+ /* 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 f88ae04af85d..9c60fffcf53d 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -81,6 +81,10 @@ char *cifs_build_path_to_root(struct smb3_fs_context *ctx,
struct cifs_tcon *tcon, int add_treename);
char *cifs_build_devname(char *nodename, const char *prepath);
void delete_mid(struct TCP_Server_Info *server, struct smb_message *smb);
+struct smb_message *smb_message_alloc(enum smb_command_trace 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);
void __release_mid(struct TCP_Server_Info *server, struct smb_message *smb);
void cifs_wake_up_task(struct TCP_Server_Info *server,
struct smb_message *smb);
@@ -470,14 +474,9 @@ static inline bool dfs_src_pathname_equal(const char *s1, const char *s2)
return true;
}

-static inline void smb_get_mid(struct smb_message *smb)
-{
- refcount_inc(&smb->refcount);
-}
-
static inline void release_mid(struct TCP_Server_Info *server, struct smb_message *smb)
{
- if (refcount_dec_and_test(&smb->refcount))
+ if (refcount_dec_and_test(&smb->ref))
__release_mid(server, smb);
}

diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index 97de3ae68d7a..3d7e279ba149 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -327,7 +327,7 @@ cifs_abort_connection(struct TCP_Server_Info *server)
cifs_dbg(FYI, "%s: moving mids to private list\n", __func__);
spin_lock(&server->mid_queue_lock);
list_for_each_entry_safe(smb, nsmb, &server->pending_mid_q, qhead) {
- smb_get_mid(smb);
+ smb_get_message(smb);
if (smb->mid_state == MID_REQUEST_SUBMITTED)
smb->mid_state = MID_RETRY_NEEDED;
list_move(&smb->qhead, &retry_list);
@@ -884,7 +884,7 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
*/
spin_lock(&server->mid_queue_lock);
list_for_each_entry_safe(smb, nsmb, &server->pending_mid_q, qhead) {
- smb_get_mid(smb);
+ smb_get_message(smb);
list_move(&smb->qhead, &dispose_list);
smb->deleted_from_q = true;
}
@@ -1103,7 +1103,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);
- smb_get_mid(smb);
+ smb_get_message(smb);
smb->mid_state = MID_SHUTDOWN;
list_move(&smb->qhead, &dispose_list);
smb->deleted_from_q = true;
diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
index c1c16f6346fb..df74975374ee 100644
--- a/fs/smb/client/smb1ops.c
+++ b/fs/smb/client/smb1ops.c
@@ -254,7 +254,7 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buffer)
if (compare_mid(smb->mid, buf) &&
smb->mid_state == MID_REQUEST_SUBMITTED &&
le16_to_cpu(smb->command) == buf->Command) {
- smb_get_mid(smb);
+ smb_get_message(smb);
spin_unlock(&server->mid_queue_lock);
return smb;
}
diff --git a/fs/smb/client/smb1transport.c b/fs/smb/client/smb1transport.c
index c2d211a62577..f38fe262c7ea 100644
--- a/fs/smb/client/smb1transport.c
+++ b/fs/smb/client/smb1transport.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));
- refcount_set(&smb->refcount, 1);
+ refcount_set(&smb->ref, 1);
spin_lock_init(&smb->mid_lock);
smb->mid = get_mid(smb_buffer);
smb->pid = current->pid;
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 236eb560bdff..f39074d0e4a0 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -416,7 +416,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 == shdr->Command)) {
- smb_get_mid(smb);
+ smb_get_message(smb);
if (dequeue) {
list_del_init(&smb->qhead);
smb->deleted_from_q = true;
diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index a28b66ead690..f5b676802ce7 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -619,10 +619,10 @@ smb2_mid_entry_alloc(const struct smb2_hdr *shdr,

smb = mempool_alloc(&smb_message_pool, GFP_NOFS);
memset(smb, 0, sizeof(*smb));
- refcount_set(&smb->refcount, 1);
+ refcount_set(&smb->ref, 1);
spin_lock_init(&smb->mid_lock);
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 = shdr->Command; /* Always LE */
smb->when_alloc = jiffies;
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index 622f63779de0..3ea52cf4a64b 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 smb_command_trace 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_trace = 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 TCP_Server_Info *server, struct smb_message *smb)
{
@@ -722,7 +762,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(server, smb);
}