[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250806203705.2560493-14-dhowells@redhat.com>
Date: Wed, 6 Aug 2025 21:36:34 +0100
From: David Howells <dhowells@...hat.com>
To: Steve French <sfrench@...ba.org>
Cc: David Howells <dhowells@...hat.com>,
Paulo Alcantara <pc@...guebit.org>,
Shyam Prasad N <sprasad@...rosoft.com>,
Tom Talpey <tom@...pey.com>,
Wang Zhaolong <wangzhaolong@...weicloud.com>,
Stefan Metzmacher <metze@...ba.org>,
Mina Almasry <almasrymina@...gle.com>,
linux-cifs@...r.kernel.org,
linux-kernel@...r.kernel.org,
netfs@...ts.linux.dev,
linux-fsdevel@...r.kernel.org
Subject: [RFC PATCH 13/31] cifs: Institute message managing struct
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@...hat.com>
cc: Steve French <sfrench@...ba.org>
cc: Paulo Alcantara <pc@...guebit.org>
cc: Shyam Prasad N <sprasad@...rosoft.com>
cc: Tom Talpey <tom@...pey.com>
cc: linux-cifs@...r.kernel.org
cc: netfs@...ts.linux.dev
cc: linux-fsdevel@...r.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);
}
Powered by blists - more mailing lists