lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<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

Powered by Openwall GNU/*/Linux Powered by OpenVZ