From 1e2f487584ed426a744b86e04f96662488c7aa0e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 8 Sep 2025 12:06:18 +0200 Subject: [PATCH 001/159] smb: smbdirect: introduce smbdirect_socket_status_string() This will be used for more useful debug messages. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect_socket.h | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index 3c4a8d627aa3..8484c6f09317 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -16,6 +16,29 @@ enum smbdirect_socket_status { SMBDIRECT_SOCKET_DESTROYED }; +static __always_inline +const char *smbdirect_socket_status_string(enum smbdirect_socket_status status) +{ + switch (status) { + case SMBDIRECT_SOCKET_CREATED: + return "CREATED"; + case SMBDIRECT_SOCKET_CONNECTING: + return "CONNECTING"; + case SMBDIRECT_SOCKET_CONNECTED: + return "CONNECTED"; + case SMBDIRECT_SOCKET_NEGOTIATE_FAILED: + return "NEGOTIATE_FAILED"; + case SMBDIRECT_SOCKET_DISCONNECTING: + return "DISCONNECTING"; + case SMBDIRECT_SOCKET_DISCONNECTED: + return "DISCONNECTED"; + case SMBDIRECT_SOCKET_DESTROYED: + return "DESTROYED"; + } + + return ""; +} + struct smbdirect_socket { enum smbdirect_socket_status status; From 371d3ab51ce44c8a7c0f9b835b74b7340a922059 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Aug 2025 18:48:16 +0200 Subject: [PATCH 002/159] smb: smbdirect: introduce smbdirect_socket.status_wait This will be used by server and client soon. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect_socket.h | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index 8484c6f09317..a69b9649b88e 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -41,6 +41,7 @@ const char *smbdirect_socket_status_string(enum smbdirect_socket_status status) struct smbdirect_socket { enum smbdirect_socket_status status; + wait_queue_head_t status_wait; /* RDMA related */ struct { From 17e1d07430e4bd6a14e2d194791f545f8548ff58 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Aug 2025 15:08:33 +0200 Subject: [PATCH 003/159] smb: smbdirect: introduce smbdirect_socket_init() This will make it easier to keep the initialization in a single place. For now it's an __always_inline function as we only share the header files. Once move to common functions we'll have a dedicated smbdirect.ko that exports functions... Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect_socket.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index a69b9649b88e..4e2b87208d91 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -136,6 +136,24 @@ struct smbdirect_socket { } recv_io; }; +static __always_inline void smbdirect_socket_init(struct smbdirect_socket *sc) +{ + /* + * This also sets status = SMBDIRECT_SOCKET_CREATED + */ + BUILD_BUG_ON(SMBDIRECT_SOCKET_CREATED != 0); + memset(sc, 0, sizeof(*sc)); + + init_waitqueue_head(&sc->status_wait); + + INIT_LIST_HEAD(&sc->recv_io.free.list); + spin_lock_init(&sc->recv_io.free.lock); + + INIT_LIST_HEAD(&sc->recv_io.reassembly.list); + spin_lock_init(&sc->recv_io.reassembly.lock); + init_waitqueue_head(&sc->recv_io.reassembly.wait_queue); +} + struct smbdirect_send_io { struct smbdirect_socket *socket; struct ib_cqe cqe; From de32f33c0365d06962675dc2c2269723dd917d0f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Aug 2025 19:05:39 +0200 Subject: [PATCH 004/159] smb: smbdirect: introduce smbdirect_socket.disconnect_work Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect_socket.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index 4e2b87208d91..ab36c2271e3e 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -43,6 +43,8 @@ struct smbdirect_socket { enum smbdirect_socket_status status; wait_queue_head_t status_wait; + struct work_struct disconnect_work; + /* RDMA related */ struct { struct rdma_cm_id *cm_id; From 3b7be44a0eb18b2e51190fd1d26997dc7bddc32d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 11 Aug 2025 15:19:51 +0200 Subject: [PATCH 005/159] smb: smbdirect: introduce smbdirect_socket.send_io.pending.{count,{dec,zero}_wait_queue} This will be shared between client and server soon. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect_socket.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index ab36c2271e3e..1df43b7a87f4 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -77,6 +77,21 @@ struct smbdirect_socket { struct kmem_cache *cache; mempool_t *pool; } mem; + + /* + * The state about posted/pending sends + */ + struct { + atomic_t count; + /* + * woken when count is decremented + */ + wait_queue_head_t dec_wait_queue; + /* + * woken when count reached zero + */ + wait_queue_head_t zero_wait_queue; + } pending; } send_io; /* @@ -148,6 +163,10 @@ static __always_inline void smbdirect_socket_init(struct smbdirect_socket *sc) init_waitqueue_head(&sc->status_wait); + atomic_set(&sc->send_io.pending.count, 0); + init_waitqueue_head(&sc->send_io.pending.dec_wait_queue); + init_waitqueue_head(&sc->send_io.pending.zero_wait_queue); + INIT_LIST_HEAD(&sc->recv_io.free.list); spin_lock_init(&sc->recv_io.free.lock); From 2191b3471df53d87a46179b0c302c77c9ccfec11 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 11 Aug 2025 16:03:00 +0200 Subject: [PATCH 006/159] smb: smbdirect: introduce smbdirect_socket.send_io.credits.{count,wait_queue} This will be shared between client and server soon. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect_socket.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index 1df43b7a87f4..7c2147a0244a 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -78,6 +78,14 @@ struct smbdirect_socket { mempool_t *pool; } mem; + /* + * The credit state for the send side + */ + struct { + atomic_t count; + wait_queue_head_t wait_queue; + } credits; + /* * The state about posted/pending sends */ @@ -163,6 +171,9 @@ static __always_inline void smbdirect_socket_init(struct smbdirect_socket *sc) init_waitqueue_head(&sc->status_wait); + atomic_set(&sc->send_io.credits.count, 0); + init_waitqueue_head(&sc->send_io.credits.wait_queue); + atomic_set(&sc->send_io.pending.count, 0); init_waitqueue_head(&sc->send_io.pending.dec_wait_queue); init_waitqueue_head(&sc->send_io.pending.zero_wait_queue); From cce93d2d0ccc88d2486e220e4a802c9edc48849b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 18 Aug 2025 21:13:03 +0200 Subject: [PATCH 007/159] smb: smbdirect: introduce struct smbdirect_send_batch This will replace struct smb_direct_send_ctx in the server and allow us move code to the common smbdirect layer soon. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect_socket.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index 7c2147a0244a..e1454ccf849b 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -210,6 +210,23 @@ struct smbdirect_send_io { u8 packet[]; }; +struct smbdirect_send_batch { + /* + * List of smbdirect_send_io messages + */ + struct list_head msg_list; + /* + * Number of list entries + */ + size_t wr_cnt; + + /* + * Possible remote key invalidation state + */ + bool need_invalidate_rkey; + u32 remote_key; +}; + struct smbdirect_recv_io { struct smbdirect_socket *socket; struct ib_cqe cqe; From 90255ed46774bda93a945a6dbf9228d9ecfcd79f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 14 Aug 2025 11:41:59 +0200 Subject: [PATCH 008/159] smb: smbdirect: introduce smbdirect_socket.rw_io.credits This will be used by the server to manage the state for RDMA read/write requests. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect_socket.h | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index e1454ccf849b..148e8dbf1254 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -159,6 +159,27 @@ struct smbdirect_socket { bool full_packet_received; } reassembly; } recv_io; + + /* + * The state for RDMA read/write requests on the server + */ + struct { + /* + * The credit state for the send side + */ + struct { + /* + * The maximum number of rw credits + */ + size_t max; + /* + * The number of pages per credit + */ + size_t num_pages; + atomic_t count; + wait_queue_head_t wait_queue; + } credits; + } rw_io; }; static __always_inline void smbdirect_socket_init(struct smbdirect_socket *sc) @@ -184,6 +205,9 @@ static __always_inline void smbdirect_socket_init(struct smbdirect_socket *sc) INIT_LIST_HEAD(&sc->recv_io.reassembly.list); spin_lock_init(&sc->recv_io.reassembly.lock); init_waitqueue_head(&sc->recv_io.reassembly.wait_queue); + + atomic_set(&sc->rw_io.credits.count, 0); + init_waitqueue_head(&sc->rw_io.credits.wait_queue); } struct smbdirect_send_io { From b5a4242fb902f3780ef85d4027ba5987b7ce1e2d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 18 Aug 2025 21:04:14 +0200 Subject: [PATCH 009/159] smb: smbdirect: introduce struct smbdirect_rw_io This will be used by the server in order to manage RDMA reads and writes. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect_socket.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index 148e8dbf1254..d7f3b25c022d 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -6,6 +6,8 @@ #ifndef __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_SOCKET_H__ #define __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_SOCKET_H__ +#include + enum smbdirect_socket_status { SMBDIRECT_SOCKET_CREATED, SMBDIRECT_SOCKET_CONNECTING, @@ -273,4 +275,18 @@ struct smbdirect_recv_io { u8 packet[]; }; +struct smbdirect_rw_io { + struct smbdirect_socket *socket; + struct ib_cqe cqe; + + struct list_head list; + + int error; + struct completion *completion; + + struct rdma_rw_ctx rdma_ctx; + struct sg_table sgt; + struct scatterlist sg_list[]; +}; + #endif /* __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_SOCKET_H__ */ From ec76e3cc6bbcb17815a4bfa6450d4bae1e708c9b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 11 Aug 2025 15:57:04 +0200 Subject: [PATCH 010/159] smb: smbdirect: introduce smbdirect_socket.recv_io.{posted,credits} This will be used by client and server soon in order to maintain the state of posted recv_io messages and granted credits. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect_socket.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index d7f3b25c022d..1abfcd230f9a 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -135,6 +135,23 @@ struct smbdirect_socket { spinlock_t lock; } free; + /* + * The state for posted recv_io messages + * and the refill work struct. + */ + struct { + atomic_t count; + struct work_struct refill_work; + } posted; + + /* + * The credit state for the recv side + */ + struct { + u16 target; + atomic_t count; + } credits; + /* * The list of arrived non-empty smbdirect_recv_io * structures @@ -204,6 +221,10 @@ static __always_inline void smbdirect_socket_init(struct smbdirect_socket *sc) INIT_LIST_HEAD(&sc->recv_io.free.list); spin_lock_init(&sc->recv_io.free.lock); + atomic_set(&sc->recv_io.posted.count, 0); + + atomic_set(&sc->recv_io.credits.count, 0); + INIT_LIST_HEAD(&sc->recv_io.reassembly.list); spin_lock_init(&sc->recv_io.reassembly.lock); init_waitqueue_head(&sc->recv_io.reassembly.wait_queue); From 932fa15c3726459d0f996893262af33b9f7dc121 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 14 Aug 2025 19:12:38 +0200 Subject: [PATCH 011/159] smb: smbdirect: introduce smbdirect_socket_parameters.{resolve_{addr,route},rdma_connect,negotiate}_timeout_msec These will be used instead of hardcoded values in client and server. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect.h b/fs/smb/common/smbdirect/smbdirect.h index b9a385344ff3..17aa08dd6aba 100644 --- a/fs/smb/common/smbdirect/smbdirect.h +++ b/fs/smb/common/smbdirect/smbdirect.h @@ -23,6 +23,10 @@ struct smbdirect_buffer_descriptor_v1 { * Some values are important for the upper layer. */ struct smbdirect_socket_parameters { + __u32 resolve_addr_timeout_msec; + __u32 resolve_route_timeout_msec; + __u32 rdma_connect_timeout_msec; + __u32 negotiate_timeout_msec; __u16 recv_credit_max; __u16 send_credit_target; __u32 max_send_size; From 8e34a763870dc48b69049c2a4ec032a21d66feb6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 19 Aug 2025 23:18:21 +0200 Subject: [PATCH 012/159] smb: smbdirect: introduce smbdirect_socket_parameters.{initiator_depth,responder_resources} This will make it easier to specify these from the outside of the core code later. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect.h b/fs/smb/common/smbdirect/smbdirect.h index 17aa08dd6aba..c3274bbb3c02 100644 --- a/fs/smb/common/smbdirect/smbdirect.h +++ b/fs/smb/common/smbdirect/smbdirect.h @@ -27,6 +27,8 @@ struct smbdirect_socket_parameters { __u32 resolve_route_timeout_msec; __u32 rdma_connect_timeout_msec; __u32 negotiate_timeout_msec; + __u8 initiator_depth; + __u8 responder_resources; __u16 recv_credit_max; __u16 send_credit_target; __u32 max_send_size; From 2baedb2026a5c01e79e9691540eea14d65f7277a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 Aug 2025 12:13:16 +0200 Subject: [PATCH 013/159] smb: smbdirect: introduce smbdirect_socket.rdma.legacy_iwarp This will be used by client and server soon. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect_socket.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index 1abfcd230f9a..3aaee6ca2934 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -50,6 +50,10 @@ struct smbdirect_socket { /* RDMA related */ struct { struct rdma_cm_id *cm_id; + /* + * This is for iWarp MPA v1 + */ + bool legacy_iwarp; } rdma; /* IB verbs related */ From 89bae05f9df68f827de0106760de53933083a391 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 15 Aug 2025 17:47:58 +0200 Subject: [PATCH 014/159] smb: smbdirect: introduce smbdirect_socket.idle.{keepalive,immediate_work,timer_work} This will allow client and server to use the common structures in order to share common functions later. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect_socket.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index 3aaee6ca2934..11e9b365ac96 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -41,6 +41,12 @@ const char *smbdirect_socket_status_string(enum smbdirect_socket_status status) return ""; } +enum smbdirect_keepalive_status { + SMBDIRECT_KEEPALIVE_NONE, + SMBDIRECT_KEEPALIVE_PENDING, + SMBDIRECT_KEEPALIVE_SENT +}; + struct smbdirect_socket { enum smbdirect_socket_status status; wait_queue_head_t status_wait; @@ -71,6 +77,15 @@ struct smbdirect_socket { struct smbdirect_socket_parameters parameters; + /* + * The state for keepalive and timeout handling + */ + struct { + enum smbdirect_keepalive_status keepalive; + struct work_struct immediate_work; + struct delayed_work timer_work; + } idle; + /* * The state for posted send buffers */ From 6889d2f5caa69ff4f523ef11a207fcaedaff8c7e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 19 Aug 2025 13:52:29 +0200 Subject: [PATCH 015/159] smb: smbdirect: introduce smbdirect_socket.statistics These will be used by the client and maybe shared code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect_socket.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index 11e9b365ac96..649d66cd4a83 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -218,6 +218,17 @@ struct smbdirect_socket { wait_queue_head_t wait_queue; } credits; } rw_io; + + /* + * For debug purposes + */ + struct { + u64 get_receive_buffer; + u64 put_receive_buffer; + u64 enqueue_reassembly_queue; + u64 dequeue_reassembly_queue; + u64 send_empty; + } statistics; }; static __always_inline void smbdirect_socket_init(struct smbdirect_socket *sc) From 6c5b0f9253d7f15722db22da28cd49ab34252214 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 12:22:24 +0200 Subject: [PATCH 016/159] smb: smbdirect: introduce smbdirect_socket.workqueue The client currently used a per socket workqueue because it can block in a work function waiting for credits. So we use a per socket pointer in order to prepare common code. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect_socket.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index 649d66cd4a83..b0efa5a26016 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -51,6 +51,14 @@ struct smbdirect_socket { enum smbdirect_socket_status status; wait_queue_head_t status_wait; + /* + * This points to the workqueue to + * be used for this socket. + * It can be per socket (on the client) + * or point to a global workqueue (on the server) + */ + struct workqueue_struct *workqueue; + struct work_struct disconnect_work; /* RDMA related */ From 02c39c0121d209117cb10b76df0b960f546b72e3 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 Aug 2025 16:16:47 +0200 Subject: [PATCH 017/159] smb: smbdirect: introduce struct smbdirect_mr_io This will be used by the client in order to maintain memory registrations. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect_socket.h | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index b0efa5a26016..f220891ab290 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -334,6 +334,32 @@ struct smbdirect_recv_io { u8 packet[]; }; +enum smbdirect_mr_state { + SMBDIRECT_MR_READY, + SMBDIRECT_MR_REGISTERED, + SMBDIRECT_MR_INVALIDATED, + SMBDIRECT_MR_ERROR +}; + +struct smbdirect_mr_io { + struct smbdirect_socket *socket; + struct ib_cqe cqe; + + struct list_head list; + + enum smbdirect_mr_state state; + struct ib_mr *mr; + struct sg_table sgt; + enum dma_data_direction dir; + union { + struct ib_reg_wr wr; + struct ib_send_wr inv_wr; + }; + + bool need_invalidate; + struct completion invalidate_done; +}; + struct smbdirect_rw_io { struct smbdirect_socket *socket; struct ib_cqe cqe; From 41e5086905a3c37c3e5b716192b2dcd719ad8ef5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 Aug 2025 23:50:42 +0200 Subject: [PATCH 018/159] smb: smbdirect: introduce smbdirect_socket_parameters.max_frmr_depth This will be used by the client... Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect.h | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/smb/common/smbdirect/smbdirect.h b/fs/smb/common/smbdirect/smbdirect.h index c3274bbb3c02..05cc6a9d0ccd 100644 --- a/fs/smb/common/smbdirect/smbdirect.h +++ b/fs/smb/common/smbdirect/smbdirect.h @@ -36,6 +36,7 @@ struct smbdirect_socket_parameters { __u32 max_recv_size; __u32 max_fragmented_recv_size; __u32 max_read_write_size; + __u32 max_frmr_depth; __u32 keepalive_interval_msec; __u32 keepalive_timeout_msec; } __packed; From ed3350f09d2c0234c59910ef1655cb9cbe17b0ca Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 19 Aug 2025 09:34:27 +0200 Subject: [PATCH 019/159] smb: smbdirect: introduce smbdirect_socket.mr_io.* This will be used by the client and will allow us to move to common code... Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect_socket.h | 45 ++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index f220891ab290..5d403b1becea 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -206,6 +206,44 @@ struct smbdirect_socket { } reassembly; } recv_io; + /* + * The state for Memory registrations on the client + */ + struct { + enum ib_mr_type type; + + /* + * The list of free smbdirect_mr_io + * structures + */ + struct { + struct list_head list; + spinlock_t lock; + } all; + + /* + * The number of available MRs ready for memory registration + */ + struct { + atomic_t count; + wait_queue_head_t wait_queue; + } ready; + + /* + * The number of used MRs + */ + struct { + atomic_t count; + } used; + + struct work_struct recovery_work; + + /* Used by transport to wait until all MRs are returned */ + struct { + wait_queue_head_t wait_queue; + } cleanup; + } mr_io; + /* * The state for RDMA read/write requests on the server */ @@ -269,6 +307,13 @@ static __always_inline void smbdirect_socket_init(struct smbdirect_socket *sc) atomic_set(&sc->rw_io.credits.count, 0); init_waitqueue_head(&sc->rw_io.credits.wait_queue); + + spin_lock_init(&sc->mr_io.all.lock); + INIT_LIST_HEAD(&sc->mr_io.all.list); + atomic_set(&sc->mr_io.ready.count, 0); + init_waitqueue_head(&sc->mr_io.ready.wait_queue); + atomic_set(&sc->mr_io.used.count, 0); + init_waitqueue_head(&sc->mr_io.cleanup.wait_queue); } struct smbdirect_send_io { From 6920b4ad49fc7ff5b99a0dcff8e9612753a7a876 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 26 Aug 2025 16:30:32 +0200 Subject: [PATCH 020/159] smb: smbdirect: let smbdirect_socket_init() initialize all [delayed_]work_structs as disabled This safer to start with and allows common code not care about if the caller uses these or not. E.g. sc->mr_io.recovery_work is only used on the client... Note disable_[delayed_]work_sync() requires a valid function pointer in INIT_[DELAYED_]WORK(). The non _sync() version don't require it, but as we need to use the _sync() version on cleanup we better use it here too, it won't block anyway here... Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect_socket.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index 5d403b1becea..14f6e6d2035f 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -277,6 +277,14 @@ struct smbdirect_socket { } statistics; }; +static void __smbdirect_socket_disabled_work(struct work_struct *work) +{ + /* + * Should never be called as disable_[delayed_]work_sync() was used. + */ + WARN_ON_ONCE(1); +} + static __always_inline void smbdirect_socket_init(struct smbdirect_socket *sc) { /* @@ -287,6 +295,14 @@ static __always_inline void smbdirect_socket_init(struct smbdirect_socket *sc) init_waitqueue_head(&sc->status_wait); + INIT_WORK(&sc->disconnect_work, __smbdirect_socket_disabled_work); + disable_work_sync(&sc->disconnect_work); + + INIT_WORK(&sc->idle.immediate_work, __smbdirect_socket_disabled_work); + disable_work_sync(&sc->idle.immediate_work); + INIT_DELAYED_WORK(&sc->idle.timer_work, __smbdirect_socket_disabled_work); + disable_delayed_work_sync(&sc->idle.timer_work); + atomic_set(&sc->send_io.credits.count, 0); init_waitqueue_head(&sc->send_io.credits.wait_queue); @@ -298,6 +314,8 @@ static __always_inline void smbdirect_socket_init(struct smbdirect_socket *sc) spin_lock_init(&sc->recv_io.free.lock); atomic_set(&sc->recv_io.posted.count, 0); + INIT_WORK(&sc->recv_io.posted.refill_work, __smbdirect_socket_disabled_work); + disable_work_sync(&sc->recv_io.posted.refill_work); atomic_set(&sc->recv_io.credits.count, 0); @@ -313,6 +331,8 @@ static __always_inline void smbdirect_socket_init(struct smbdirect_socket *sc) atomic_set(&sc->mr_io.ready.count, 0); init_waitqueue_head(&sc->mr_io.ready.wait_queue); atomic_set(&sc->mr_io.used.count, 0); + INIT_WORK(&sc->mr_io.recovery_work, __smbdirect_socket_disabled_work); + disable_work_sync(&sc->mr_io.recovery_work); init_waitqueue_head(&sc->mr_io.cleanup.wait_queue); } From ef71f1e046489c77a2f7d012edc762fba0a7aadc Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 20 Aug 2025 11:25:06 +0200 Subject: [PATCH 021/159] smb: client: fix sending the iwrap custom IRD/ORD negotiation messages Do a real negotiation and check the servers initiator_depth and responder_resources. This should use big endian in order to be useful. I have captures of windows clients showing this. The fact that we used little endian up to now means that we sent very large numbers and the negotiation with the server truncated them to the server limits. Note the reason why this uses u8 for initiator_depth and responder_resources is that the rdma layer also uses it. The inconsitency regarding the initiator_depth and responder_resources values being reversed for iwarp devices in RDMA_CM_EVENT_ESTABLISHED should also be fixed later, but for now we should fix it. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Cc: linux-rdma@vger.kernel.org Fixes: c7398583340a ("CIFS: SMBD: Implement RDMA memory registration") Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 110 ++++++++++++++++++++++++++++++++++---- fs/smb/client/smbdirect.h | 4 +- 2 files changed, 103 insertions(+), 11 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index e0fce5033004..6480945c2459 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -179,6 +179,8 @@ static int smbd_conn_upcall( struct smbd_connection *info = id->context; struct smbdirect_socket *sc = &info->socket; const char *event_name = rdma_event_msg(event->event); + u8 peer_initiator_depth; + u8 peer_responder_resources; log_rdma_event(INFO, "event=%s status=%d\n", event_name, event->status); @@ -204,6 +206,85 @@ static int smbd_conn_upcall( case RDMA_CM_EVENT_ESTABLISHED: log_rdma_event(INFO, "connected event=%s\n", event_name); + + /* + * Here we work around an inconsistency between + * iWarp and other devices (at least rxe and irdma using RoCEv2) + */ + if (rdma_protocol_iwarp(id->device, id->port_num)) { + /* + * iWarp devices report the peer's values + * with the perspective of the peer here. + * Tested with siw and irdma (in iwarp mode) + * We need to change to our perspective here, + * so we need to switch the values. + */ + peer_initiator_depth = event->param.conn.responder_resources; + peer_responder_resources = event->param.conn.initiator_depth; + } else { + /* + * Non iWarp devices report the peer's values + * already changed to our perspective here. + * Tested with rxe and irdma (in roce mode). + */ + peer_initiator_depth = event->param.conn.initiator_depth; + peer_responder_resources = event->param.conn.responder_resources; + } + if (rdma_protocol_iwarp(id->device, id->port_num) && + event->param.conn.private_data_len == 8) { + /* + * Legacy clients with only iWarp MPA v1 support + * need a private blob in order to negotiate + * the IRD/ORD values. + */ + const __be32 *ird_ord_hdr = event->param.conn.private_data; + u32 ird32 = be32_to_cpu(ird_ord_hdr[0]); + u32 ord32 = be32_to_cpu(ird_ord_hdr[1]); + + /* + * cifs.ko sends the legacy IRD/ORD negotiation + * event if iWarp MPA v2 was used. + * + * Here we check that the values match and only + * mark the client as legacy if they don't match. + */ + if ((u32)event->param.conn.initiator_depth != ird32 || + (u32)event->param.conn.responder_resources != ord32) { + /* + * There are broken clients (old cifs.ko) + * using little endian and also + * struct rdma_conn_param only uses u8 + * for initiator_depth and responder_resources, + * so we truncate the value to U8_MAX. + * + * smb_direct_accept_client() will then + * do the real negotiation in order to + * select the minimum between client and + * server. + */ + ird32 = min_t(u32, ird32, U8_MAX); + ord32 = min_t(u32, ord32, U8_MAX); + + info->legacy_iwarp = true; + peer_initiator_depth = (u8)ird32; + peer_responder_resources = (u8)ord32; + } + } + + /* + * negotiate the value by using the minimum + * between client and server if the client provided + * non 0 values. + */ + if (peer_initiator_depth != 0) + info->initiator_depth = + min_t(u8, info->initiator_depth, + peer_initiator_depth); + if (peer_responder_resources != 0) + info->responder_resources = + min_t(u8, info->responder_resources, + peer_responder_resources); + sc->status = SMBDIRECT_SOCKET_CONNECTED; wake_up_interruptible(&info->status_wait); break; @@ -1551,7 +1632,7 @@ static struct smbd_connection *_smbd_get_connection( struct ib_qp_init_attr qp_attr; struct sockaddr_in *addr_in = (struct sockaddr_in *) dstaddr; struct ib_port_immutable port_immutable; - u32 ird_ord_hdr[2]; + __be32 ird_ord_hdr[2]; info = kzalloc(sizeof(struct smbd_connection), GFP_KERNEL); if (!info) @@ -1559,6 +1640,9 @@ static struct smbd_connection *_smbd_get_connection( sc = &info->socket; sp = &sc->parameters; + info->initiator_depth = 1; + info->responder_resources = SMBD_CM_RESPONDER_RESOURCES; + sc->status = SMBDIRECT_SOCKET_CONNECTING; rc = smbd_ia_open(info, dstaddr, port); if (rc) { @@ -1639,22 +1723,22 @@ static struct smbd_connection *_smbd_get_connection( } sc->ib.qp = sc->rdma.cm_id->qp; - memset(&conn_param, 0, sizeof(conn_param)); - conn_param.initiator_depth = 0; - - conn_param.responder_resources = - min(sc->ib.dev->attrs.max_qp_rd_atom, - SMBD_CM_RESPONDER_RESOURCES); - info->responder_resources = conn_param.responder_resources; + info->responder_resources = + min_t(u8, info->responder_resources, + sc->ib.dev->attrs.max_qp_rd_atom); log_rdma_mr(INFO, "responder_resources=%d\n", info->responder_resources); + memset(&conn_param, 0, sizeof(conn_param)); + conn_param.initiator_depth = info->initiator_depth; + conn_param.responder_resources = info->responder_resources; + /* Need to send IRD/ORD in private data for iWARP */ sc->ib.dev->ops.get_port_immutable( sc->ib.dev, sc->rdma.cm_id->port_num, &port_immutable); if (port_immutable.core_cap_flags & RDMA_CORE_PORT_IWARP) { - ird_ord_hdr[0] = info->responder_resources; - ird_ord_hdr[1] = 1; + ird_ord_hdr[0] = cpu_to_be32(conn_param.responder_resources); + ird_ord_hdr[1] = cpu_to_be32(conn_param.initiator_depth); conn_param.private_data = ird_ord_hdr; conn_param.private_data_len = sizeof(ird_ord_hdr); } else { @@ -2121,6 +2205,12 @@ static int allocate_mr_list(struct smbd_connection *info) atomic_set(&info->mr_used_count, 0); init_waitqueue_head(&info->wait_for_mr_cleanup); INIT_WORK(&info->mr_recovery_work, smbd_mr_recovery_work); + + if (info->responder_resources == 0) { + log_rdma_mr(ERR, "responder_resources negotiated as 0\n"); + return -EINVAL; + } + /* Allocate more MRs (2x) than hardware responder_resources */ for (i = 0; i < info->responder_resources * 2; i++) { smbdirect_mr = kzalloc(sizeof(*smbdirect_mr), GFP_KERNEL); diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index e45aa9ddd71d..4ca9b2b2c57f 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -67,7 +67,9 @@ struct smbd_connection { /* Memory registrations */ /* Maximum number of RDMA read/write outstanding on this connection */ - int responder_resources; + bool legacy_iwarp; + u8 initiator_depth; + u8 responder_resources; /* Maximum number of pages in a single RDMA write/read on this connection */ int max_frmr_depth; /* From 58dfba8a2d4eb6defc6e710196b053abdaf6cd79 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Aug 2025 18:48:13 +0200 Subject: [PATCH 022/159] smb: client/smbdirect: replace SMBDIRECT_SOCKET_CONNECTING with more detailed states The process of reaching a functional connection represented by SMBDIRECT_SOCKET_CONNECTED, is more complex than using a single SMBDIRECT_SOCKET_CONNECTING state. This will allow us to remove a lot of special variables and completions in the following commits. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 73 ++++++++++++++++++++-- fs/smb/common/smbdirect/smbdirect_socket.h | 42 +++++++++++-- 2 files changed, 103 insertions(+), 12 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 6480945c2459..e4abc1a9564a 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -161,9 +161,36 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) container_of(work, struct smbd_connection, disconnect_work); struct smbdirect_socket *sc = &info->socket; - if (sc->status == SMBDIRECT_SOCKET_CONNECTED) { + switch (sc->status) { + case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: + case SMBDIRECT_SOCKET_NEGOTIATE_RUNNING: + case SMBDIRECT_SOCKET_NEGOTIATE_FAILED: + case SMBDIRECT_SOCKET_CONNECTED: sc->status = SMBDIRECT_SOCKET_DISCONNECTING; rdma_disconnect(sc->rdma.cm_id); + break; + + case SMBDIRECT_SOCKET_CREATED: + case SMBDIRECT_SOCKET_RESOLVE_ADDR_NEEDED: + case SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING: + case SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED: + case SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED: + case SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING: + case SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED: + case SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED: + case SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING: + case SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED: + /* + * rdma_connect() never reached + * RDMA_CM_EVENT_ESTABLISHED + */ + sc->status = SMBDIRECT_SOCKET_DISCONNECTED; + break; + + case SMBDIRECT_SOCKET_DISCONNECTING: + case SMBDIRECT_SOCKET_DISCONNECTED: + case SMBDIRECT_SOCKET_DESTROYED: + break; } } @@ -187,19 +214,31 @@ static int smbd_conn_upcall( switch (event->event) { case RDMA_CM_EVENT_ADDR_RESOLVED: + WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING); + sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED; + info->ri_rc = 0; + complete(&info->ri_done); + break; + case RDMA_CM_EVENT_ROUTE_RESOLVED: + WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING); + sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED; info->ri_rc = 0; complete(&info->ri_done); break; case RDMA_CM_EVENT_ADDR_ERROR: log_rdma_event(ERR, "connecting failed event=%s\n", event_name); + WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING); + sc->status = SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED; info->ri_rc = -EHOSTUNREACH; complete(&info->ri_done); break; case RDMA_CM_EVENT_ROUTE_ERROR: log_rdma_event(ERR, "connecting failed event=%s\n", event_name); + WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING); + sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED; info->ri_rc = -ENETUNREACH; complete(&info->ri_done); break; @@ -285,7 +324,8 @@ static int smbd_conn_upcall( min_t(u8, info->responder_resources, peer_responder_resources); - sc->status = SMBDIRECT_SOCKET_CONNECTED; + WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING); + sc->status = SMBDIRECT_SOCKET_NEGOTIATE_NEEDED; wake_up_interruptible(&info->status_wait); break; @@ -293,7 +333,8 @@ static int smbd_conn_upcall( case RDMA_CM_EVENT_UNREACHABLE: case RDMA_CM_EVENT_REJECTED: log_rdma_event(ERR, "connecting failed event=%s\n", event_name); - sc->status = SMBDIRECT_SOCKET_DISCONNECTED; + WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING); + sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED; wake_up_interruptible(&info->status_wait); break; @@ -565,6 +606,12 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) info->negotiate_done = process_negotiation_response(response, wc->byte_len); put_receive_buffer(info, response); + WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_NEGOTIATE_RUNNING); + if (!info->negotiate_done) + sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED; + else + sc->status = SMBDIRECT_SOCKET_CONNECTED; + complete(&info->negotiate_completion); return; @@ -655,6 +702,7 @@ static struct rdma_cm_id *smbd_create_id( struct smbd_connection *info, struct sockaddr *dstaddr, int port) { + struct smbdirect_socket *sc = &info->socket; struct rdma_cm_id *id; int rc; __be16 *sport; @@ -677,6 +725,8 @@ static struct rdma_cm_id *smbd_create_id( init_completion(&info->ri_done); info->ri_rc = -ETIMEDOUT; + WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_NEEDED); + sc->status = SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING; rc = rdma_resolve_addr(id, NULL, (struct sockaddr *)dstaddr, RDMA_RESOLVE_TIMEOUT); if (rc) { @@ -697,6 +747,8 @@ static struct rdma_cm_id *smbd_create_id( } info->ri_rc = -ETIMEDOUT; + WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED); + sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING; rc = rdma_resolve_route(id, RDMA_RESOLVE_TIMEOUT); if (rc) { log_rdma_event(ERR, "rdma_resolve_route() failed %i\n", rc); @@ -743,6 +795,9 @@ static int smbd_ia_open( struct smbdirect_socket *sc = &info->socket; int rc; + WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_CREATED); + sc->status = SMBDIRECT_SOCKET_RESOLVE_ADDR_NEEDED; + sc->rdma.cm_id = smbd_create_id(info, dstaddr, port); if (IS_ERR(sc->rdma.cm_id)) { rc = PTR_ERR(sc->rdma.cm_id); @@ -1184,6 +1239,9 @@ static int smbd_negotiate(struct smbd_connection *info) int rc; struct smbdirect_recv_io *response = get_receive_buffer(info); + WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_NEGOTIATE_NEEDED); + sc->status = SMBDIRECT_SOCKET_NEGOTIATE_RUNNING; + sc->recv_io.expected = SMBDIRECT_EXPECT_NEGOTIATE_REP; rc = smbd_post_recv(info, response); log_rdma_event(INFO, "smbd_post_recv rc=%d iov.addr=0x%llx iov.length=%u iov.lkey=0x%x\n", @@ -1643,7 +1701,7 @@ static struct smbd_connection *_smbd_get_connection( info->initiator_depth = 1; info->responder_resources = SMBD_CM_RESPONDER_RESOURCES; - sc->status = SMBDIRECT_SOCKET_CONNECTING; + sc->status = SMBDIRECT_SOCKET_CREATED; rc = smbd_ia_open(info, dstaddr, port); if (rc) { log_rdma_event(INFO, "smbd_ia_open rc=%d\n", rc); @@ -1755,6 +1813,9 @@ static struct smbd_connection *_smbd_get_connection( init_waitqueue_head(&info->status_wait); init_waitqueue_head(&sc->recv_io.reassembly.wait_queue); + + WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED); + sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING; rc = rdma_connect(sc->rdma.cm_id, &conn_param); if (rc) { log_rdma_event(ERR, "rdma_connect() failed with %i\n", rc); @@ -1763,10 +1824,10 @@ static struct smbd_connection *_smbd_get_connection( wait_event_interruptible_timeout( info->status_wait, - sc->status != SMBDIRECT_SOCKET_CONNECTING, + sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING, msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT)); - if (sc->status != SMBDIRECT_SOCKET_CONNECTED) { + if (sc->status != SMBDIRECT_SOCKET_NEGOTIATE_NEEDED) { log_rdma_event(ERR, "rdma_connect failed port=%d\n", port); goto rdma_connect_failed; } diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index 14f6e6d2035f..ced8c9f20cf5 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -10,9 +10,19 @@ enum smbdirect_socket_status { SMBDIRECT_SOCKET_CREATED, - SMBDIRECT_SOCKET_CONNECTING, - SMBDIRECT_SOCKET_CONNECTED, + SMBDIRECT_SOCKET_RESOLVE_ADDR_NEEDED, + SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING, + SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED, + SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED, + SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING, + SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED, + SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED, + SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING, + SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED, + SMBDIRECT_SOCKET_NEGOTIATE_NEEDED, + SMBDIRECT_SOCKET_NEGOTIATE_RUNNING, SMBDIRECT_SOCKET_NEGOTIATE_FAILED, + SMBDIRECT_SOCKET_CONNECTED, SMBDIRECT_SOCKET_DISCONNECTING, SMBDIRECT_SOCKET_DISCONNECTED, SMBDIRECT_SOCKET_DESTROYED @@ -24,12 +34,32 @@ const char *smbdirect_socket_status_string(enum smbdirect_socket_status status) switch (status) { case SMBDIRECT_SOCKET_CREATED: return "CREATED"; - case SMBDIRECT_SOCKET_CONNECTING: - return "CONNECTING"; - case SMBDIRECT_SOCKET_CONNECTED: - return "CONNECTED"; + case SMBDIRECT_SOCKET_RESOLVE_ADDR_NEEDED: + return "RESOLVE_ADDR_NEEDED"; + case SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING: + return "RESOLVE_ADDR_RUNNING"; + case SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED: + return "RESOLVE_ADDR_FAILED"; + case SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED: + return "RESOLVE_ROUTE_NEEDED"; + case SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING: + return "RESOLVE_ROUTE_RUNNING"; + case SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED: + return "RESOLVE_ROUTE_FAILED"; + case SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED: + return "RDMA_CONNECT_NEEDED"; + case SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING: + return "RDMA_CONNECT_RUNNING"; + case SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED: + return "RDMA_CONNECT_FAILED"; + case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: + return "NEGOTIATE_NEEDED"; + case SMBDIRECT_SOCKET_NEGOTIATE_RUNNING: + return "NEGOTIATE_RUNNING"; case SMBDIRECT_SOCKET_NEGOTIATE_FAILED: return "NEGOTIATE_FAILED"; + case SMBDIRECT_SOCKET_CONNECTED: + return "CONNECTED"; case SMBDIRECT_SOCKET_DISCONNECTING: return "DISCONNECTING"; case SMBDIRECT_SOCKET_DISCONNECTED: From cc678b8a89291ef55c8dfc01391506f1234c6cae Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 28 Aug 2025 10:39:56 +0200 Subject: [PATCH 023/159] smb: client/smbdirect: introduce SMBDIRECT_SOCKET_ERROR This will be used to turn SMBDIRECT_SOCKET_CONNECTED into an error within smbd_disconnect_rdma_connection() on the client and smb_direct_disconnect_rdma_connection() on the server. We do this in a single commit with the client as otherwise it won't build because the enum value is not handled in the switch statement. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 1 + fs/smb/common/smbdirect/smbdirect_socket.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index e4abc1a9564a..09f8b12dd4f1 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -166,6 +166,7 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) case SMBDIRECT_SOCKET_NEGOTIATE_RUNNING: case SMBDIRECT_SOCKET_NEGOTIATE_FAILED: case SMBDIRECT_SOCKET_CONNECTED: + case SMBDIRECT_SOCKET_ERROR: sc->status = SMBDIRECT_SOCKET_DISCONNECTING; rdma_disconnect(sc->rdma.cm_id); break; diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index ced8c9f20cf5..5e25abc02364 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -23,6 +23,7 @@ enum smbdirect_socket_status { SMBDIRECT_SOCKET_NEGOTIATE_RUNNING, SMBDIRECT_SOCKET_NEGOTIATE_FAILED, SMBDIRECT_SOCKET_CONNECTED, + SMBDIRECT_SOCKET_ERROR, SMBDIRECT_SOCKET_DISCONNECTING, SMBDIRECT_SOCKET_DISCONNECTED, SMBDIRECT_SOCKET_DESTROYED @@ -60,6 +61,8 @@ const char *smbdirect_socket_status_string(enum smbdirect_socket_status status) return "NEGOTIATE_FAILED"; case SMBDIRECT_SOCKET_CONNECTED: return "CONNECTED"; + case SMBDIRECT_SOCKET_ERROR: + return "ERROR"; case SMBDIRECT_SOCKET_DISCONNECTING: return "DISCONNECTING"; case SMBDIRECT_SOCKET_DISCONNECTED: From f5b893edde7bcd15246dfeefd25082fe637db647 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 28 Aug 2025 12:11:02 +0200 Subject: [PATCH 024/159] smb: smbdirect: introduce smbdirect_socket.first_error This will be used when a connected conection gets the first error. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect_socket.h | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index 5e25abc02364..db22a1d0546b 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -83,6 +83,7 @@ enum smbdirect_keepalive_status { struct smbdirect_socket { enum smbdirect_socket_status status; wait_queue_head_t status_wait; + int first_error; /* * This points to the workqueue to From afff34dc025b5f0476645f44b4d9cbc83dd54e71 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 8 Sep 2025 12:14:43 +0200 Subject: [PATCH 025/159] smb: client: adjust smbdirect related output of cifs_debug_data_proc_show() For the reader it is not obvious that the counter values are displayed in hex as there's no leading '0x' before '%x'. So changed them to %u instead and added '0x' for non-counter values and also a string for the status. Note this generates some checkpatch warnings like this: WARNING: quoted string split across lines #45: FILE: fs/smb/client/cifs_debug.c:460: + seq_printf(m, "\nSMBDirect protocol version: 0x%x " + "transport status: %s (%u)", But I'll leave this is the current style in the related code... Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/cifs_debug.c | 47 +++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index 2337cf795db3..265e063e95bd 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -456,55 +456,56 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) sc = &server->smbd_conn->socket; sp = &sc->parameters; - seq_printf(m, "\nSMBDirect (in hex) protocol version: %x " - "transport status: %x", + seq_printf(m, "\nSMBDirect protocol version: 0x%x " + "transport status: %s (%u)", server->smbd_conn->protocol, - server->smbd_conn->socket.status); - seq_printf(m, "\nConn receive_credit_max: %x " - "send_credit_target: %x max_send_size: %x", + smbdirect_socket_status_string(sc->status), + sc->status); + seq_printf(m, "\nConn receive_credit_max: %u " + "send_credit_target: %u max_send_size: %u", sp->recv_credit_max, sp->send_credit_target, sp->max_send_size); - seq_printf(m, "\nConn max_fragmented_recv_size: %x " - "max_fragmented_send_size: %x max_receive_size:%x", + seq_printf(m, "\nConn max_fragmented_recv_size: %u " + "max_fragmented_send_size: %u max_receive_size:%u", sp->max_fragmented_recv_size, sp->max_fragmented_send_size, sp->max_recv_size); - seq_printf(m, "\nConn keep_alive_interval: %x " - "max_readwrite_size: %x rdma_readwrite_threshold: %x", + seq_printf(m, "\nConn keep_alive_interval: %u " + "max_readwrite_size: %u rdma_readwrite_threshold: %u", sp->keepalive_interval_msec * 1000, sp->max_read_write_size, server->smbd_conn->rdma_readwrite_threshold); - seq_printf(m, "\nDebug count_get_receive_buffer: %x " - "count_put_receive_buffer: %x count_send_empty: %x", + seq_printf(m, "\nDebug count_get_receive_buffer: %u " + "count_put_receive_buffer: %u count_send_empty: %u", server->smbd_conn->count_get_receive_buffer, server->smbd_conn->count_put_receive_buffer, server->smbd_conn->count_send_empty); - seq_printf(m, "\nRead Queue count_reassembly_queue: %x " - "count_enqueue_reassembly_queue: %x " - "count_dequeue_reassembly_queue: %x " - "reassembly_data_length: %x " - "reassembly_queue_length: %x", + seq_printf(m, "\nRead Queue count_reassembly_queue: %u " + "count_enqueue_reassembly_queue: %u " + "count_dequeue_reassembly_queue: %u " + "reassembly_data_length: %u " + "reassembly_queue_length: %u", server->smbd_conn->count_reassembly_queue, server->smbd_conn->count_enqueue_reassembly_queue, server->smbd_conn->count_dequeue_reassembly_queue, sc->recv_io.reassembly.data_length, sc->recv_io.reassembly.queue_length); - seq_printf(m, "\nCurrent Credits send_credits: %x " - "receive_credits: %x receive_credit_target: %x", + seq_printf(m, "\nCurrent Credits send_credits: %u " + "receive_credits: %u receive_credit_target: %u", atomic_read(&server->smbd_conn->send_credits), atomic_read(&server->smbd_conn->receive_credits), server->smbd_conn->receive_credit_target); - seq_printf(m, "\nPending send_pending: %x ", + seq_printf(m, "\nPending send_pending: %u ", atomic_read(&server->smbd_conn->send_pending)); - seq_printf(m, "\nReceive buffers count_receive_queue: %x ", + seq_printf(m, "\nReceive buffers count_receive_queue: %u ", server->smbd_conn->count_receive_queue); - seq_printf(m, "\nMR responder_resources: %x " - "max_frmr_depth: %x mr_type: %x", + seq_printf(m, "\nMR responder_resources: %u " + "max_frmr_depth: %u mr_type: 0x%x", server->smbd_conn->responder_resources, server->smbd_conn->max_frmr_depth, server->smbd_conn->mr_type); - seq_printf(m, "\nMR mr_ready_count: %x mr_used_count: %x", + seq_printf(m, "\nMR mr_ready_count: %u mr_used_count: %u", atomic_read(&server->smbd_conn->mr_ready_count), atomic_read(&server->smbd_conn->mr_used_count)); skip_rdma: From 00e4c7a87d1fa8d5668e2922578ff4aff6efb8a2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Aug 2025 18:48:14 +0200 Subject: [PATCH 026/159] smb: client: use status_wait and SMBDIRECT_SOCKET_NEGOTIATE_RUNNING for completion We can use the state change from SMBDIRECT_SOCKET_NEGOTIATE_RUNNING to SMBDIRECT_SOCKET_CONNECTED or SMBDIRECT_SOCKET_NEGOTIATE_FAILED in order to notify the caller if the negotiation is over. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 19 ++++++++++--------- fs/smb/client/smbdirect.h | 3 --- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 09f8b12dd4f1..cfb45bc99376 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -582,6 +582,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) u32 data_offset = 0; u32 data_length = 0; u32 remaining_data_length = 0; + bool negotiate_done = false; log_rdma_recv(INFO, "response=0x%p type=%d wc status=%d wc opcode %d byte_len=%d pkey_index=%u\n", response, sc->recv_io.expected, wc->status, wc->opcode, @@ -604,16 +605,16 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) case SMBDIRECT_EXPECT_NEGOTIATE_REP: dump_smbdirect_negotiate_resp(smbdirect_recv_io_payload(response)); sc->recv_io.reassembly.full_packet_received = true; - info->negotiate_done = + negotiate_done = process_negotiation_response(response, wc->byte_len); put_receive_buffer(info, response); WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_NEGOTIATE_RUNNING); - if (!info->negotiate_done) + if (!negotiate_done) sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED; else sc->status = SMBDIRECT_SOCKET_CONNECTED; - complete(&info->negotiate_completion); + wake_up_interruptible(&info->status_wait); return; /* SMBD data transfer packet */ @@ -1253,17 +1254,17 @@ static int smbd_negotiate(struct smbd_connection *info) return rc; } - init_completion(&info->negotiate_completion); - info->negotiate_done = false; rc = smbd_post_send_negotiate_req(info); if (rc) return rc; - rc = wait_for_completion_interruptible_timeout( - &info->negotiate_completion, SMBD_NEGOTIATE_TIMEOUT * HZ); - log_rdma_event(INFO, "wait_for_completion_timeout rc=%d\n", rc); + rc = wait_event_interruptible_timeout( + info->status_wait, + sc->status != SMBDIRECT_SOCKET_NEGOTIATE_RUNNING, + secs_to_jiffies(SMBD_NEGOTIATE_TIMEOUT)); + log_rdma_event(INFO, "wait_event_interruptible_timeout rc=%d\n", rc); - if (info->negotiate_done) + if (sc->status == SMBDIRECT_SOCKET_CONNECTED) return 0; if (rc == 0) diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index 4ca9b2b2c57f..c9b0c6b61e7e 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -49,9 +49,6 @@ struct smbd_connection { struct completion ri_done; wait_queue_head_t status_wait; - struct completion negotiate_completion; - bool negotiate_done; - struct work_struct disconnect_work; struct work_struct post_send_credits_work; From 4ff3fa4e4aa78c3aa9083a8d448f8af4f0740df7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Aug 2025 18:48:15 +0200 Subject: [PATCH 027/159] smb: client: use status_wait and SMBDIRECT_SOCKET_RESOLVE_{ADDR,ROUTE}_RUNNING for completion We can use the state change from SMBDIRECT_SOCKET_RESOLVE_{ADDR,ROUTE}_RUNNING to the next state in order to wake the caller to do the next step. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 49 ++++++++++++++++++++++----------------- fs/smb/client/smbdirect.h | 2 -- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index cfb45bc99376..556beec3f430 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -217,31 +217,27 @@ static int smbd_conn_upcall( case RDMA_CM_EVENT_ADDR_RESOLVED: WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING); sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED; - info->ri_rc = 0; - complete(&info->ri_done); + wake_up_interruptible(&info->status_wait); break; case RDMA_CM_EVENT_ROUTE_RESOLVED: WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING); sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED; - info->ri_rc = 0; - complete(&info->ri_done); + wake_up_interruptible(&info->status_wait); break; case RDMA_CM_EVENT_ADDR_ERROR: log_rdma_event(ERR, "connecting failed event=%s\n", event_name); WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING); sc->status = SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED; - info->ri_rc = -EHOSTUNREACH; - complete(&info->ri_done); + wake_up_interruptible(&info->status_wait); break; case RDMA_CM_EVENT_ROUTE_ERROR: log_rdma_event(ERR, "connecting failed event=%s\n", event_name); WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING); sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED; - info->ri_rc = -ENETUNREACH; - complete(&info->ri_done); + wake_up_interruptible(&info->status_wait); break; case RDMA_CM_EVENT_ESTABLISHED: @@ -724,9 +720,6 @@ static struct rdma_cm_id *smbd_create_id( *sport = htons(port); - init_completion(&info->ri_done); - info->ri_rc = -ETIMEDOUT; - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_NEEDED); sc->status = SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING; rc = rdma_resolve_addr(id, NULL, (struct sockaddr *)dstaddr, @@ -735,20 +728,26 @@ static struct rdma_cm_id *smbd_create_id( log_rdma_event(ERR, "rdma_resolve_addr() failed %i\n", rc); goto out; } - rc = wait_for_completion_interruptible_timeout( - &info->ri_done, msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT)); + rc = wait_event_interruptible_timeout( + info->status_wait, + sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING, + msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT)); /* e.g. if interrupted returns -ERESTARTSYS */ if (rc < 0) { log_rdma_event(ERR, "rdma_resolve_addr timeout rc: %i\n", rc); goto out; } - rc = info->ri_rc; - if (rc) { + if (sc->status == SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING) { + rc = -ETIMEDOUT; + log_rdma_event(ERR, "rdma_resolve_addr() completed %i\n", rc); + goto out; + } + if (sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED) { + rc = -EHOSTUNREACH; log_rdma_event(ERR, "rdma_resolve_addr() completed %i\n", rc); goto out; } - info->ri_rc = -ETIMEDOUT; WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED); sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING; rc = rdma_resolve_route(id, RDMA_RESOLVE_TIMEOUT); @@ -756,15 +755,22 @@ static struct rdma_cm_id *smbd_create_id( log_rdma_event(ERR, "rdma_resolve_route() failed %i\n", rc); goto out; } - rc = wait_for_completion_interruptible_timeout( - &info->ri_done, msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT)); + rc = wait_event_interruptible_timeout( + info->status_wait, + sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING, + msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT)); /* e.g. if interrupted returns -ERESTARTSYS */ if (rc < 0) { log_rdma_event(ERR, "rdma_resolve_addr timeout rc: %i\n", rc); goto out; } - rc = info->ri_rc; - if (rc) { + if (sc->status == SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING) { + rc = -ETIMEDOUT; + log_rdma_event(ERR, "rdma_resolve_route() completed %i\n", rc); + goto out; + } + if (sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED) { + rc = -ENETUNREACH; log_rdma_event(ERR, "rdma_resolve_route() completed %i\n", rc); goto out; } @@ -1703,6 +1709,8 @@ static struct smbd_connection *_smbd_get_connection( info->initiator_depth = 1; info->responder_resources = SMBD_CM_RESPONDER_RESOURCES; + init_waitqueue_head(&info->status_wait); + sc->status = SMBDIRECT_SOCKET_CREATED; rc = smbd_ia_open(info, dstaddr, port); if (rc) { @@ -1813,7 +1821,6 @@ static struct smbd_connection *_smbd_get_connection( log_rdma_event(INFO, "connecting to IP %pI4 port %d\n", &addr_in->sin_addr, port); - init_waitqueue_head(&info->status_wait); init_waitqueue_head(&sc->recv_io.reassembly.wait_queue); WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED); diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index c9b0c6b61e7e..82b1d936e800 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -45,8 +45,6 @@ enum keep_alive_status { struct smbd_connection { struct smbdirect_socket socket; - int ri_rc; - struct completion ri_done; wait_queue_head_t status_wait; struct work_struct disconnect_work; From d9140ef074239408a1d991819811fadbbe781c79 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Aug 2025 18:48:17 +0200 Subject: [PATCH 028/159] smb: client: make use of smbdirect_socket.status_wait This will allow us to have common helper functions soon. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 32 ++++++++++++++++---------------- fs/smb/client/smbdirect.h | 2 -- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 556beec3f430..501c515ec04f 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -217,27 +217,27 @@ static int smbd_conn_upcall( case RDMA_CM_EVENT_ADDR_RESOLVED: WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING); sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED; - wake_up_interruptible(&info->status_wait); + wake_up_interruptible(&sc->status_wait); break; case RDMA_CM_EVENT_ROUTE_RESOLVED: WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING); sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED; - wake_up_interruptible(&info->status_wait); + wake_up_interruptible(&sc->status_wait); break; case RDMA_CM_EVENT_ADDR_ERROR: log_rdma_event(ERR, "connecting failed event=%s\n", event_name); WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING); sc->status = SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED; - wake_up_interruptible(&info->status_wait); + wake_up_interruptible(&sc->status_wait); break; case RDMA_CM_EVENT_ROUTE_ERROR: log_rdma_event(ERR, "connecting failed event=%s\n", event_name); WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING); sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED; - wake_up_interruptible(&info->status_wait); + wake_up_interruptible(&sc->status_wait); break; case RDMA_CM_EVENT_ESTABLISHED: @@ -323,7 +323,7 @@ static int smbd_conn_upcall( WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING); sc->status = SMBDIRECT_SOCKET_NEGOTIATE_NEEDED; - wake_up_interruptible(&info->status_wait); + wake_up_interruptible(&sc->status_wait); break; case RDMA_CM_EVENT_CONNECT_ERROR: @@ -332,7 +332,7 @@ static int smbd_conn_upcall( log_rdma_event(ERR, "connecting failed event=%s\n", event_name); WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING); sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED; - wake_up_interruptible(&info->status_wait); + wake_up_interruptible(&sc->status_wait); break; case RDMA_CM_EVENT_DEVICE_REMOVAL: @@ -341,12 +341,12 @@ static int smbd_conn_upcall( if (sc->status == SMBDIRECT_SOCKET_NEGOTIATE_FAILED) { log_rdma_event(ERR, "event=%s during negotiation\n", event_name); sc->status = SMBDIRECT_SOCKET_DISCONNECTED; - wake_up(&info->status_wait); + wake_up(&sc->status_wait); break; } sc->status = SMBDIRECT_SOCKET_DISCONNECTED; - wake_up_interruptible(&info->status_wait); + wake_up_interruptible(&sc->status_wait); wake_up_interruptible(&sc->recv_io.reassembly.wait_queue); wake_up_interruptible_all(&info->wait_send_queue); break; @@ -610,7 +610,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) else sc->status = SMBDIRECT_SOCKET_CONNECTED; - wake_up_interruptible(&info->status_wait); + wake_up_interruptible(&sc->status_wait); return; /* SMBD data transfer packet */ @@ -729,7 +729,7 @@ static struct rdma_cm_id *smbd_create_id( goto out; } rc = wait_event_interruptible_timeout( - info->status_wait, + sc->status_wait, sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING, msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT)); /* e.g. if interrupted returns -ERESTARTSYS */ @@ -756,7 +756,7 @@ static struct rdma_cm_id *smbd_create_id( goto out; } rc = wait_event_interruptible_timeout( - info->status_wait, + sc->status_wait, sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING, msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT)); /* e.g. if interrupted returns -ERESTARTSYS */ @@ -1265,7 +1265,7 @@ static int smbd_negotiate(struct smbd_connection *info) return rc; rc = wait_event_interruptible_timeout( - info->status_wait, + sc->status_wait, sc->status != SMBDIRECT_SOCKET_NEGOTIATE_RUNNING, secs_to_jiffies(SMBD_NEGOTIATE_TIMEOUT)); log_rdma_event(INFO, "wait_event_interruptible_timeout rc=%d\n", rc); @@ -1492,7 +1492,7 @@ void smbd_destroy(struct TCP_Server_Info *server) rdma_disconnect(sc->rdma.cm_id); log_rdma_event(INFO, "wait for transport being disconnected\n"); wait_event_interruptible( - info->status_wait, + sc->status_wait, sc->status == SMBDIRECT_SOCKET_DISCONNECTED); } @@ -1709,7 +1709,7 @@ static struct smbd_connection *_smbd_get_connection( info->initiator_depth = 1; info->responder_resources = SMBD_CM_RESPONDER_RESOURCES; - init_waitqueue_head(&info->status_wait); + init_waitqueue_head(&sc->status_wait); sc->status = SMBDIRECT_SOCKET_CREATED; rc = smbd_ia_open(info, dstaddr, port); @@ -1832,7 +1832,7 @@ static struct smbd_connection *_smbd_get_connection( } wait_event_interruptible_timeout( - info->status_wait, + sc->status_wait, sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING, msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT)); @@ -1889,7 +1889,7 @@ static struct smbd_connection *_smbd_get_connection( destroy_caches_and_workqueue(info); sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED; rdma_disconnect(sc->rdma.cm_id); - wait_event(info->status_wait, + wait_event(sc->status_wait, sc->status == SMBDIRECT_SOCKET_DISCONNECTED); allocate_cache_failed: diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index 82b1d936e800..f250241d2d24 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -45,8 +45,6 @@ enum keep_alive_status { struct smbd_connection { struct smbdirect_socket socket; - wait_queue_head_t status_wait; - struct work_struct disconnect_work; struct work_struct post_send_credits_work; From 5a0d5ae65c121decfac03c68a20343e75f636957 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 14 Aug 2025 10:06:50 +0200 Subject: [PATCH 029/159] smb: client: make only use of wake_up[_all]() in smbdirect.c wake_up_interruptible[_all]() doesn't wake up tasks waiting with wait_event(). So we better wake_up[_all]() in order to wake up all tasks in order to simplify the logic. As we currently don't use any wait_event_*_exclusive() it doesn't really matter if we use wake_up() or wake_up_all(). But in this patch I try to use wake_up() for expected situations and wake_up_all() for situations of a broken connection. So don't need to adjust things in future when we may use wait_event_*_exclusive() in order to wake up only one process that should make progress. Changing the wait_event_*() code in order to keep wait_event(), wait_event_interruptible() and wait_event_interruptible_timeout() or changing them to wait_event_killable(), wait_event_killable_timeout(), wait_event_killable_exclusive() is something to think about in a future patch. The goal here is to avoid that some tasks are not woken and freeze forever. Also note that this patch only changes the existing wake_up*() calls. Adding more wake_up*() calls for other wait queues is also deferred to a future patch. Link: https://lore.kernel.org/linux-cifs/13851363-0dc9-465c-9ced-3ede4904eef0@samba.org/T/#t Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 40 ++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 501c515ec04f..82d36fb248fd 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -217,27 +217,27 @@ static int smbd_conn_upcall( case RDMA_CM_EVENT_ADDR_RESOLVED: WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING); sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED; - wake_up_interruptible(&sc->status_wait); + wake_up(&sc->status_wait); break; case RDMA_CM_EVENT_ROUTE_RESOLVED: WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING); sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED; - wake_up_interruptible(&sc->status_wait); + wake_up(&sc->status_wait); break; case RDMA_CM_EVENT_ADDR_ERROR: log_rdma_event(ERR, "connecting failed event=%s\n", event_name); WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING); sc->status = SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED; - wake_up_interruptible(&sc->status_wait); + wake_up_all(&sc->status_wait); break; case RDMA_CM_EVENT_ROUTE_ERROR: log_rdma_event(ERR, "connecting failed event=%s\n", event_name); WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING); sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED; - wake_up_interruptible(&sc->status_wait); + wake_up_all(&sc->status_wait); break; case RDMA_CM_EVENT_ESTABLISHED: @@ -323,7 +323,7 @@ static int smbd_conn_upcall( WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING); sc->status = SMBDIRECT_SOCKET_NEGOTIATE_NEEDED; - wake_up_interruptible(&sc->status_wait); + wake_up(&sc->status_wait); break; case RDMA_CM_EVENT_CONNECT_ERROR: @@ -332,7 +332,7 @@ static int smbd_conn_upcall( log_rdma_event(ERR, "connecting failed event=%s\n", event_name); WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING); sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED; - wake_up_interruptible(&sc->status_wait); + wake_up_all(&sc->status_wait); break; case RDMA_CM_EVENT_DEVICE_REMOVAL: @@ -341,14 +341,14 @@ static int smbd_conn_upcall( if (sc->status == SMBDIRECT_SOCKET_NEGOTIATE_FAILED) { log_rdma_event(ERR, "event=%s during negotiation\n", event_name); sc->status = SMBDIRECT_SOCKET_DISCONNECTED; - wake_up(&sc->status_wait); + wake_up_all(&sc->status_wait); break; } sc->status = SMBDIRECT_SOCKET_DISCONNECTED; - wake_up_interruptible(&sc->status_wait); - wake_up_interruptible(&sc->recv_io.reassembly.wait_queue); - wake_up_interruptible_all(&info->wait_send_queue); + wake_up_all(&sc->status_wait); + wake_up_all(&sc->recv_io.reassembly.wait_queue); + wake_up_all(&info->wait_send_queue); break; default: @@ -525,7 +525,7 @@ static void smbd_post_send_credits(struct work_struct *work) struct smbdirect_socket *sc = &info->socket; if (sc->status != SMBDIRECT_SOCKET_CONNECTED) { - wake_up(&info->wait_receive_queues); + wake_up_all(&info->wait_receive_queues); return; } @@ -605,12 +605,14 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) process_negotiation_response(response, wc->byte_len); put_receive_buffer(info, response); WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_NEGOTIATE_RUNNING); - if (!negotiate_done) + if (!negotiate_done) { sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED; - else + wake_up_all(&sc->status_wait); + } else { sc->status = SMBDIRECT_SOCKET_CONNECTED; + wake_up(&sc->status_wait); + } - wake_up_interruptible(&sc->status_wait); return; /* SMBD data transfer packet */ @@ -653,7 +655,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) * We have new send credits granted from remote peer * If any sender is waiting for credits, unblock it */ - wake_up_interruptible(&info->wait_send_queue); + wake_up(&info->wait_send_queue); } log_incoming(INFO, "data flags %d data_offset %d data_length %d remaining_data_length %d\n", @@ -675,7 +677,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) */ if (data_length) { enqueue_reassembly(info, response, data_length); - wake_up_interruptible(&sc->recv_io.reassembly.wait_queue); + wake_up(&sc->recv_io.reassembly.wait_queue); } else put_receive_buffer(info, response); @@ -1536,7 +1538,7 @@ void smbd_destroy(struct TCP_Server_Info *server) * path when sending data, and then release memory registrations. */ log_rdma_event(INFO, "freeing mr list\n"); - wake_up_interruptible_all(&info->wait_mr); + wake_up_all(&info->wait_mr); while (atomic_read(&info->mr_used_count)) { cifs_server_unlock(server); msleep(1000); @@ -2235,7 +2237,7 @@ static void smbd_mr_recovery_work(struct work_struct *work) * get_mr() from the I/O issuing CPUs */ if (atomic_inc_return(&info->mr_ready_count) == 1) - wake_up_interruptible(&info->wait_mr); + wake_up(&info->wait_mr); } } @@ -2546,7 +2548,7 @@ int smbd_deregister_mr(struct smbd_mr *smbdirect_mr) smbdirect_mr->dir); smbdirect_mr->state = MR_READY; if (atomic_inc_return(&info->mr_ready_count) == 1) - wake_up_interruptible(&info->wait_mr); + wake_up(&info->wait_mr); } else /* * Schedule the work to do MR recovery for future I/Os MR From 7360778b6f962bd87472238204b5cf76d98e8122 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Aug 2025 15:10:52 +0200 Subject: [PATCH 030/159] smb: client: make use of smbdirect_socket_init() It's much safer to initialize the whole structure at the beginning than doing it all over the place and then miss to move it if code changes. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 82d36fb248fd..fcef8f879bb3 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -1398,13 +1398,6 @@ static int allocate_receive_buffers(struct smbd_connection *info, int num_buf) struct smbdirect_recv_io *response; int i; - INIT_LIST_HEAD(&sc->recv_io.reassembly.list); - spin_lock_init(&sc->recv_io.reassembly.lock); - sc->recv_io.reassembly.data_length = 0; - sc->recv_io.reassembly.queue_length = 0; - - INIT_LIST_HEAD(&sc->recv_io.free.list); - spin_lock_init(&sc->recv_io.free.lock); info->count_receive_queue = 0; init_waitqueue_head(&info->wait_receive_queues); @@ -1706,14 +1699,12 @@ static struct smbd_connection *_smbd_get_connection( if (!info) return NULL; sc = &info->socket; + smbdirect_socket_init(sc); sp = &sc->parameters; info->initiator_depth = 1; info->responder_resources = SMBD_CM_RESPONDER_RESOURCES; - init_waitqueue_head(&sc->status_wait); - - sc->status = SMBDIRECT_SOCKET_CREATED; rc = smbd_ia_open(info, dstaddr, port); if (rc) { log_rdma_event(INFO, "smbd_ia_open rc=%d\n", rc); @@ -1823,8 +1814,6 @@ static struct smbd_connection *_smbd_get_connection( log_rdma_event(INFO, "connecting to IP %pI4 port %d\n", &addr_in->sin_addr, port); - init_waitqueue_head(&sc->recv_io.reassembly.wait_queue); - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED); sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING; rc = rdma_connect(sc->rdma.cm_id, &conn_param); From a51c67db2c9e3f1539f5c441d8db2058ed8644f9 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Aug 2025 19:06:49 +0200 Subject: [PATCH 031/159] smb: client: make use of smbdirect_socket.disconnect_work Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 12 +++++++----- fs/smb/client/smbdirect.h | 1 - 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index fcef8f879bb3..89375f3bd30a 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -157,9 +157,8 @@ do { \ static void smbd_disconnect_rdma_work(struct work_struct *work) { - struct smbd_connection *info = - container_of(work, struct smbd_connection, disconnect_work); - struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket *sc = + container_of(work, struct smbdirect_socket, disconnect_work); switch (sc->status) { case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: @@ -197,7 +196,9 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) static void smbd_disconnect_rdma_connection(struct smbd_connection *info) { - queue_work(info->workqueue, &info->disconnect_work); + struct smbdirect_socket *sc = &info->socket; + + queue_work(info->workqueue, &sc->disconnect_work); } /* Upcall from RDMA CM */ @@ -1705,6 +1706,8 @@ static struct smbd_connection *_smbd_get_connection( info->initiator_depth = 1; info->responder_resources = SMBD_CM_RESPONDER_RESOURCES; + INIT_WORK(&sc->disconnect_work, smbd_disconnect_rdma_work); + rc = smbd_ia_open(info, dstaddr, port); if (rc) { log_rdma_event(INFO, "smbd_ia_open rc=%d\n", rc); @@ -1850,7 +1853,6 @@ static struct smbd_connection *_smbd_get_connection( init_waitqueue_head(&info->wait_post_send); - INIT_WORK(&info->disconnect_work, smbd_disconnect_rdma_work); INIT_WORK(&info->post_send_credits_work, smbd_post_send_credits); info->new_credits_offered = 0; spin_lock_init(&info->lock_new_credits_offered); diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index f250241d2d24..1c63188664df 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -45,7 +45,6 @@ enum keep_alive_status { struct smbd_connection { struct smbdirect_socket socket; - struct work_struct disconnect_work; struct work_struct post_send_credits_work; spinlock_t lock_new_credits_offered; From ca48841de93cbb911d2d85e84a329bbe0fac412d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 11 Aug 2025 15:19:51 +0200 Subject: [PATCH 032/159] smb: client: make use of smbdirect_socket.send_io.pending.{count,{dec,zero}_wait_queue} This will be used by the server too and will allow to create common helper functions. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/cifs_debug.c | 2 +- fs/smb/client/smbdirect.c | 31 +++++++++++++------------------ fs/smb/client/smbdirect.h | 5 ----- 3 files changed, 14 insertions(+), 24 deletions(-) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index 265e063e95bd..d48438e6efdb 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -497,7 +497,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) atomic_read(&server->smbd_conn->receive_credits), server->smbd_conn->receive_credit_target); seq_printf(m, "\nPending send_pending: %u ", - atomic_read(&server->smbd_conn->send_pending)); + atomic_read(&sc->send_io.pending.count)); seq_printf(m, "\nReceive buffers count_receive_queue: %u ", server->smbd_conn->count_receive_queue); seq_printf(m, "\nMR responder_resources: %u " diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 89375f3bd30a..947fd301c70b 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -418,10 +418,10 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc) return; } - if (atomic_dec_and_test(&info->send_pending)) - wake_up(&info->wait_send_pending); + if (atomic_dec_and_test(&sc->send_io.pending.count)) + wake_up(&sc->send_io.pending.zero_wait_queue); - wake_up(&info->wait_post_send); + wake_up(&sc->send_io.pending.dec_wait_queue); mempool_free(request, sc->send_io.mem.pool); } @@ -908,14 +908,14 @@ static int smbd_post_send_negotiate_req(struct smbd_connection *info) request->sge[0].addr, request->sge[0].length, request->sge[0].lkey); - atomic_inc(&info->send_pending); + atomic_inc(&sc->send_io.pending.count); rc = ib_post_send(sc->ib.qp, &send_wr, NULL); if (!rc) return 0; /* if we reach here, post send failed */ log_rdma_send(ERR, "ib_post_send failed rc=%d\n", rc); - atomic_dec(&info->send_pending); + atomic_dec(&sc->send_io.pending.count); ib_dma_unmap_single(sc->ib.dev, request->sge[0].addr, request->sge[0].length, DMA_TO_DEVICE); @@ -1038,8 +1038,8 @@ static int smbd_post_send_iter(struct smbd_connection *info, } wait_send_queue: - wait_event(info->wait_post_send, - atomic_read(&info->send_pending) < sp->send_credit_target || + wait_event(sc->send_io.pending.dec_wait_queue, + atomic_read(&sc->send_io.pending.count) < sp->send_credit_target || sc->status != SMBDIRECT_SOCKET_CONNECTED); if (sc->status != SMBDIRECT_SOCKET_CONNECTED) { @@ -1048,9 +1048,9 @@ static int smbd_post_send_iter(struct smbd_connection *info, goto err_wait_send_queue; } - if (unlikely(atomic_inc_return(&info->send_pending) > + if (unlikely(atomic_inc_return(&sc->send_io.pending.count) > sp->send_credit_target)) { - atomic_dec(&info->send_pending); + atomic_dec(&sc->send_io.pending.count); goto wait_send_queue; } @@ -1157,8 +1157,8 @@ static int smbd_post_send_iter(struct smbd_connection *info, atomic_sub(new_credits, &info->receive_credits); err_alloc: - if (atomic_dec_and_test(&info->send_pending)) - wake_up(&info->wait_send_pending); + if (atomic_dec_and_test(&sc->send_io.pending.count)) + wake_up(&sc->send_io.pending.zero_wait_queue); err_wait_send_queue: /* roll back send credits and pending */ @@ -1848,11 +1848,6 @@ static struct smbd_connection *_smbd_get_connection( queue_delayed_work(info->workqueue, &info->idle_timer_work, msecs_to_jiffies(sp->keepalive_interval_msec)); - init_waitqueue_head(&info->wait_send_pending); - atomic_set(&info->send_pending, 0); - - init_waitqueue_head(&info->wait_post_send); - INIT_WORK(&info->post_send_credits_work, smbd_post_send_credits); info->new_credits_offered = 0; spin_lock_init(&info->lock_new_credits_offered); @@ -2151,8 +2146,8 @@ int smbd_send(struct TCP_Server_Info *server, * that means all the I/Os have been out and we are good to return */ - wait_event(info->wait_send_pending, - atomic_read(&info->send_pending) == 0 || + wait_event(sc->send_io.pending.zero_wait_queue, + atomic_read(&sc->send_io.pending.count) == 0 || sc->status != SMBDIRECT_SOCKET_CONNECTED); if (sc->status != SMBDIRECT_SOCKET_CONNECTED && rc == 0) diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index 1c63188664df..2ce6b7ab898a 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -82,11 +82,6 @@ struct smbd_connection { /* Used by transport to wait until all MRs are returned */ wait_queue_head_t wait_for_mr_cleanup; - /* Activity accounting */ - atomic_t send_pending; - wait_queue_head_t wait_send_pending; - wait_queue_head_t wait_post_send; - /* Receive queue */ int count_receive_queue; wait_queue_head_t wait_receive_queues; From 9b1a6b7583cb71e101a93e518e2cbc32911a2b89 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 11 Aug 2025 17:11:08 +0200 Subject: [PATCH 033/159] smb: client: make use of smbdirect_socket.send_io.credits.{count,wait_queue} This will be used by the server too and will allow to create common helper functions. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/cifs_debug.c | 2 +- fs/smb/client/smbdirect.c | 19 +++++++++---------- fs/smb/client/smbdirect.h | 3 --- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index d48438e6efdb..01a582e172cb 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -493,7 +493,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) sc->recv_io.reassembly.queue_length); seq_printf(m, "\nCurrent Credits send_credits: %u " "receive_credits: %u receive_credit_target: %u", - atomic_read(&server->smbd_conn->send_credits), + atomic_read(&sc->send_io.credits.count), atomic_read(&server->smbd_conn->receive_credits), server->smbd_conn->receive_credit_target); seq_printf(m, "\nPending send_pending: %u ", diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 947fd301c70b..a4508f8b7499 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -349,7 +349,7 @@ static int smbd_conn_upcall( sc->status = SMBDIRECT_SOCKET_DISCONNECTED; wake_up_all(&sc->status_wait); wake_up_all(&sc->recv_io.reassembly.wait_queue); - wake_up_all(&info->wait_send_queue); + wake_up_all(&sc->send_io.credits.wait_queue); break; default: @@ -473,7 +473,7 @@ static bool process_negotiation_response( log_rdma_event(ERR, "error: credits_granted==0\n"); return false; } - atomic_set(&info->send_credits, le16_to_cpu(packet->credits_granted)); + atomic_set(&sc->send_io.credits.count, le16_to_cpu(packet->credits_granted)); atomic_set(&info->receive_credits, 0); @@ -651,12 +651,12 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) le16_to_cpu(data_transfer->credits_requested); if (le16_to_cpu(data_transfer->credits_granted)) { atomic_add(le16_to_cpu(data_transfer->credits_granted), - &info->send_credits); + &sc->send_io.credits.count); /* * We have new send credits granted from remote peer * If any sender is waiting for credits, unblock it */ - wake_up(&info->wait_send_queue); + wake_up(&sc->send_io.credits.wait_queue); } log_incoming(INFO, "data flags %d data_offset %d data_length %d remaining_data_length %d\n", @@ -1021,8 +1021,8 @@ static int smbd_post_send_iter(struct smbd_connection *info, wait_credit: /* Wait for send credits. A SMBD packet needs one credit */ - rc = wait_event_interruptible(info->wait_send_queue, - atomic_read(&info->send_credits) > 0 || + rc = wait_event_interruptible(sc->send_io.credits.wait_queue, + atomic_read(&sc->send_io.credits.count) > 0 || sc->status != SMBDIRECT_SOCKET_CONNECTED); if (rc) goto err_wait_credit; @@ -1032,8 +1032,8 @@ static int smbd_post_send_iter(struct smbd_connection *info, rc = -EAGAIN; goto err_wait_credit; } - if (unlikely(atomic_dec_return(&info->send_credits) < 0)) { - atomic_inc(&info->send_credits); + if (unlikely(atomic_dec_return(&sc->send_io.credits.count) < 0)) { + atomic_inc(&sc->send_io.credits.count); goto wait_credit; } @@ -1162,7 +1162,7 @@ static int smbd_post_send_iter(struct smbd_connection *info, err_wait_send_queue: /* roll back send credits and pending */ - atomic_inc(&info->send_credits); + atomic_inc(&sc->send_io.credits.count); err_wait_credit: return rc; @@ -1843,7 +1843,6 @@ static struct smbd_connection *_smbd_get_connection( goto allocate_cache_failed; } - init_waitqueue_head(&info->wait_send_queue); INIT_DELAYED_WORK(&info->idle_timer_work, idle_connection_timer); queue_delayed_work(info->workqueue, &info->idle_timer_work, msecs_to_jiffies(sp->keepalive_interval_msec)); diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index 2ce6b7ab898a..7075bdc92193 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -53,7 +53,6 @@ struct smbd_connection { /* dynamic connection parameters defined in [MS-SMBD] 3.1.1.1 */ enum keep_alive_status keep_alive_requested; int protocol; - atomic_t send_credits; atomic_t receive_credits; int receive_credit_target; @@ -88,8 +87,6 @@ struct smbd_connection { bool send_immediate; - wait_queue_head_t wait_send_queue; - struct workqueue_struct *workqueue; struct delayed_work idle_timer_work; From b0aa92a229ab9e6de3839e06f3a8494bce5b1cd2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 12 Aug 2025 09:10:07 +0200 Subject: [PATCH 034/159] smb: client: make sure smbd_disconnect_rdma_work() doesn't run after smbd_destroy() took over If we're already disconnecting we don't need to queue the disconnect_work again. disable_work() turns the next queue_work() into a no-op. Also let smbd_destroy() cancel(and disable) queued disconnect_work and call smbd_disconnect_rdma_work() inline. The makes it more obvious that disconnect_work is never queued again after smbd_destroy() called smbd_disconnect_rdma_work(). It also means we have a single place to call rdma_disconnect(). While there we better also disable all other [delayed_]work. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index a4508f8b7499..44140fb5f2ad 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -159,6 +159,18 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) { struct smbdirect_socket *sc = container_of(work, struct smbdirect_socket, disconnect_work); + struct smbd_connection *info = + container_of(sc, struct smbd_connection, socket); + + /* + * make sure this and other work is not queued again + * but here we don't block and avoid + * disable[_delayed]_work_sync() + */ + disable_work(&sc->disconnect_work); + disable_work(&info->post_send_credits_work); + disable_work(&info->mr_recovery_work); + disable_delayed_work(&info->idle_timer_work); switch (sc->status) { case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: @@ -342,11 +354,13 @@ static int smbd_conn_upcall( if (sc->status == SMBDIRECT_SOCKET_NEGOTIATE_FAILED) { log_rdma_event(ERR, "event=%s during negotiation\n", event_name); sc->status = SMBDIRECT_SOCKET_DISCONNECTED; + smbd_disconnect_rdma_work(&sc->disconnect_work); wake_up_all(&sc->status_wait); break; } sc->status = SMBDIRECT_SOCKET_DISCONNECTED; + smbd_disconnect_rdma_work(&sc->disconnect_work); wake_up_all(&sc->status_wait); wake_up_all(&sc->recv_io.reassembly.wait_queue); wake_up_all(&sc->send_io.credits.wait_queue); @@ -1483,9 +1497,12 @@ void smbd_destroy(struct TCP_Server_Info *server) sc = &info->socket; sp = &sc->parameters; + log_rdma_event(INFO, "cancelling and disable disconnect_work\n"); + disable_work_sync(&sc->disconnect_work); + log_rdma_event(INFO, "destroying rdma session\n"); - if (sc->status != SMBDIRECT_SOCKET_DISCONNECTED) { - rdma_disconnect(sc->rdma.cm_id); + if (sc->status < SMBDIRECT_SOCKET_DISCONNECTING) { + smbd_disconnect_rdma_work(&sc->disconnect_work); log_rdma_event(INFO, "wait for transport being disconnected\n"); wait_event_interruptible( sc->status_wait, From 02548c477a90481c1fd0d6e7c84b4504ec2fcc12 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 11 Aug 2025 17:53:55 +0200 Subject: [PATCH 035/159] smb: client: queue post_recv_credits_work also if the peer raises the credit target This is already handled in the server, but currently it done in a very complex way there. So we do it much simpler. Note that put_receive_buffer() will take care of it in case data_length is 0. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 44140fb5f2ad..d8a8382624ad 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -590,6 +590,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) struct smbdirect_socket_parameters *sp = &sc->parameters; struct smbd_connection *info = container_of(sc, struct smbd_connection, socket); + int old_recv_credit_target; u32 data_offset = 0; u32 data_length = 0; u32 remaining_data_length = 0; @@ -661,6 +662,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) } atomic_dec(&info->receive_credits); + old_recv_credit_target = info->receive_credit_target; info->receive_credit_target = le16_to_cpu(data_transfer->credits_requested); if (le16_to_cpu(data_transfer->credits_granted)) { @@ -691,6 +693,9 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) * reassembly queue and wake up the reading thread */ if (data_length) { + if (info->receive_credit_target > old_recv_credit_target) + queue_work(info->workqueue, &info->post_send_credits_work); + enqueue_reassembly(info, response, data_length); wake_up(&sc->recv_io.reassembly.wait_queue); } else From a8e970358b31a5abba8b5737a67ba7b8d26f4258 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 12 Aug 2025 09:44:07 +0200 Subject: [PATCH 036/159] smb: client: make use of ib_wc_status_msg() and skip IB_WC_WR_FLUSH_ERR logging There's no need to get log message for every IB_WC_WR_FLUSH_ERR completion, but any other error should be logged at level ERR. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index d8a8382624ad..0ec09841362f 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -415,8 +415,8 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc) struct smbd_connection *info = container_of(sc, struct smbd_connection, socket); - log_rdma_send(INFO, "smbdirect_send_io 0x%p completed wc->status=%d\n", - request, wc->status); + log_rdma_send(INFO, "smbdirect_send_io 0x%p completed wc->status=%s\n", + request, ib_wc_status_msg(wc->status)); for (i = 0; i < request->num_sge; i++) ib_dma_unmap_single(sc->ib.dev, @@ -425,8 +425,9 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc) DMA_TO_DEVICE); if (wc->status != IB_WC_SUCCESS || wc->opcode != IB_WC_SEND) { - log_rdma_send(ERR, "wc->status=%d wc->opcode=%d\n", - wc->status, wc->opcode); + if (wc->status != IB_WC_WR_FLUSH_ERR) + log_rdma_send(ERR, "wc->status=%s wc->opcode=%d\n", + ib_wc_status_msg(wc->status), wc->opcode); mempool_free(request, sc->send_io.mem.pool); smbd_disconnect_rdma_connection(info); return; @@ -596,13 +597,16 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) u32 remaining_data_length = 0; bool negotiate_done = false; - log_rdma_recv(INFO, "response=0x%p type=%d wc status=%d wc opcode %d byte_len=%d pkey_index=%u\n", - response, sc->recv_io.expected, wc->status, wc->opcode, + log_rdma_recv(INFO, + "response=0x%p type=%d wc status=%s wc opcode %d byte_len=%d pkey_index=%u\n", + response, sc->recv_io.expected, + ib_wc_status_msg(wc->status), wc->opcode, wc->byte_len, wc->pkey_index); if (wc->status != IB_WC_SUCCESS || wc->opcode != IB_WC_RECV) { - log_rdma_recv(INFO, "wc->status=%d opcode=%d\n", - wc->status, wc->opcode); + if (wc->status != IB_WC_WR_FLUSH_ERR) + log_rdma_recv(ERR, "wc->status=%s opcode=%d\n", + ib_wc_status_msg(wc->status), wc->opcode); goto error; } From 1a07031fdd56754747a27b48d555152e1daf19cd Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 12 Aug 2025 09:24:57 +0200 Subject: [PATCH 037/159] smb: client: remove info->wait_receive_queues handling in smbd_destroy() We already call ib_drain_qp() before, which is an sync operation that only returns in the queues are fully drained. ib_drain_qp() completes pending requests with IB_WC_WR_FLUSH_ERR so we have already called put_receive_buffer(). So all smbdirect_recv_io objects are either in the smbdirect_socket.recv_io.free.list or smbdirect_socket.recv_io.reassembly.list. Then we explicitly iterate smbdirect_socket.recv_io.reassembly.list and call put_receive_buffer(), so every object is in smbdirect_socket.recv_io.free.list. It means info->count_receive_queue == sp->recv_credit_max was already true and calling wait_event(info->wait_receive_queues... is pointless. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/cifs_debug.c | 2 -- fs/smb/client/smbdirect.c | 13 ------------- fs/smb/client/smbdirect.h | 4 ---- 3 files changed, 19 deletions(-) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index 01a582e172cb..a40846500de6 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -498,8 +498,6 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) server->smbd_conn->receive_credit_target); seq_printf(m, "\nPending send_pending: %u ", atomic_read(&sc->send_io.pending.count)); - seq_printf(m, "\nReceive buffers count_receive_queue: %u ", - server->smbd_conn->count_receive_queue); seq_printf(m, "\nMR responder_resources: %u " "max_frmr_depth: %u mr_type: 0x%x", server->smbd_conn->responder_resources, diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 0ec09841362f..df032ed70af5 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -541,7 +541,6 @@ static void smbd_post_send_credits(struct work_struct *work) struct smbdirect_socket *sc = &info->socket; if (sc->status != SMBDIRECT_SOCKET_CONNECTED) { - wake_up_all(&info->wait_receive_queues); return; } @@ -1378,7 +1377,6 @@ static struct smbdirect_recv_io *get_receive_buffer(struct smbd_connection *info &sc->recv_io.free.list, struct smbdirect_recv_io, list); list_del(&ret->list); - info->count_receive_queue--; info->count_get_receive_buffer++; } spin_unlock_irqrestore(&sc->recv_io.free.lock, flags); @@ -1408,7 +1406,6 @@ static void put_receive_buffer( spin_lock_irqsave(&sc->recv_io.free.lock, flags); list_add_tail(&response->list, &sc->recv_io.free.list); - info->count_receive_queue++; info->count_put_receive_buffer++; spin_unlock_irqrestore(&sc->recv_io.free.lock, flags); @@ -1422,10 +1419,6 @@ static int allocate_receive_buffers(struct smbd_connection *info, int num_buf) struct smbdirect_recv_io *response; int i; - info->count_receive_queue = 0; - - init_waitqueue_head(&info->wait_receive_queues); - for (i = 0; i < num_buf; i++) { response = mempool_alloc(sc->recv_io.mem.pool, GFP_KERNEL); if (!response) @@ -1434,7 +1427,6 @@ static int allocate_receive_buffers(struct smbd_connection *info, int num_buf) response->socket = sc; response->sge.length = 0; list_add_tail(&response->list, &sc->recv_io.free.list); - info->count_receive_queue++; } return 0; @@ -1445,7 +1437,6 @@ static int allocate_receive_buffers(struct smbd_connection *info, int num_buf) &sc->recv_io.free.list, struct smbdirect_recv_io, list); list_del(&response->list); - info->count_receive_queue--; mempool_free(response, sc->recv_io.mem.pool); } @@ -1495,7 +1486,6 @@ void smbd_destroy(struct TCP_Server_Info *server) { struct smbd_connection *info = server->smbd_conn; struct smbdirect_socket *sc; - struct smbdirect_socket_parameters *sp; struct smbdirect_recv_io *response; unsigned long flags; @@ -1504,7 +1494,6 @@ void smbd_destroy(struct TCP_Server_Info *server) return; } sc = &info->socket; - sp = &sc->parameters; log_rdma_event(INFO, "cancelling and disable disconnect_work\n"); disable_work_sync(&sc->disconnect_work); @@ -1546,8 +1535,6 @@ void smbd_destroy(struct TCP_Server_Info *server) sc->recv_io.reassembly.data_length = 0; log_rdma_event(INFO, "free receive buffers\n"); - wait_event(info->wait_receive_queues, - info->count_receive_queue == sp->recv_credit_max); destroy_receive_buffers(info); /* diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index 7075bdc92193..0b6e968c3d91 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -81,10 +81,6 @@ struct smbd_connection { /* Used by transport to wait until all MRs are returned */ wait_queue_head_t wait_for_mr_cleanup; - /* Receive queue */ - int count_receive_queue; - wait_queue_head_t wait_receive_queues; - bool send_immediate; struct workqueue_struct *workqueue; From 9219f8cac296769324bbe8a28c289586114244c4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 14 Aug 2025 15:01:35 +0200 Subject: [PATCH 038/159] smb: client: limit the range of info->receive_credit_target This simplifies further changes... Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 7 ++++++- fs/smb/client/smbdirect.h | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index df032ed70af5..92d4d75dc38d 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -483,6 +483,7 @@ static bool process_negotiation_response( return false; } info->receive_credit_target = le16_to_cpu(packet->credits_requested); + info->receive_credit_target = min_t(u16, info->receive_credit_target, sp->recv_credit_max); if (packet->credits_granted == 0) { log_rdma_event(ERR, "error: credits_granted==0\n"); @@ -590,7 +591,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) struct smbdirect_socket_parameters *sp = &sc->parameters; struct smbd_connection *info = container_of(sc, struct smbd_connection, socket); - int old_recv_credit_target; + u16 old_recv_credit_target; u32 data_offset = 0; u32 data_length = 0; u32 remaining_data_length = 0; @@ -668,6 +669,10 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) old_recv_credit_target = info->receive_credit_target; info->receive_credit_target = le16_to_cpu(data_transfer->credits_requested); + info->receive_credit_target = + min_t(u16, info->receive_credit_target, sp->recv_credit_max); + info->receive_credit_target = + max_t(u16, info->receive_credit_target, 1); if (le16_to_cpu(data_transfer->credits_granted)) { atomic_add(le16_to_cpu(data_transfer->credits_granted), &sc->send_io.credits.count); diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index 0b6e968c3d91..d5ccb92fb618 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -54,7 +54,7 @@ struct smbd_connection { enum keep_alive_status keep_alive_requested; int protocol; atomic_t receive_credits; - int receive_credit_target; + u16 receive_credit_target; /* Memory registrations */ /* Maximum number of RDMA read/write outstanding on this connection */ From 5fb9b459b3686e366640edd4e62805ef7b4de927 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 14 Aug 2025 13:57:37 +0200 Subject: [PATCH 039/159] smb: client: count the number of posted recv_io messages in order to calculated credits (At least for me) the logic maintaining the count of posted recv_io messages and the count of granted credits is much easier to understand. From there we can easily calculate the number of new_credits we'll grant to the peer in outgoing send_io messages. This will simplify the move to common logic that can be shared between client and server in the following patches. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 30 ++++++++++++++---------------- fs/smb/client/smbdirect.h | 4 +--- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 92d4d75dc38d..6332230ad4ca 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -492,6 +492,7 @@ static bool process_negotiation_response( atomic_set(&sc->send_io.credits.count, le16_to_cpu(packet->credits_granted)); atomic_set(&info->receive_credits, 0); + atomic_set(&info->receive_posted, 0); if (le32_to_cpu(packet->preferred_send_size) > sp->max_recv_size) { log_rdma_event(ERR, "error: preferred_send_size=%d\n", @@ -533,7 +534,6 @@ static bool process_negotiation_response( static void smbd_post_send_credits(struct work_struct *work) { - int ret = 0; int rc; struct smbdirect_recv_io *response; struct smbd_connection *info = @@ -561,14 +561,10 @@ static void smbd_post_send_credits(struct work_struct *work) break; } - ret++; + atomic_inc(&info->receive_posted); } } - spin_lock(&info->lock_new_credits_offered); - info->new_credits_offered += ret; - spin_unlock(&info->lock_new_credits_offered); - /* Promptly send an immediate packet as defined in [MS-SMBD] 3.1.1.1 */ info->send_immediate = true; if (atomic_read(&info->receive_credits) < @@ -665,6 +661,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) sc->recv_io.reassembly.full_packet_received = true; } + atomic_dec(&info->receive_posted); atomic_dec(&info->receive_credits); old_recv_credit_target = info->receive_credit_target; info->receive_credit_target = @@ -965,10 +962,16 @@ static int manage_credits_prior_sending(struct smbd_connection *info) { int new_credits; - spin_lock(&info->lock_new_credits_offered); - new_credits = info->new_credits_offered; - info->new_credits_offered = 0; - spin_unlock(&info->lock_new_credits_offered); + if (atomic_read(&info->receive_credits) >= info->receive_credit_target) + return 0; + + new_credits = atomic_read(&info->receive_posted); + if (new_credits == 0) + return 0; + + new_credits -= atomic_read(&info->receive_credits); + if (new_credits <= 0) + return 0; return new_credits; } @@ -1177,10 +1180,7 @@ static int smbd_post_send_iter(struct smbd_connection *info, DMA_TO_DEVICE); mempool_free(request, sc->send_io.mem.pool); - /* roll back receive credits and credits to be offered */ - spin_lock(&info->lock_new_credits_offered); - info->new_credits_offered += new_credits; - spin_unlock(&info->lock_new_credits_offered); + /* roll back the granted receive credits */ atomic_sub(new_credits, &info->receive_credits); err_alloc: @@ -1866,8 +1866,6 @@ static struct smbd_connection *_smbd_get_connection( msecs_to_jiffies(sp->keepalive_interval_msec)); INIT_WORK(&info->post_send_credits_work, smbd_post_send_credits); - info->new_credits_offered = 0; - spin_lock_init(&info->lock_new_credits_offered); rc = smbd_negotiate(info); if (rc) { diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index d5ccb92fb618..a10f69fab573 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -46,9 +46,7 @@ struct smbd_connection { struct smbdirect_socket socket; struct work_struct post_send_credits_work; - - spinlock_t lock_new_credits_offered; - int new_credits_offered; + atomic_t receive_posted; /* dynamic connection parameters defined in [MS-SMBD] 3.1.1.1 */ enum keep_alive_status keep_alive_requested; From c7316ec2d542e27ea717a0d7493902098329f908 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 14 Aug 2025 16:32:30 +0200 Subject: [PATCH 040/159] smb: client: make use of smbdirect_socket.recv_io.{posted,credits} This will make it possible to introduce common helper functions in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/cifs_debug.c | 4 +-- fs/smb/client/smbdirect.c | 64 ++++++++++++++++++-------------------- fs/smb/client/smbdirect.h | 5 --- 3 files changed, 33 insertions(+), 40 deletions(-) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index a40846500de6..10bfcb57e196 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -494,8 +494,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) seq_printf(m, "\nCurrent Credits send_credits: %u " "receive_credits: %u receive_credit_target: %u", atomic_read(&sc->send_io.credits.count), - atomic_read(&server->smbd_conn->receive_credits), - server->smbd_conn->receive_credit_target); + atomic_read(&sc->recv_io.credits.count), + sc->recv_io.credits.target); seq_printf(m, "\nPending send_pending: %u ", atomic_read(&sc->send_io.pending.count)); seq_printf(m, "\nMR responder_resources: %u " diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 6332230ad4ca..512f1cdd3e91 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -168,7 +168,7 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) * disable[_delayed]_work_sync() */ disable_work(&sc->disconnect_work); - disable_work(&info->post_send_credits_work); + disable_work(&sc->recv_io.posted.refill_work); disable_work(&info->mr_recovery_work); disable_delayed_work(&info->idle_timer_work); @@ -482,8 +482,8 @@ static bool process_negotiation_response( log_rdma_event(ERR, "error: credits_requested==0\n"); return false; } - info->receive_credit_target = le16_to_cpu(packet->credits_requested); - info->receive_credit_target = min_t(u16, info->receive_credit_target, sp->recv_credit_max); + sc->recv_io.credits.target = le16_to_cpu(packet->credits_requested); + sc->recv_io.credits.target = min_t(u16, sc->recv_io.credits.target, sp->recv_credit_max); if (packet->credits_granted == 0) { log_rdma_event(ERR, "error: credits_granted==0\n"); @@ -491,9 +491,6 @@ static bool process_negotiation_response( } atomic_set(&sc->send_io.credits.count, le16_to_cpu(packet->credits_granted)); - atomic_set(&info->receive_credits, 0); - atomic_set(&info->receive_posted, 0); - if (le32_to_cpu(packet->preferred_send_size) > sp->max_recv_size) { log_rdma_event(ERR, "error: preferred_send_size=%d\n", le32_to_cpu(packet->preferred_send_size)); @@ -536,17 +533,17 @@ static void smbd_post_send_credits(struct work_struct *work) { int rc; struct smbdirect_recv_io *response; + struct smbdirect_socket *sc = + container_of(work, struct smbdirect_socket, recv_io.posted.refill_work); struct smbd_connection *info = - container_of(work, struct smbd_connection, - post_send_credits_work); - struct smbdirect_socket *sc = &info->socket; + container_of(sc, struct smbd_connection, socket); if (sc->status != SMBDIRECT_SOCKET_CONNECTED) { return; } - if (info->receive_credit_target > - atomic_read(&info->receive_credits)) { + if (sc->recv_io.credits.target > + atomic_read(&sc->recv_io.credits.count)) { while (true) { response = get_receive_buffer(info); if (!response) @@ -561,14 +558,14 @@ static void smbd_post_send_credits(struct work_struct *work) break; } - atomic_inc(&info->receive_posted); + atomic_inc(&sc->recv_io.posted.count); } } /* Promptly send an immediate packet as defined in [MS-SMBD] 3.1.1.1 */ info->send_immediate = true; - if (atomic_read(&info->receive_credits) < - info->receive_credit_target - 1) { + if (atomic_read(&sc->recv_io.credits.count) < + sc->recv_io.credits.target - 1) { if (info->keep_alive_requested == KEEP_ALIVE_PENDING || info->send_immediate) { log_keep_alive(INFO, "send an empty message\n"); @@ -661,15 +658,15 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) sc->recv_io.reassembly.full_packet_received = true; } - atomic_dec(&info->receive_posted); - atomic_dec(&info->receive_credits); - old_recv_credit_target = info->receive_credit_target; - info->receive_credit_target = + atomic_dec(&sc->recv_io.posted.count); + atomic_dec(&sc->recv_io.credits.count); + old_recv_credit_target = sc->recv_io.credits.target; + sc->recv_io.credits.target = le16_to_cpu(data_transfer->credits_requested); - info->receive_credit_target = - min_t(u16, info->receive_credit_target, sp->recv_credit_max); - info->receive_credit_target = - max_t(u16, info->receive_credit_target, 1); + sc->recv_io.credits.target = + min_t(u16, sc->recv_io.credits.target, sp->recv_credit_max); + sc->recv_io.credits.target = + max_t(u16, sc->recv_io.credits.target, 1); if (le16_to_cpu(data_transfer->credits_granted)) { atomic_add(le16_to_cpu(data_transfer->credits_granted), &sc->send_io.credits.count); @@ -698,8 +695,8 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) * reassembly queue and wake up the reading thread */ if (data_length) { - if (info->receive_credit_target > old_recv_credit_target) - queue_work(info->workqueue, &info->post_send_credits_work); + if (sc->recv_io.credits.target > old_recv_credit_target) + queue_work(info->workqueue, &sc->recv_io.posted.refill_work); enqueue_reassembly(info, response, data_length); wake_up(&sc->recv_io.reassembly.wait_queue); @@ -960,16 +957,17 @@ static int smbd_post_send_negotiate_req(struct smbd_connection *info) */ static int manage_credits_prior_sending(struct smbd_connection *info) { + struct smbdirect_socket *sc = &info->socket; int new_credits; - if (atomic_read(&info->receive_credits) >= info->receive_credit_target) + if (atomic_read(&sc->recv_io.credits.count) >= sc->recv_io.credits.target) return 0; - new_credits = atomic_read(&info->receive_posted); + new_credits = atomic_read(&sc->recv_io.posted.count); if (new_credits == 0) return 0; - new_credits -= atomic_read(&info->receive_credits); + new_credits -= atomic_read(&sc->recv_io.credits.count); if (new_credits <= 0) return 0; @@ -1123,7 +1121,7 @@ static int smbd_post_send_iter(struct smbd_connection *info, packet->credits_requested = cpu_to_le16(sp->send_credit_target); new_credits = manage_credits_prior_sending(info); - atomic_add(new_credits, &info->receive_credits); + atomic_add(new_credits, &sc->recv_io.credits.count); packet->credits_granted = cpu_to_le16(new_credits); info->send_immediate = false; @@ -1181,7 +1179,7 @@ static int smbd_post_send_iter(struct smbd_connection *info, mempool_free(request, sc->send_io.mem.pool); /* roll back the granted receive credits */ - atomic_sub(new_credits, &info->receive_credits); + atomic_sub(new_credits, &sc->recv_io.credits.count); err_alloc: if (atomic_dec_and_test(&sc->send_io.pending.count)) @@ -1414,7 +1412,7 @@ static void put_receive_buffer( info->count_put_receive_buffer++; spin_unlock_irqrestore(&sc->recv_io.free.lock, flags); - queue_work(info->workqueue, &info->post_send_credits_work); + queue_work(info->workqueue, &sc->recv_io.posted.refill_work); } /* Preallocate all receive buffer on transport establishment */ @@ -1512,8 +1510,8 @@ void smbd_destroy(struct TCP_Server_Info *server) sc->status == SMBDIRECT_SOCKET_DISCONNECTED); } - log_rdma_event(INFO, "cancelling post_send_credits_work\n"); - disable_work_sync(&info->post_send_credits_work); + log_rdma_event(INFO, "cancelling recv_io.posted.refill_work\n"); + disable_work_sync(&sc->recv_io.posted.refill_work); log_rdma_event(INFO, "destroying qp\n"); ib_drain_qp(sc->ib.qp); @@ -1865,7 +1863,7 @@ static struct smbd_connection *_smbd_get_connection( queue_delayed_work(info->workqueue, &info->idle_timer_work, msecs_to_jiffies(sp->keepalive_interval_msec)); - INIT_WORK(&info->post_send_credits_work, smbd_post_send_credits); + INIT_WORK(&sc->recv_io.posted.refill_work, smbd_post_send_credits); rc = smbd_negotiate(info); if (rc) { diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index a10f69fab573..fb681605ea37 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -45,14 +45,9 @@ enum keep_alive_status { struct smbd_connection { struct smbdirect_socket socket; - struct work_struct post_send_credits_work; - atomic_t receive_posted; - /* dynamic connection parameters defined in [MS-SMBD] 3.1.1.1 */ enum keep_alive_status keep_alive_requested; int protocol; - atomic_t receive_credits; - u16 receive_credit_target; /* Memory registrations */ /* Maximum number of RDMA read/write outstanding on this connection */ From d3e743b514c20bfe26e340835cebb1f8301997ab Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 14 Aug 2025 18:34:02 +0200 Subject: [PATCH 041/159] smb: client: remove useless smbd_connection.send_immediate We always set it to true before having an if statement that checks it is true... Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 10 ++-------- fs/smb/client/smbdirect.h | 2 -- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 512f1cdd3e91..21e4a10d3999 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -563,14 +563,10 @@ static void smbd_post_send_credits(struct work_struct *work) } /* Promptly send an immediate packet as defined in [MS-SMBD] 3.1.1.1 */ - info->send_immediate = true; if (atomic_read(&sc->recv_io.credits.count) < sc->recv_io.credits.target - 1) { - if (info->keep_alive_requested == KEEP_ALIVE_PENDING || - info->send_immediate) { - log_keep_alive(INFO, "send an empty message\n"); - smbd_post_send_empty(info); - } + log_keep_alive(INFO, "send an empty message\n"); + smbd_post_send_empty(info); } } @@ -1124,8 +1120,6 @@ static int smbd_post_send_iter(struct smbd_connection *info, atomic_add(new_credits, &sc->recv_io.credits.count); packet->credits_granted = cpu_to_le16(new_credits); - info->send_immediate = false; - packet->flags = 0; if (manage_keep_alive_before_sending(info)) packet->flags |= cpu_to_le16(SMBDIRECT_FLAG_RESPONSE_REQUESTED); diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index fb681605ea37..2666f39ef26b 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -74,8 +74,6 @@ struct smbd_connection { /* Used by transport to wait until all MRs are returned */ wait_queue_head_t wait_for_mr_cleanup; - bool send_immediate; - struct workqueue_struct *workqueue; struct delayed_work idle_timer_work; From 14b6088dd97b5332c018a2e87c46be1e8cfdabc8 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 15 Aug 2025 11:03:04 +0200 Subject: [PATCH 042/159] smb: client: fill smbdirect_socket_parameters at the beginning and use the values from there This is what we should do and it also simplifies the following changes. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 48 +++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 21e4a10d3999..bed9d86ec85d 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -1718,30 +1718,6 @@ static struct smbd_connection *_smbd_get_connection( INIT_WORK(&sc->disconnect_work, smbd_disconnect_rdma_work); - rc = smbd_ia_open(info, dstaddr, port); - if (rc) { - log_rdma_event(INFO, "smbd_ia_open rc=%d\n", rc); - goto create_id_failed; - } - - if (smbd_send_credit_target > sc->ib.dev->attrs.max_cqe || - smbd_send_credit_target > sc->ib.dev->attrs.max_qp_wr) { - log_rdma_event(ERR, "consider lowering send_credit_target = %d. Possible CQE overrun, device reporting max_cqe %d max_qp_wr %d\n", - smbd_send_credit_target, - sc->ib.dev->attrs.max_cqe, - sc->ib.dev->attrs.max_qp_wr); - goto config_failed; - } - - if (smbd_receive_credit_max > sc->ib.dev->attrs.max_cqe || - smbd_receive_credit_max > sc->ib.dev->attrs.max_qp_wr) { - log_rdma_event(ERR, "consider lowering receive_credit_max = %d. Possible CQE overrun, device reporting max_cqe %d max_qp_wr %d\n", - smbd_receive_credit_max, - sc->ib.dev->attrs.max_cqe, - sc->ib.dev->attrs.max_qp_wr); - goto config_failed; - } - sp->recv_credit_max = smbd_receive_credit_max; sp->send_credit_target = smbd_send_credit_target; sp->max_send_size = smbd_max_send_size; @@ -1749,6 +1725,30 @@ static struct smbd_connection *_smbd_get_connection( sp->max_recv_size = smbd_max_receive_size; sp->keepalive_interval_msec = smbd_keep_alive_interval * 1000; + rc = smbd_ia_open(info, dstaddr, port); + if (rc) { + log_rdma_event(INFO, "smbd_ia_open rc=%d\n", rc); + goto create_id_failed; + } + + if (sp->send_credit_target > sc->ib.dev->attrs.max_cqe || + sp->send_credit_target > sc->ib.dev->attrs.max_qp_wr) { + log_rdma_event(ERR, "consider lowering send_credit_target = %d. Possible CQE overrun, device reporting max_cqe %d max_qp_wr %d\n", + sp->send_credit_target, + sc->ib.dev->attrs.max_cqe, + sc->ib.dev->attrs.max_qp_wr); + goto config_failed; + } + + if (sp->recv_credit_max > sc->ib.dev->attrs.max_cqe || + sp->recv_credit_max > sc->ib.dev->attrs.max_qp_wr) { + log_rdma_event(ERR, "consider lowering receive_credit_max = %d. Possible CQE overrun, device reporting max_cqe %d max_qp_wr %d\n", + sp->recv_credit_max, + sc->ib.dev->attrs.max_cqe, + sc->ib.dev->attrs.max_qp_wr); + goto config_failed; + } + if (sc->ib.dev->attrs.max_send_sge < SMBDIRECT_SEND_IO_MAX_SGE || sc->ib.dev->attrs.max_recv_sge < SMBDIRECT_RECV_IO_MAX_SGE) { log_rdma_event(ERR, From 1f2ff73a233005cb1f8e7bc02477603e2f9f4c69 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 14 Aug 2025 19:39:22 +0200 Subject: [PATCH 043/159] smb: client: make use of smbdirect_socket_parameters.{resolve_{addr,route},rdma_connect,negotiate}_timeout_msec This will make future changes to these values much saner. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index bed9d86ec85d..b7b54a36a46e 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -57,6 +57,9 @@ static ssize_t smb_extract_iter_to_rdma(struct iov_iter *iter, size_t len, /* SMBD negotiation timeout in seconds */ #define SMBD_NEGOTIATE_TIMEOUT 120 +/* The timeout to wait for a keepalive message from peer in seconds */ +#define KEEPALIVE_RECV_TIMEOUT 5 + /* SMBD minimum receive size and fragmented sized defined in [MS-SMBD] */ #define SMBD_MIN_RECEIVE_SIZE 128 #define SMBD_MIN_FRAGMENTED_SIZE 131072 @@ -721,6 +724,7 @@ static struct rdma_cm_id *smbd_create_id( struct sockaddr *dstaddr, int port) { struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; struct rdma_cm_id *id; int rc; __be16 *sport; @@ -743,7 +747,7 @@ static struct rdma_cm_id *smbd_create_id( WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_NEEDED); sc->status = SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING; rc = rdma_resolve_addr(id, NULL, (struct sockaddr *)dstaddr, - RDMA_RESOLVE_TIMEOUT); + sp->resolve_addr_timeout_msec); if (rc) { log_rdma_event(ERR, "rdma_resolve_addr() failed %i\n", rc); goto out; @@ -751,7 +755,7 @@ static struct rdma_cm_id *smbd_create_id( rc = wait_event_interruptible_timeout( sc->status_wait, sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING, - msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT)); + msecs_to_jiffies(sp->resolve_addr_timeout_msec)); /* e.g. if interrupted returns -ERESTARTSYS */ if (rc < 0) { log_rdma_event(ERR, "rdma_resolve_addr timeout rc: %i\n", rc); @@ -770,7 +774,7 @@ static struct rdma_cm_id *smbd_create_id( WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED); sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING; - rc = rdma_resolve_route(id, RDMA_RESOLVE_TIMEOUT); + rc = rdma_resolve_route(id, sp->resolve_route_timeout_msec); if (rc) { log_rdma_event(ERR, "rdma_resolve_route() failed %i\n", rc); goto out; @@ -778,7 +782,7 @@ static struct rdma_cm_id *smbd_create_id( rc = wait_event_interruptible_timeout( sc->status_wait, sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING, - msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT)); + msecs_to_jiffies(sp->resolve_route_timeout_msec)); /* e.g. if interrupted returns -ERESTARTSYS */ if (rc < 0) { log_rdma_event(ERR, "rdma_resolve_addr timeout rc: %i\n", rc); @@ -1266,6 +1270,7 @@ static int smbd_post_recv( static int smbd_negotiate(struct smbd_connection *info) { struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; int rc; struct smbdirect_recv_io *response = get_receive_buffer(info); @@ -1289,7 +1294,7 @@ static int smbd_negotiate(struct smbd_connection *info) rc = wait_event_interruptible_timeout( sc->status_wait, sc->status != SMBDIRECT_SOCKET_NEGOTIATE_RUNNING, - secs_to_jiffies(SMBD_NEGOTIATE_TIMEOUT)); + msecs_to_jiffies(sp->negotiate_timeout_msec)); log_rdma_event(INFO, "wait_event_interruptible_timeout rc=%d\n", rc); if (sc->status == SMBDIRECT_SOCKET_CONNECTED) @@ -1718,12 +1723,17 @@ static struct smbd_connection *_smbd_get_connection( INIT_WORK(&sc->disconnect_work, smbd_disconnect_rdma_work); + sp->resolve_addr_timeout_msec = RDMA_RESOLVE_TIMEOUT; + sp->resolve_route_timeout_msec = RDMA_RESOLVE_TIMEOUT; + sp->rdma_connect_timeout_msec = RDMA_RESOLVE_TIMEOUT; + sp->negotiate_timeout_msec = SMBD_NEGOTIATE_TIMEOUT * 1000; sp->recv_credit_max = smbd_receive_credit_max; sp->send_credit_target = smbd_send_credit_target; sp->max_send_size = smbd_max_send_size; sp->max_fragmented_recv_size = smbd_max_fragmented_recv_size; sp->max_recv_size = smbd_max_receive_size; sp->keepalive_interval_msec = smbd_keep_alive_interval * 1000; + sp->keepalive_timeout_msec = KEEPALIVE_RECV_TIMEOUT * 1000; rc = smbd_ia_open(info, dstaddr, port); if (rc) { @@ -1838,7 +1848,7 @@ static struct smbd_connection *_smbd_get_connection( wait_event_interruptible_timeout( sc->status_wait, sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING, - msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT)); + msecs_to_jiffies(sp->rdma_connect_timeout_msec)); if (sc->status != SMBDIRECT_SOCKET_NEGOTIATE_NEEDED) { log_rdma_event(ERR, "rdma_connect failed port=%d\n", port); From dd53b45fc871cd9eb8ce90b215378c683aae783b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 19 Aug 2025 23:18:21 +0200 Subject: [PATCH 044/159] smb: client: make use of smbdirect_socket_parameters.{initiator_depth,responder_resources} This will make it easier to specify these from the outside of the core code first and then negotiate the value with the peer. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/cifs_debug.c | 2 +- fs/smb/client/smbdirect.c | 29 +++++++++++++++-------------- fs/smb/client/smbdirect.h | 2 -- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index 10bfcb57e196..3086ab2622ba 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -500,7 +500,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) atomic_read(&sc->send_io.pending.count)); seq_printf(m, "\nMR responder_resources: %u " "max_frmr_depth: %u mr_type: 0x%x", - server->smbd_conn->responder_resources, + sp->responder_resources, server->smbd_conn->max_frmr_depth, server->smbd_conn->mr_type); seq_printf(m, "\nMR mr_ready_count: %u mr_used_count: %u", diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index b7b54a36a46e..a55163e2876b 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -222,6 +222,7 @@ static int smbd_conn_upcall( { struct smbd_connection *info = id->context; struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; const char *event_name = rdma_event_msg(event->event); u8 peer_initiator_depth; u8 peer_responder_resources; @@ -329,12 +330,12 @@ static int smbd_conn_upcall( * non 0 values. */ if (peer_initiator_depth != 0) - info->initiator_depth = - min_t(u8, info->initiator_depth, + sp->initiator_depth = + min_t(u8, sp->initiator_depth, peer_initiator_depth); if (peer_responder_resources != 0) - info->responder_resources = - min_t(u8, info->responder_resources, + sp->responder_resources = + min_t(u8, sp->responder_resources, peer_responder_resources); WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING); @@ -1718,15 +1719,14 @@ static struct smbd_connection *_smbd_get_connection( smbdirect_socket_init(sc); sp = &sc->parameters; - info->initiator_depth = 1; - info->responder_resources = SMBD_CM_RESPONDER_RESOURCES; - INIT_WORK(&sc->disconnect_work, smbd_disconnect_rdma_work); sp->resolve_addr_timeout_msec = RDMA_RESOLVE_TIMEOUT; sp->resolve_route_timeout_msec = RDMA_RESOLVE_TIMEOUT; sp->rdma_connect_timeout_msec = RDMA_RESOLVE_TIMEOUT; sp->negotiate_timeout_msec = SMBD_NEGOTIATE_TIMEOUT * 1000; + sp->initiator_depth = 1; + sp->responder_resources = SMBD_CM_RESPONDER_RESOURCES; sp->recv_credit_max = smbd_receive_credit_max; sp->send_credit_target = smbd_send_credit_target; sp->max_send_size = smbd_max_send_size; @@ -1807,15 +1807,15 @@ static struct smbd_connection *_smbd_get_connection( } sc->ib.qp = sc->rdma.cm_id->qp; - info->responder_resources = - min_t(u8, info->responder_resources, + sp->responder_resources = + min_t(u8, sp->responder_resources, sc->ib.dev->attrs.max_qp_rd_atom); log_rdma_mr(INFO, "responder_resources=%d\n", - info->responder_resources); + sp->responder_resources); memset(&conn_param, 0, sizeof(conn_param)); - conn_param.initiator_depth = info->initiator_depth; - conn_param.responder_resources = info->responder_resources; + conn_param.initiator_depth = sp->initiator_depth; + conn_param.responder_resources = sp->responder_resources; /* Need to send IRD/ORD in private data for iWARP */ sc->ib.dev->ops.get_port_immutable( @@ -2270,6 +2270,7 @@ static void destroy_mr_list(struct smbd_connection *info) static int allocate_mr_list(struct smbd_connection *info) { struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; int i; struct smbd_mr *smbdirect_mr, *tmp; @@ -2281,13 +2282,13 @@ static int allocate_mr_list(struct smbd_connection *info) init_waitqueue_head(&info->wait_for_mr_cleanup); INIT_WORK(&info->mr_recovery_work, smbd_mr_recovery_work); - if (info->responder_resources == 0) { + if (sp->responder_resources == 0) { log_rdma_mr(ERR, "responder_resources negotiated as 0\n"); return -EINVAL; } /* Allocate more MRs (2x) than hardware responder_resources */ - for (i = 0; i < info->responder_resources * 2; i++) { + for (i = 0; i < sp->responder_resources * 2; i++) { smbdirect_mr = kzalloc(sizeof(*smbdirect_mr), GFP_KERNEL); if (!smbdirect_mr) goto cleanup_entries; diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index 2666f39ef26b..a5a70b3c63cb 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -52,8 +52,6 @@ struct smbd_connection { /* Memory registrations */ /* Maximum number of RDMA read/write outstanding on this connection */ bool legacy_iwarp; - u8 initiator_depth; - u8 responder_resources; /* Maximum number of pages in a single RDMA write/read on this connection */ int max_frmr_depth; /* From ea5a4e31ab4757273dacaa7e05368892516b53d6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 Aug 2025 12:22:46 +0200 Subject: [PATCH 045/159] smb: client: make use of smbdirect_socket.rdma.legacy_iwarp Currently it's write only for the client, but it will likely be use for debugging later. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 2 +- fs/smb/client/smbdirect.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index a55163e2876b..b910d62d66c5 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -318,7 +318,7 @@ static int smbd_conn_upcall( ird32 = min_t(u32, ird32, U8_MAX); ord32 = min_t(u32, ord32, U8_MAX); - info->legacy_iwarp = true; + sc->rdma.legacy_iwarp = true; peer_initiator_depth = (u8)ird32; peer_responder_resources = (u8)ord32; } diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index a5a70b3c63cb..1bb9b9412685 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -50,8 +50,6 @@ struct smbd_connection { int protocol; /* Memory registrations */ - /* Maximum number of RDMA read/write outstanding on this connection */ - bool legacy_iwarp; /* Maximum number of pages in a single RDMA write/read on this connection */ int max_frmr_depth; /* From 1b2c46cdb7c0127711cd72028072d85f6ebd1b53 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 15 Aug 2025 12:53:35 +0200 Subject: [PATCH 046/159] smb: client: send empty packets via send_immediate_work This is what the server already does and it makes refactoring for common structures and functions much easier. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 25 +++++++++++++++++++++---- fs/smb/client/smbdirect.h | 1 + 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index b910d62d66c5..d53e39e91e10 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -173,6 +173,7 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) disable_work(&sc->disconnect_work); disable_work(&sc->recv_io.posted.refill_work); disable_work(&info->mr_recovery_work); + disable_work(&info->send_immediate_work); disable_delayed_work(&info->idle_timer_work); switch (sc->status) { @@ -569,8 +570,8 @@ static void smbd_post_send_credits(struct work_struct *work) /* Promptly send an immediate packet as defined in [MS-SMBD] 3.1.1.1 */ if (atomic_read(&sc->recv_io.credits.count) < sc->recv_io.credits.target - 1) { - log_keep_alive(INFO, "send an empty message\n"); - smbd_post_send_empty(info); + log_keep_alive(INFO, "schedule send of an empty message\n"); + queue_work(info->workqueue, &info->send_immediate_work); } } @@ -1455,6 +1456,19 @@ static void destroy_receive_buffers(struct smbd_connection *info) mempool_free(response, sc->recv_io.mem.pool); } +static void send_immediate_empty_message(struct work_struct *work) +{ + struct smbd_connection *info = + container_of(work, struct smbd_connection, send_immediate_work); + struct smbdirect_socket *sc = &info->socket; + + if (sc->status != SMBDIRECT_SOCKET_CONNECTED) + return; + + log_keep_alive(INFO, "send an empty message\n"); + smbd_post_send_empty(info); +} + /* Implement idle connection timer [MS-SMBD] 3.1.6.2 */ static void idle_connection_timer(struct work_struct *work) { @@ -1472,8 +1486,8 @@ static void idle_connection_timer(struct work_struct *work) return; } - log_keep_alive(INFO, "about to send an empty idle message\n"); - smbd_post_send_empty(info); + log_keep_alive(INFO, "schedule send of empty idle message\n"); + queue_work(info->workqueue, &info->send_immediate_work); /* Setup the next idle timeout work */ queue_delayed_work(info->workqueue, &info->idle_timer_work, @@ -1520,6 +1534,8 @@ void smbd_destroy(struct TCP_Server_Info *server) log_rdma_event(INFO, "cancelling idle timer\n"); disable_delayed_work_sync(&info->idle_timer_work); + log_rdma_event(INFO, "cancelling send immediate work\n"); + disable_work_sync(&info->send_immediate_work); /* It's not possible for upper layer to get to reassembly */ log_rdma_event(INFO, "drain the reassembly queue\n"); @@ -1863,6 +1879,7 @@ static struct smbd_connection *_smbd_get_connection( goto allocate_cache_failed; } + INIT_WORK(&info->send_immediate_work, send_immediate_empty_message); INIT_DELAYED_WORK(&info->idle_timer_work, idle_connection_timer); queue_delayed_work(info->workqueue, &info->idle_timer_work, msecs_to_jiffies(sp->keepalive_interval_msec)); diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index 1bb9b9412685..07c7fba2f340 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -71,6 +71,7 @@ struct smbd_connection { wait_queue_head_t wait_for_mr_cleanup; struct workqueue_struct *workqueue; + struct work_struct send_immediate_work; struct delayed_work idle_timer_work; /* for debug purposes */ From ac31755c7a649786a9e11c6288513f5f4c1d30c9 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 14 Aug 2025 19:41:12 +0200 Subject: [PATCH 047/159] smb: client: fix smbdirect keep alive handling to match the documentation We setup the first timer with the negotiate timeout and set KEEP_ALIVE_PENDING, so that the expired timer disconnects. On every incoming message we need to reset the timer to the keepalive interval (120s). On SMBDIRECT_FLAG_RESPONSE_REQUESTED we need to schedule a response instead of setting KEEP_ALIVE_PENDING. Doing both would mean we would also set SMBDIRECT_FLAG_RESPONSE_REQUESTED in that response. If both ends would do that we'd play ping pong in a busy loop. If we move to KEEP_ALIVE_SENT and send the keepalive request with SMBDIRECT_FLAG_RESPONSE_REQUESTED, we need to setup the timer with keepalive timeout (5s) in order to disconnect if no incoming message reset the timer. The fired timer sets KEEP_ALIVE_PENDING and also setup timer with keepalive timeout (5s) in order to disconnect if no incoming message reset the timer. We do that before queueing the send_immediate_work and have that timer in case we didn't reach the send code that typically sets the timer to keepalive timeout. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 52 ++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index d53e39e91e10..5863dc7e021a 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -610,6 +610,14 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) response->sge.length, DMA_FROM_DEVICE); + /* + * Reset timer to the keepalive interval in + * order to trigger our next keepalive message. + */ + info->keep_alive_requested = KEEP_ALIVE_NONE; + mod_delayed_work(info->workqueue, &info->idle_timer_work, + msecs_to_jiffies(sp->keepalive_interval_msec)); + switch (sc->recv_io.expected) { /* SMBD negotiation response */ case SMBDIRECT_EXPECT_NEGOTIATE_REP: @@ -684,11 +692,11 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) le32_to_cpu(data_transfer->data_length), le32_to_cpu(data_transfer->remaining_data_length)); - /* Send a KEEP_ALIVE response right away if requested */ - info->keep_alive_requested = KEEP_ALIVE_NONE; + /* Send an immediate response right away if requested */ if (le16_to_cpu(data_transfer->flags) & SMBDIRECT_FLAG_RESPONSE_REQUESTED) { - info->keep_alive_requested = KEEP_ALIVE_PENDING; + log_keep_alive(INFO, "schedule send of immediate response\n"); + queue_work(info->workqueue, &info->send_immediate_work); } /* @@ -987,8 +995,17 @@ static int manage_credits_prior_sending(struct smbd_connection *info) */ static int manage_keep_alive_before_sending(struct smbd_connection *info) { + struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; + if (info->keep_alive_requested == KEEP_ALIVE_PENDING) { info->keep_alive_requested = KEEP_ALIVE_SENT; + /* + * Now use the keepalive timeout (instead of keepalive interval) + * in order to wait for a response + */ + mod_delayed_work(info->workqueue, &info->idle_timer_work, + msecs_to_jiffies(sp->keepalive_timeout_msec)); return 1; } return 0; @@ -999,7 +1016,6 @@ static int smbd_post_send(struct smbd_connection *info, struct smbdirect_send_io *request) { struct smbdirect_socket *sc = &info->socket; - struct smbdirect_socket_parameters *sp = &sc->parameters; struct ib_send_wr send_wr; int rc, i; @@ -1028,10 +1044,7 @@ static int smbd_post_send(struct smbd_connection *info, log_rdma_send(ERR, "ib_post_send failed rc=%d\n", rc); smbd_disconnect_rdma_connection(info); rc = -EAGAIN; - } else - /* Reset timer for idle connection after packet is sent */ - mod_delayed_work(info->workqueue, &info->idle_timer_work, - msecs_to_jiffies(sp->keepalive_interval_msec)); + } return rc; } @@ -1486,12 +1499,18 @@ static void idle_connection_timer(struct work_struct *work) return; } + if (sc->status != SMBDIRECT_SOCKET_CONNECTED) + return; + + /* + * Now use the keepalive timeout (instead of keepalive interval) + * in order to wait for a response + */ + info->keep_alive_requested = KEEP_ALIVE_PENDING; + mod_delayed_work(info->workqueue, &info->idle_timer_work, + msecs_to_jiffies(sp->keepalive_timeout_msec)); log_keep_alive(INFO, "schedule send of empty idle message\n"); queue_work(info->workqueue, &info->send_immediate_work); - - /* Setup the next idle timeout work */ - queue_delayed_work(info->workqueue, &info->idle_timer_work, - msecs_to_jiffies(sp->keepalive_interval_msec)); } /* @@ -1881,8 +1900,13 @@ static struct smbd_connection *_smbd_get_connection( INIT_WORK(&info->send_immediate_work, send_immediate_empty_message); INIT_DELAYED_WORK(&info->idle_timer_work, idle_connection_timer); - queue_delayed_work(info->workqueue, &info->idle_timer_work, - msecs_to_jiffies(sp->keepalive_interval_msec)); + /* + * start with the negotiate timeout and KEEP_ALIVE_PENDING + * so that the timer will cause a disconnect. + */ + info->keep_alive_requested = KEEP_ALIVE_PENDING; + mod_delayed_work(info->workqueue, &info->idle_timer_work, + msecs_to_jiffies(sp->negotiate_timeout_msec)); INIT_WORK(&sc->recv_io.posted.refill_work, smbd_post_send_credits); From 4dc536a135e0ef862ccc25f5d68ad5c062dc01a0 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 15 Aug 2025 17:57:32 +0200 Subject: [PATCH 048/159] smb: client: make use of smbdirect_socket.idle.{keepalive,immediate_work,timer_work} This will allow client and server to use the common structures in order to share common functions later. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 59 ++++++++++++++++++++------------------- fs/smb/client/smbdirect.h | 9 ------ 2 files changed, 30 insertions(+), 38 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 5863dc7e021a..efebc4aa297f 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -173,8 +173,8 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) disable_work(&sc->disconnect_work); disable_work(&sc->recv_io.posted.refill_work); disable_work(&info->mr_recovery_work); - disable_work(&info->send_immediate_work); - disable_delayed_work(&info->idle_timer_work); + disable_work(&sc->idle.immediate_work); + disable_delayed_work(&sc->idle.timer_work); switch (sc->status) { case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: @@ -571,7 +571,7 @@ static void smbd_post_send_credits(struct work_struct *work) if (atomic_read(&sc->recv_io.credits.count) < sc->recv_io.credits.target - 1) { log_keep_alive(INFO, "schedule send of an empty message\n"); - queue_work(info->workqueue, &info->send_immediate_work); + queue_work(info->workqueue, &sc->idle.immediate_work); } } @@ -614,8 +614,8 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) * Reset timer to the keepalive interval in * order to trigger our next keepalive message. */ - info->keep_alive_requested = KEEP_ALIVE_NONE; - mod_delayed_work(info->workqueue, &info->idle_timer_work, + sc->idle.keepalive = SMBDIRECT_KEEPALIVE_NONE; + mod_delayed_work(info->workqueue, &sc->idle.timer_work, msecs_to_jiffies(sp->keepalive_interval_msec)); switch (sc->recv_io.expected) { @@ -696,7 +696,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) if (le16_to_cpu(data_transfer->flags) & SMBDIRECT_FLAG_RESPONSE_REQUESTED) { log_keep_alive(INFO, "schedule send of immediate response\n"); - queue_work(info->workqueue, &info->send_immediate_work); + queue_work(info->workqueue, &sc->idle.immediate_work); } /* @@ -998,13 +998,13 @@ static int manage_keep_alive_before_sending(struct smbd_connection *info) struct smbdirect_socket *sc = &info->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; - if (info->keep_alive_requested == KEEP_ALIVE_PENDING) { - info->keep_alive_requested = KEEP_ALIVE_SENT; + if (sc->idle.keepalive == SMBDIRECT_KEEPALIVE_PENDING) { + sc->idle.keepalive = SMBDIRECT_KEEPALIVE_SENT; /* * Now use the keepalive timeout (instead of keepalive interval) * in order to wait for a response */ - mod_delayed_work(info->workqueue, &info->idle_timer_work, + mod_delayed_work(info->workqueue, &sc->idle.timer_work, msecs_to_jiffies(sp->keepalive_timeout_msec)); return 1; } @@ -1471,9 +1471,10 @@ static void destroy_receive_buffers(struct smbd_connection *info) static void send_immediate_empty_message(struct work_struct *work) { + struct smbdirect_socket *sc = + container_of(work, struct smbdirect_socket, idle.immediate_work); struct smbd_connection *info = - container_of(work, struct smbd_connection, send_immediate_work); - struct smbdirect_socket *sc = &info->socket; + container_of(sc, struct smbd_connection, socket); if (sc->status != SMBDIRECT_SOCKET_CONNECTED) return; @@ -1485,16 +1486,16 @@ static void send_immediate_empty_message(struct work_struct *work) /* Implement idle connection timer [MS-SMBD] 3.1.6.2 */ static void idle_connection_timer(struct work_struct *work) { - struct smbd_connection *info = container_of( - work, struct smbd_connection, - idle_timer_work.work); - struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket *sc = + container_of(work, struct smbdirect_socket, idle.timer_work.work); struct smbdirect_socket_parameters *sp = &sc->parameters; + struct smbd_connection *info = + container_of(sc, struct smbd_connection, socket); - if (info->keep_alive_requested != KEEP_ALIVE_NONE) { + if (sc->idle.keepalive != SMBDIRECT_KEEPALIVE_NONE) { log_keep_alive(ERR, - "error status info->keep_alive_requested=%d\n", - info->keep_alive_requested); + "error status sc->idle.keepalive=%d\n", + sc->idle.keepalive); smbd_disconnect_rdma_connection(info); return; } @@ -1506,11 +1507,11 @@ static void idle_connection_timer(struct work_struct *work) * Now use the keepalive timeout (instead of keepalive interval) * in order to wait for a response */ - info->keep_alive_requested = KEEP_ALIVE_PENDING; - mod_delayed_work(info->workqueue, &info->idle_timer_work, + sc->idle.keepalive = SMBDIRECT_KEEPALIVE_PENDING; + mod_delayed_work(info->workqueue, &sc->idle.timer_work, msecs_to_jiffies(sp->keepalive_timeout_msec)); log_keep_alive(INFO, "schedule send of empty idle message\n"); - queue_work(info->workqueue, &info->send_immediate_work); + queue_work(info->workqueue, &sc->idle.immediate_work); } /* @@ -1552,9 +1553,9 @@ void smbd_destroy(struct TCP_Server_Info *server) sc->ib.qp = NULL; log_rdma_event(INFO, "cancelling idle timer\n"); - disable_delayed_work_sync(&info->idle_timer_work); + disable_delayed_work_sync(&sc->idle.timer_work); log_rdma_event(INFO, "cancelling send immediate work\n"); - disable_work_sync(&info->send_immediate_work); + disable_work_sync(&sc->idle.immediate_work); /* It's not possible for upper layer to get to reassembly */ log_rdma_event(INFO, "drain the reassembly queue\n"); @@ -1898,14 +1899,14 @@ static struct smbd_connection *_smbd_get_connection( goto allocate_cache_failed; } - INIT_WORK(&info->send_immediate_work, send_immediate_empty_message); - INIT_DELAYED_WORK(&info->idle_timer_work, idle_connection_timer); + INIT_WORK(&sc->idle.immediate_work, send_immediate_empty_message); + INIT_DELAYED_WORK(&sc->idle.timer_work, idle_connection_timer); /* - * start with the negotiate timeout and KEEP_ALIVE_PENDING + * start with the negotiate timeout and SMBDIRECT_KEEPALIVE_PENDING * so that the timer will cause a disconnect. */ - info->keep_alive_requested = KEEP_ALIVE_PENDING; - mod_delayed_work(info->workqueue, &info->idle_timer_work, + sc->idle.keepalive = SMBDIRECT_KEEPALIVE_PENDING; + mod_delayed_work(info->workqueue, &sc->idle.timer_work, msecs_to_jiffies(sp->negotiate_timeout_msec)); INIT_WORK(&sc->recv_io.posted.refill_work, smbd_post_send_credits); @@ -1931,7 +1932,7 @@ static struct smbd_connection *_smbd_get_connection( return NULL; negotiation_failed: - disable_delayed_work_sync(&info->idle_timer_work); + disable_delayed_work_sync(&sc->idle.timer_work); destroy_caches_and_workqueue(info); sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED; rdma_disconnect(sc->rdma.cm_id); diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index 07c7fba2f340..5f9ba769623b 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -27,12 +27,6 @@ extern int smbd_max_send_size; extern int smbd_send_credit_target; extern int smbd_receive_credit_max; -enum keep_alive_status { - KEEP_ALIVE_NONE, - KEEP_ALIVE_PENDING, - KEEP_ALIVE_SENT, -}; - /* * The context for the SMBDirect transport * Everything related to the transport is here. It has several logical parts @@ -46,7 +40,6 @@ struct smbd_connection { struct smbdirect_socket socket; /* dynamic connection parameters defined in [MS-SMBD] 3.1.1.1 */ - enum keep_alive_status keep_alive_requested; int protocol; /* Memory registrations */ @@ -71,8 +64,6 @@ struct smbd_connection { wait_queue_head_t wait_for_mr_cleanup; struct workqueue_struct *workqueue; - struct work_struct send_immediate_work; - struct delayed_work idle_timer_work; /* for debug purposes */ unsigned int count_get_receive_buffer; From 87d03d6c829aea8c6cf632ac24ee5227c3b8b00b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 18 Aug 2025 10:42:42 +0200 Subject: [PATCH 049/159] smb: client: remove unused smbd_connection->protocol There is only one protocol version for smbdirect yet and this variable is write only. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/cifs_debug.c | 3 ++- fs/smb/client/smbdirect.c | 1 - fs/smb/client/smbdirect.h | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index 3086ab2622ba..e407bedd4aa7 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -24,6 +24,7 @@ #endif #ifdef CONFIG_CIFS_SMB_DIRECT #include "smbdirect.h" +#include "../common/smbdirect/smbdirect_pdu.h" #endif #include "cifs_swn.h" #include "cached_dir.h" @@ -458,7 +459,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) seq_printf(m, "\nSMBDirect protocol version: 0x%x " "transport status: %s (%u)", - server->smbd_conn->protocol, + SMBDIRECT_V1, smbdirect_socket_status_string(sc->status), sc->status); seq_printf(m, "\nConn receive_credit_max: %u " diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index efebc4aa297f..6c1bec769e88 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -481,7 +481,6 @@ static bool process_negotiation_response( le16_to_cpu(packet->negotiated_version)); return false; } - info->protocol = le16_to_cpu(packet->negotiated_version); if (packet->credits_requested == 0) { log_rdma_event(ERR, "error: credits_requested==0\n"); diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index 5f9ba769623b..90238a917256 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -39,8 +39,6 @@ extern int smbd_receive_credit_max; struct smbd_connection { struct smbdirect_socket socket; - /* dynamic connection parameters defined in [MS-SMBD] 3.1.1.1 */ - int protocol; /* Memory registrations */ /* Maximum number of pages in a single RDMA write/read on this connection */ From 2449c7cc9bc26f8c80560f376f26c6f50b346c0f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 19 Aug 2025 12:03:59 +0200 Subject: [PATCH 050/159] smb: client: remove unused smbd_connection.count_reassembly_queue This basically represents the same information as sc->recv_io.reassembly.queue_length. The only thing that's different is that smbd_connection.count_reassembly_queue was updated in each loop step, while sc->recv_io.reassembly.queue_length is only updated once after the loop in smbd_recv. Also sc->recv_io.reassembly.queue_length is updated under a spinlock. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/cifs_debug.c | 3 +-- fs/smb/client/smbdirect.c | 2 -- fs/smb/client/smbdirect.h | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index e407bedd4aa7..7cf3b045d3fb 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -482,12 +482,11 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) server->smbd_conn->count_get_receive_buffer, server->smbd_conn->count_put_receive_buffer, server->smbd_conn->count_send_empty); - seq_printf(m, "\nRead Queue count_reassembly_queue: %u " + seq_printf(m, "\nRead Queue " "count_enqueue_reassembly_queue: %u " "count_dequeue_reassembly_queue: %u " "reassembly_data_length: %u " "reassembly_queue_length: %u", - server->smbd_conn->count_reassembly_queue, server->smbd_conn->count_enqueue_reassembly_queue, server->smbd_conn->count_dequeue_reassembly_queue, sc->recv_io.reassembly.data_length, diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 6c1bec769e88..40a423de0e87 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -1353,7 +1353,6 @@ static void enqueue_reassembly( virt_wmb(); sc->recv_io.reassembly.data_length += data_length; spin_unlock(&sc->recv_io.reassembly.lock); - info->count_reassembly_queue++; info->count_enqueue_reassembly_queue++; } @@ -2079,7 +2078,6 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg) &sc->recv_io.reassembly.lock); } queue_removed++; - info->count_reassembly_queue--; info->count_dequeue_reassembly_queue++; put_receive_buffer(info, response); offset = 0; diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index 90238a917256..2b13fa92f2d9 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -66,7 +66,6 @@ struct smbd_connection { /* for debug purposes */ unsigned int count_get_receive_buffer; unsigned int count_put_receive_buffer; - unsigned int count_reassembly_queue; unsigned int count_enqueue_reassembly_queue; unsigned int count_dequeue_reassembly_queue; unsigned int count_send_empty; From ddfcb069c1dd1c909c34605e025e0aeae1b496e3 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 19 Aug 2025 13:54:35 +0200 Subject: [PATCH 051/159] smb: client: make use of smbdirect_socket.statistics This will allow us to use common functions soon. Note this generates the following warnings from scripts/checkpatch.pl --quiet: WARNING: quoted string split across lines #59: FILE: fs/smb/client/cifs_debug.c:481: + seq_printf(m, "\nDebug count_get_receive_buffer: %llu " + "count_put_receive_buffer: %llu count_send_empty: %llu", WARNING: quoted string split across lines #66: FILE: fs/smb/client/cifs_debug.c:486: seq_printf(m, "\nRead Queue " + "count_enqueue_reassembly_queue: %llu " WARNING: quoted string split across lines #67: FILE: fs/smb/client/cifs_debug.c:487: + "count_enqueue_reassembly_queue: %llu " + "count_dequeue_reassembly_queue: %llu " total: 0 errors, 3 warnings, 83 lines checked scripts/checkpatch.pl: FAILED But I left them in there, because it matches the code arround it... Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/cifs_debug.c | 18 +++++++++--------- fs/smb/client/smbdirect.c | 11 ++++++----- fs/smb/client/smbdirect.h | 7 ------- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index 7cf3b045d3fb..55bf867be0e2 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -477,18 +477,18 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) sp->keepalive_interval_msec * 1000, sp->max_read_write_size, server->smbd_conn->rdma_readwrite_threshold); - seq_printf(m, "\nDebug count_get_receive_buffer: %u " - "count_put_receive_buffer: %u count_send_empty: %u", - server->smbd_conn->count_get_receive_buffer, - server->smbd_conn->count_put_receive_buffer, - server->smbd_conn->count_send_empty); + seq_printf(m, "\nDebug count_get_receive_buffer: %llu " + "count_put_receive_buffer: %llu count_send_empty: %llu", + sc->statistics.get_receive_buffer, + sc->statistics.put_receive_buffer, + sc->statistics.send_empty); seq_printf(m, "\nRead Queue " - "count_enqueue_reassembly_queue: %u " - "count_dequeue_reassembly_queue: %u " + "count_enqueue_reassembly_queue: %llu " + "count_dequeue_reassembly_queue: %llu " "reassembly_data_length: %u " "reassembly_queue_length: %u", - server->smbd_conn->count_enqueue_reassembly_queue, - server->smbd_conn->count_dequeue_reassembly_queue, + sc->statistics.enqueue_reassembly_queue, + sc->statistics.dequeue_reassembly_queue, sc->recv_io.reassembly.data_length, sc->recv_io.reassembly.queue_length); seq_printf(m, "\nCurrent Credits send_credits: %u " diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 40a423de0e87..fe4127b53013 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -1212,9 +1212,10 @@ static int smbd_post_send_iter(struct smbd_connection *info, */ static int smbd_post_send_empty(struct smbd_connection *info) { + struct smbdirect_socket *sc = &info->socket; int remaining_data_length = 0; - info->count_send_empty++; + sc->statistics.send_empty++; return smbd_post_send_iter(info, NULL, &remaining_data_length); } @@ -1353,7 +1354,7 @@ static void enqueue_reassembly( virt_wmb(); sc->recv_io.reassembly.data_length += data_length; spin_unlock(&sc->recv_io.reassembly.lock); - info->count_enqueue_reassembly_queue++; + sc->statistics.enqueue_reassembly_queue++; } /* @@ -1392,7 +1393,7 @@ static struct smbdirect_recv_io *get_receive_buffer(struct smbd_connection *info &sc->recv_io.free.list, struct smbdirect_recv_io, list); list_del(&ret->list); - info->count_get_receive_buffer++; + sc->statistics.get_receive_buffer++; } spin_unlock_irqrestore(&sc->recv_io.free.lock, flags); @@ -1421,7 +1422,7 @@ static void put_receive_buffer( spin_lock_irqsave(&sc->recv_io.free.lock, flags); list_add_tail(&response->list, &sc->recv_io.free.list); - info->count_put_receive_buffer++; + sc->statistics.put_receive_buffer++; spin_unlock_irqrestore(&sc->recv_io.free.lock, flags); queue_work(info->workqueue, &sc->recv_io.posted.refill_work); @@ -2078,7 +2079,7 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg) &sc->recv_io.reassembly.lock); } queue_removed++; - info->count_dequeue_reassembly_queue++; + sc->statistics.dequeue_reassembly_queue++; put_receive_buffer(info, response); offset = 0; log_read(INFO, "put_receive_buffer offset=0\n"); diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index 2b13fa92f2d9..8ebbbc0b0499 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -62,13 +62,6 @@ struct smbd_connection { wait_queue_head_t wait_for_mr_cleanup; struct workqueue_struct *workqueue; - - /* for debug purposes */ - unsigned int count_get_receive_buffer; - unsigned int count_put_receive_buffer; - unsigned int count_enqueue_reassembly_queue; - unsigned int count_dequeue_reassembly_queue; - unsigned int count_send_empty; }; /* Create a SMBDirect session */ From a8efb796db30288fab498156ef1fa03a34d88817 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 Aug 2025 14:50:56 +0200 Subject: [PATCH 052/159] smb: client: move rdma_readwrite_threshold from smbd_connection to TCP_Server_Info This belongs to the SMB layer not to the transport layer, it just uses the negotiated transport parameters to adjust the value if needed. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/cifs_debug.c | 2 +- fs/smb/client/cifsglob.h | 7 +++++++ fs/smb/client/smb2pdu.c | 2 +- fs/smb/client/smbdirect.c | 15 +++++++++++---- fs/smb/client/smbdirect.h | 7 ------- 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index 55bf867be0e2..9c9f15871c23 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -476,7 +476,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) "max_readwrite_size: %u rdma_readwrite_threshold: %u", sp->keepalive_interval_msec * 1000, sp->max_read_write_size, - server->smbd_conn->rdma_readwrite_threshold); + server->rdma_readwrite_threshold); seq_printf(m, "\nDebug count_get_receive_buffer: %llu " "count_put_receive_buffer: %llu count_send_empty: %llu", sc->statistics.get_receive_buffer, diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 0fae95cf81c4..80664f937fc7 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -814,6 +814,13 @@ struct TCP_Server_Info { unsigned int max_read; unsigned int max_write; unsigned int min_offload; + /* + * If payload is less than or equal to the threshold, + * use RDMA send/recv to send upper layer I/O. + * If payload is more than the threshold, + * use RDMA read/write through memory registration for I/O. + */ + unsigned int rdma_readwrite_threshold; unsigned int retrans; struct { bool requested; /* "compress" mount option set*/ diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index c3b9d3f6210f..1c63d2c9cc9c 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -4411,7 +4411,7 @@ static inline bool smb3_use_rdma_offload(struct cifs_io_parms *io_parms) return false; /* offload also has its overhead, so only do it if desired */ - if (io_parms->length < server->smbd_conn->rdma_readwrite_threshold) + if (io_parms->length < server->rdma_readwrite_threshold) return false; return true; diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index fe4127b53013..09bf47c854a8 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -518,10 +518,6 @@ static bool process_negotiation_response( } sp->max_fragmented_send_size = le32_to_cpu(packet->max_fragmented_size); - info->rdma_readwrite_threshold = - rdma_readwrite_threshold > sp->max_fragmented_send_size ? - sp->max_fragmented_send_size : - rdma_readwrite_threshold; sp->max_read_write_size = min_t(u32, @@ -1962,6 +1958,7 @@ struct smbd_connection *smbd_get_connection( struct TCP_Server_Info *server, struct sockaddr *dstaddr) { struct smbd_connection *ret; + const struct smbdirect_socket_parameters *sp; int port = SMBD_PORT; try_again: @@ -1972,6 +1969,16 @@ struct smbd_connection *smbd_get_connection( port = SMB_PORT; goto try_again; } + if (!ret) + return NULL; + + sp = &ret->socket.parameters; + + server->rdma_readwrite_threshold = + rdma_readwrite_threshold > sp->max_fragmented_send_size ? + sp->max_fragmented_send_size : + rdma_readwrite_threshold; + return ret; } diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index 8ebbbc0b0499..4eec2ac4ba80 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -43,13 +43,6 @@ struct smbd_connection { /* Memory registrations */ /* Maximum number of pages in a single RDMA write/read on this connection */ int max_frmr_depth; - /* - * If payload is less than or equal to the threshold, - * use RDMA send/recv to send upper layer I/O. - * If payload is more than the threshold, - * use RDMA read/write through memory registration for I/O. - */ - int rdma_readwrite_threshold; enum ib_mr_type mr_type; struct list_head mr_list; spinlock_t mr_list_lock; From 40212a27c75ff22457d958097a27a3d8815b0a70 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 12:29:03 +0200 Subject: [PATCH 053/159] smb: client: make use of smbdirect_socket.workqueue This will simplify the move to common code... Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 32 ++++++++++++++++---------------- fs/smb/client/smbdirect.h | 2 -- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 09bf47c854a8..9ea0383a3ae7 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -214,7 +214,7 @@ static void smbd_disconnect_rdma_connection(struct smbd_connection *info) { struct smbdirect_socket *sc = &info->socket; - queue_work(info->workqueue, &sc->disconnect_work); + queue_work(sc->workqueue, &sc->disconnect_work); } /* Upcall from RDMA CM */ @@ -566,7 +566,7 @@ static void smbd_post_send_credits(struct work_struct *work) if (atomic_read(&sc->recv_io.credits.count) < sc->recv_io.credits.target - 1) { log_keep_alive(INFO, "schedule send of an empty message\n"); - queue_work(info->workqueue, &sc->idle.immediate_work); + queue_work(sc->workqueue, &sc->idle.immediate_work); } } @@ -610,7 +610,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) * order to trigger our next keepalive message. */ sc->idle.keepalive = SMBDIRECT_KEEPALIVE_NONE; - mod_delayed_work(info->workqueue, &sc->idle.timer_work, + mod_delayed_work(sc->workqueue, &sc->idle.timer_work, msecs_to_jiffies(sp->keepalive_interval_msec)); switch (sc->recv_io.expected) { @@ -691,7 +691,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) if (le16_to_cpu(data_transfer->flags) & SMBDIRECT_FLAG_RESPONSE_REQUESTED) { log_keep_alive(INFO, "schedule send of immediate response\n"); - queue_work(info->workqueue, &sc->idle.immediate_work); + queue_work(sc->workqueue, &sc->idle.immediate_work); } /* @@ -700,7 +700,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) */ if (data_length) { if (sc->recv_io.credits.target > old_recv_credit_target) - queue_work(info->workqueue, &sc->recv_io.posted.refill_work); + queue_work(sc->workqueue, &sc->recv_io.posted.refill_work); enqueue_reassembly(info, response, data_length); wake_up(&sc->recv_io.reassembly.wait_queue); @@ -999,7 +999,7 @@ static int manage_keep_alive_before_sending(struct smbd_connection *info) * Now use the keepalive timeout (instead of keepalive interval) * in order to wait for a response */ - mod_delayed_work(info->workqueue, &sc->idle.timer_work, + mod_delayed_work(sc->workqueue, &sc->idle.timer_work, msecs_to_jiffies(sp->keepalive_timeout_msec)); return 1; } @@ -1421,7 +1421,7 @@ static void put_receive_buffer( sc->statistics.put_receive_buffer++; spin_unlock_irqrestore(&sc->recv_io.free.lock, flags); - queue_work(info->workqueue, &sc->recv_io.posted.refill_work); + queue_work(sc->workqueue, &sc->recv_io.posted.refill_work); } /* Preallocate all receive buffer on transport establishment */ @@ -1503,10 +1503,10 @@ static void idle_connection_timer(struct work_struct *work) * in order to wait for a response */ sc->idle.keepalive = SMBDIRECT_KEEPALIVE_PENDING; - mod_delayed_work(info->workqueue, &sc->idle.timer_work, + mod_delayed_work(sc->workqueue, &sc->idle.timer_work, msecs_to_jiffies(sp->keepalive_timeout_msec)); log_keep_alive(INFO, "schedule send of empty idle message\n"); - queue_work(info->workqueue, &sc->idle.immediate_work); + queue_work(sc->workqueue, &sc->idle.immediate_work); } /* @@ -1601,7 +1601,7 @@ void smbd_destroy(struct TCP_Server_Info *server) sc->status = SMBDIRECT_SOCKET_DESTROYED; - destroy_workqueue(info->workqueue); + destroy_workqueue(sc->workqueue); log_rdma_event(INFO, "rdma session destroyed\n"); kfree(info); server->smbd_conn = NULL; @@ -1648,7 +1648,7 @@ static void destroy_caches_and_workqueue(struct smbd_connection *info) struct smbdirect_socket *sc = &info->socket; destroy_receive_buffers(info); - destroy_workqueue(info->workqueue); + destroy_workqueue(sc->workqueue); mempool_destroy(sc->recv_io.mem.pool); kmem_cache_destroy(sc->recv_io.mem.cache); mempool_destroy(sc->send_io.mem.pool); @@ -1704,8 +1704,8 @@ static int allocate_caches_and_workqueue(struct smbd_connection *info) goto out3; scnprintf(name, MAX_NAME_LEN, "smbd_%p", info); - info->workqueue = create_workqueue(name); - if (!info->workqueue) + sc->workqueue = create_workqueue(name); + if (!sc->workqueue) goto out4; rc = allocate_receive_buffers(info, sp->recv_credit_max); @@ -1717,7 +1717,7 @@ static int allocate_caches_and_workqueue(struct smbd_connection *info) return 0; out5: - destroy_workqueue(info->workqueue); + destroy_workqueue(sc->workqueue); out4: mempool_destroy(sc->recv_io.mem.pool); out3: @@ -1901,7 +1901,7 @@ static struct smbd_connection *_smbd_get_connection( * so that the timer will cause a disconnect. */ sc->idle.keepalive = SMBDIRECT_KEEPALIVE_PENDING; - mod_delayed_work(info->workqueue, &sc->idle.timer_work, + mod_delayed_work(sc->workqueue, &sc->idle.timer_work, msecs_to_jiffies(sp->negotiate_timeout_msec)); INIT_WORK(&sc->recv_io.posted.refill_work, smbd_post_send_credits); @@ -2605,7 +2605,7 @@ int smbd_deregister_mr(struct smbd_mr *smbdirect_mr) * Schedule the work to do MR recovery for future I/Os MR * recovery is slow and don't want it to block current I/O */ - queue_work(info->workqueue, &info->mr_recovery_work); + queue_work(sc->workqueue, &info->mr_recovery_work); done: if (atomic_dec_and_test(&info->mr_used_count)) diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index 4eec2ac4ba80..455618e676f5 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -53,8 +53,6 @@ struct smbd_connection { struct work_struct mr_recovery_work; /* Used by transport to wait until all MRs are returned */ wait_queue_head_t wait_for_mr_cleanup; - - struct workqueue_struct *workqueue; }; /* Create a SMBDirect session */ From 5f84b0819a7e678d1004df9aea05d8484ca68ce8 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 00:23:53 +0200 Subject: [PATCH 054/159] smb: client: add and use smbd_get_parameters() In future struct smbdirect_socket_parameters will be the only public structure for the smb layer. This prepares this... Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smb2ops.c | 8 ++++---- fs/smb/client/smbdirect.c | 7 +++++++ fs/smb/client/smbdirect.h | 2 ++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index e586f3f4b5c9..4711a23c5b38 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -504,8 +504,8 @@ smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) wsize = min_t(unsigned int, wsize, server->max_write); #ifdef CONFIG_CIFS_SMB_DIRECT if (server->rdma) { - struct smbdirect_socket_parameters *sp = - &server->smbd_conn->socket.parameters; + const struct smbdirect_socket_parameters *sp = + smbd_get_parameters(server->smbd_conn); if (server->sign) /* @@ -555,8 +555,8 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) rsize = min_t(unsigned int, rsize, server->max_read); #ifdef CONFIG_CIFS_SMB_DIRECT if (server->rdma) { - struct smbdirect_socket_parameters *sp = - &server->smbd_conn->socket.parameters; + const struct smbdirect_socket_parameters *sp = + smbd_get_parameters(server->smbd_conn); if (server->sign) /* diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 9ea0383a3ae7..3aa137710375 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -13,6 +13,13 @@ #include "cifsproto.h" #include "smb2proto.h" +const struct smbdirect_socket_parameters *smbd_get_parameters(struct smbd_connection *conn) +{ + struct smbdirect_socket *sc = &conn->socket; + + return &sc->parameters; +} + static struct smbdirect_recv_io *get_receive_buffer( struct smbd_connection *info); static void put_receive_buffer( diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index 455618e676f5..7773939db5f2 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -59,6 +59,8 @@ struct smbd_connection { struct smbd_connection *smbd_get_connection( struct TCP_Server_Info *server, struct sockaddr *dstaddr); +const struct smbdirect_socket_parameters *smbd_get_parameters(struct smbd_connection *conn); + /* Reconnect SMBDirect session */ int smbd_reconnect(struct TCP_Server_Info *server); /* Destroy SMBDirect session */ From f454f36cd0b9ee3b7b6c7181238ef20f1326063a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 Aug 2025 23:36:33 +0200 Subject: [PATCH 055/159] smb: client: make use of struct smbdirect_mr_io This will allow us to move to common functions in future too. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/cifsglob.h | 2 +- fs/smb/client/smbdirect.c | 66 ++++++++++++++++++++------------------- fs/smb/client/smbdirect.h | 27 ++-------------- 3 files changed, 37 insertions(+), 58 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 80664f937fc7..3ac254e123dc 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -1547,7 +1547,7 @@ struct cifs_io_subrequest { struct kvec iov[2]; struct TCP_Server_Info *server; #ifdef CONFIG_CIFS_SMB_DIRECT - struct smbd_mr *mr; + struct smbdirect_mr_io *mr; #endif struct cifs_credits credits; }; diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 3aa137710375..138d8837a123 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -2229,14 +2229,15 @@ int smbd_send(struct TCP_Server_Info *server, static void register_mr_done(struct ib_cq *cq, struct ib_wc *wc) { - struct smbd_mr *mr; - struct ib_cqe *cqe; + struct smbdirect_mr_io *mr = + container_of(wc->wr_cqe, struct smbdirect_mr_io, cqe); + struct smbdirect_socket *sc = mr->socket; + struct smbd_connection *info = + container_of(sc, struct smbd_connection, socket); if (wc->status) { log_rdma_mr(ERR, "status=%d\n", wc->status); - cqe = wc->wr_cqe; - mr = container_of(cqe, struct smbd_mr, cqe); - smbd_disconnect_rdma_connection(mr->conn); + smbd_disconnect_rdma_connection(info); } } @@ -2254,11 +2255,11 @@ static void smbd_mr_recovery_work(struct work_struct *work) struct smbd_connection *info = container_of(work, struct smbd_connection, mr_recovery_work); struct smbdirect_socket *sc = &info->socket; - struct smbd_mr *smbdirect_mr; + struct smbdirect_mr_io *smbdirect_mr; int rc; list_for_each_entry(smbdirect_mr, &info->mr_list, list) { - if (smbdirect_mr->state == MR_ERROR) { + if (smbdirect_mr->state == SMBDIRECT_MR_ERROR) { /* recover this MR entry */ rc = ib_dereg_mr(smbdirect_mr->mr); @@ -2284,7 +2285,7 @@ static void smbd_mr_recovery_work(struct work_struct *work) /* This MR is being used, don't recover it */ continue; - smbdirect_mr->state = MR_READY; + smbdirect_mr->state = SMBDIRECT_MR_READY; /* smbdirect_mr->state is updated by this function * and is read and updated by I/O issuing CPUs trying @@ -2301,11 +2302,11 @@ static void smbd_mr_recovery_work(struct work_struct *work) static void destroy_mr_list(struct smbd_connection *info) { struct smbdirect_socket *sc = &info->socket; - struct smbd_mr *mr, *tmp; + struct smbdirect_mr_io *mr, *tmp; disable_work_sync(&info->mr_recovery_work); list_for_each_entry_safe(mr, tmp, &info->mr_list, list) { - if (mr->state == MR_INVALIDATED) + if (mr->state == SMBDIRECT_MR_INVALIDATED) ib_dma_unmap_sg(sc->ib.dev, mr->sgt.sgl, mr->sgt.nents, mr->dir); ib_dereg_mr(mr->mr); @@ -2326,7 +2327,7 @@ static int allocate_mr_list(struct smbd_connection *info) struct smbdirect_socket *sc = &info->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; int i; - struct smbd_mr *smbdirect_mr, *tmp; + struct smbdirect_mr_io *smbdirect_mr, *tmp; INIT_LIST_HEAD(&info->mr_list); init_waitqueue_head(&info->wait_mr); @@ -2361,8 +2362,8 @@ static int allocate_mr_list(struct smbd_connection *info) ib_dereg_mr(smbdirect_mr->mr); goto out; } - smbdirect_mr->state = MR_READY; - smbdirect_mr->conn = info; + smbdirect_mr->state = SMBDIRECT_MR_READY; + smbdirect_mr->socket = sc; list_add_tail(&smbdirect_mr->list, &info->mr_list); atomic_inc(&info->mr_ready_count); @@ -2389,10 +2390,10 @@ static int allocate_mr_list(struct smbd_connection *info) * issuing I/O trying to get MR at the same time, mr_list_lock is used to * protect this situation. */ -static struct smbd_mr *get_mr(struct smbd_connection *info) +static struct smbdirect_mr_io *get_mr(struct smbd_connection *info) { struct smbdirect_socket *sc = &info->socket; - struct smbd_mr *ret; + struct smbdirect_mr_io *ret; int rc; again: rc = wait_event_interruptible(info->wait_mr, @@ -2410,8 +2411,8 @@ static struct smbd_mr *get_mr(struct smbd_connection *info) spin_lock(&info->mr_list_lock); list_for_each_entry(ret, &info->mr_list, list) { - if (ret->state == MR_READY) { - ret->state = MR_REGISTERED; + if (ret->state == SMBDIRECT_MR_READY) { + ret->state = SMBDIRECT_MR_REGISTERED; spin_unlock(&info->mr_list_lock); atomic_dec(&info->mr_ready_count); atomic_inc(&info->mr_used_count); @@ -2453,12 +2454,12 @@ static int smbd_iter_to_mr(struct smbd_connection *info, * need_invalidate: true if this MR needs to be locally invalidated after I/O * return value: the MR registered, NULL if failed. */ -struct smbd_mr *smbd_register_mr(struct smbd_connection *info, +struct smbdirect_mr_io *smbd_register_mr(struct smbd_connection *info, struct iov_iter *iter, bool writing, bool need_invalidate) { struct smbdirect_socket *sc = &info->socket; - struct smbd_mr *smbdirect_mr; + struct smbdirect_mr_io *smbdirect_mr; int rc, num_pages; enum dma_data_direction dir; struct ib_reg_wr *reg_wr; @@ -2530,13 +2531,13 @@ struct smbd_mr *smbd_register_mr(struct smbd_connection *info, log_rdma_mr(ERR, "ib_post_send failed rc=%x reg_wr->key=%x\n", rc, reg_wr->key); - /* If all failed, attempt to recover this MR by setting it MR_ERROR*/ + /* If all failed, attempt to recover this MR by setting it SMBDIRECT_MR_ERROR*/ map_mr_error: ib_dma_unmap_sg(sc->ib.dev, smbdirect_mr->sgt.sgl, smbdirect_mr->sgt.nents, smbdirect_mr->dir); dma_map_error: - smbdirect_mr->state = MR_ERROR; + smbdirect_mr->state = SMBDIRECT_MR_ERROR; if (atomic_dec_and_test(&info->mr_used_count)) wake_up(&info->wait_for_mr_cleanup); @@ -2547,15 +2548,15 @@ struct smbd_mr *smbd_register_mr(struct smbd_connection *info, static void local_inv_done(struct ib_cq *cq, struct ib_wc *wc) { - struct smbd_mr *smbdirect_mr; + struct smbdirect_mr_io *smbdirect_mr; struct ib_cqe *cqe; cqe = wc->wr_cqe; - smbdirect_mr = container_of(cqe, struct smbd_mr, cqe); - smbdirect_mr->state = MR_INVALIDATED; + smbdirect_mr = container_of(cqe, struct smbdirect_mr_io, cqe); + smbdirect_mr->state = SMBDIRECT_MR_INVALIDATED; if (wc->status != IB_WC_SUCCESS) { log_rdma_mr(ERR, "invalidate failed status=%x\n", wc->status); - smbdirect_mr->state = MR_ERROR; + smbdirect_mr->state = SMBDIRECT_MR_ERROR; } complete(&smbdirect_mr->invalidate_done); } @@ -2566,11 +2567,12 @@ static void local_inv_done(struct ib_cq *cq, struct ib_wc *wc) * and we have to locally invalidate the buffer to prevent data is being * modified by remote peer after upper layer consumes it */ -int smbd_deregister_mr(struct smbd_mr *smbdirect_mr) +int smbd_deregister_mr(struct smbdirect_mr_io *smbdirect_mr) { struct ib_send_wr *wr; - struct smbd_connection *info = smbdirect_mr->conn; - struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket *sc = smbdirect_mr->socket; + struct smbd_connection *info = + container_of(sc, struct smbd_connection, socket); int rc = 0; if (smbdirect_mr->need_invalidate) { @@ -2594,17 +2596,17 @@ int smbd_deregister_mr(struct smbd_mr *smbdirect_mr) smbdirect_mr->need_invalidate = false; } else /* - * For remote invalidation, just set it to MR_INVALIDATED + * For remote invalidation, just set it to SMBDIRECT_MR_INVALIDATED * and defer to mr_recovery_work to recover the MR for next use */ - smbdirect_mr->state = MR_INVALIDATED; + smbdirect_mr->state = SMBDIRECT_MR_INVALIDATED; - if (smbdirect_mr->state == MR_INVALIDATED) { + if (smbdirect_mr->state == SMBDIRECT_MR_INVALIDATED) { ib_dma_unmap_sg( sc->ib.dev, smbdirect_mr->sgt.sgl, smbdirect_mr->sgt.nents, smbdirect_mr->dir); - smbdirect_mr->state = MR_READY; + smbdirect_mr->state = SMBDIRECT_MR_READY; if (atomic_inc_return(&info->mr_ready_count) == 1) wake_up(&info->wait_mr); } else diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index 7773939db5f2..83e726967b2f 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -71,34 +71,11 @@ 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); -enum mr_state { - MR_READY, - MR_REGISTERED, - MR_INVALIDATED, - MR_ERROR -}; - -struct smbd_mr { - struct smbd_connection *conn; - struct list_head list; - enum mr_state state; - struct ib_mr *mr; - struct sg_table sgt; - enum dma_data_direction dir; - union { - struct ib_reg_wr wr; - struct ib_send_wr inv_wr; - }; - struct ib_cqe cqe; - bool need_invalidate; - struct completion invalidate_done; -}; - /* Interfaces to register and deregister MR for RDMA read/write */ -struct smbd_mr *smbd_register_mr( +struct smbdirect_mr_io *smbd_register_mr( struct smbd_connection *info, struct iov_iter *iter, bool writing, bool need_invalidate); -int smbd_deregister_mr(struct smbd_mr *mr); +int smbd_deregister_mr(struct smbdirect_mr_io *mr); #else #define cifs_rdma_enabled(server) 0 From 9a52e3b0d63fc5eaefee3707136fa3c5258ae39e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 00:32:34 +0200 Subject: [PATCH 056/159] smb: client: make use of smbdirect_socket_parameters.max_frmr_depth This make it easier to have common code later. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/cifs_debug.c | 2 +- fs/smb/client/file.c | 16 ++++++++++++---- fs/smb/client/smbdirect.c | 34 ++++++++++++++++++---------------- fs/smb/client/smbdirect.h | 2 -- 4 files changed, 31 insertions(+), 23 deletions(-) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index 9c9f15871c23..72d1ae56290f 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -501,7 +501,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) seq_printf(m, "\nMR responder_resources: %u " "max_frmr_depth: %u mr_type: 0x%x", sp->responder_resources, - server->smbd_conn->max_frmr_depth, + sp->max_frmr_depth, server->smbd_conn->mr_type); seq_printf(m, "\nMR mr_ready_count: %u mr_used_count: %u", atomic_read(&server->smbd_conn->mr_ready_count), diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index cb907e18cc35..a5ed742afa00 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -97,8 +97,12 @@ static void cifs_prepare_write(struct netfs_io_subrequest *subreq) cifs_trace_rw_credits_write_prepare); #ifdef CONFIG_CIFS_SMB_DIRECT - if (server->smbd_conn) - stream->sreq_max_segs = server->smbd_conn->max_frmr_depth; + if (server->smbd_conn) { + const struct smbdirect_socket_parameters *sp = + smbd_get_parameters(server->smbd_conn); + + stream->sreq_max_segs = sp->max_frmr_depth; + } #endif } @@ -187,8 +191,12 @@ static int cifs_prepare_read(struct netfs_io_subrequest *subreq) cifs_trace_rw_credits_read_submit); #ifdef CONFIG_CIFS_SMB_DIRECT - if (server->smbd_conn) - rreq->io_streams[0].sreq_max_segs = server->smbd_conn->max_frmr_depth; + if (server->smbd_conn) { + const struct smbdirect_socket_parameters *sp = + smbd_get_parameters(server->smbd_conn); + + rreq->io_streams[0].sreq_max_segs = sp->max_frmr_depth; + } #endif return 0; } diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 138d8837a123..f85c14261c59 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -472,8 +472,6 @@ static bool process_negotiation_response( struct smbdirect_recv_io *response, int packet_length) { struct smbdirect_socket *sc = response->socket; - struct smbd_connection *info = - container_of(sc, struct smbd_connection, socket); struct smbdirect_socket_parameters *sp = &sc->parameters; struct smbdirect_negotiate_resp *packet = smbdirect_recv_io_payload(response); @@ -529,8 +527,8 @@ static bool process_negotiation_response( sp->max_read_write_size = min_t(u32, le32_to_cpu(packet->max_readwrite_size), - info->max_frmr_depth * PAGE_SIZE); - info->max_frmr_depth = sp->max_read_write_size / PAGE_SIZE; + sp->max_frmr_depth * PAGE_SIZE); + sp->max_frmr_depth = sp->max_read_write_size / PAGE_SIZE; sc->recv_io.expected = SMBDIRECT_EXPECT_DATA_TRANSFER; return true; @@ -837,6 +835,7 @@ static int smbd_ia_open( struct sockaddr *dstaddr, int port) { struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; int rc; WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_CREATED); @@ -857,8 +856,8 @@ static int smbd_ia_open( rc = -EPROTONOSUPPORT; goto out2; } - info->max_frmr_depth = min_t(int, - smbd_max_frmr_depth, + sp->max_frmr_depth = min_t(u32, + sp->max_frmr_depth, sc->ib.dev->attrs.max_fast_reg_page_list_len); info->mr_type = IB_MR_TYPE_MEM_REG; if (sc->ib.dev->attrs.kernel_cap_flags & IBK_SG_GAPS_REG) @@ -1770,6 +1769,7 @@ static struct smbd_connection *_smbd_get_connection( sp->max_send_size = smbd_max_send_size; sp->max_fragmented_recv_size = smbd_max_fragmented_recv_size; sp->max_recv_size = smbd_max_receive_size; + sp->max_frmr_depth = smbd_max_frmr_depth; sp->keepalive_interval_msec = smbd_keep_alive_interval * 1000; sp->keepalive_timeout_msec = KEEPALIVE_RECV_TIMEOUT * 1000; @@ -2255,6 +2255,7 @@ static void smbd_mr_recovery_work(struct work_struct *work) struct smbd_connection *info = container_of(work, struct smbd_connection, mr_recovery_work); struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; struct smbdirect_mr_io *smbdirect_mr; int rc; @@ -2273,11 +2274,11 @@ static void smbd_mr_recovery_work(struct work_struct *work) smbdirect_mr->mr = ib_alloc_mr( sc->ib.pd, info->mr_type, - info->max_frmr_depth); + sp->max_frmr_depth); if (IS_ERR(smbdirect_mr->mr)) { log_rdma_mr(ERR, "ib_alloc_mr failed mr_type=%x max_frmr_depth=%x\n", info->mr_type, - info->max_frmr_depth); + sp->max_frmr_depth); smbd_disconnect_rdma_connection(info); continue; } @@ -2348,13 +2349,13 @@ static int allocate_mr_list(struct smbd_connection *info) if (!smbdirect_mr) goto cleanup_entries; smbdirect_mr->mr = ib_alloc_mr(sc->ib.pd, info->mr_type, - info->max_frmr_depth); + sp->max_frmr_depth); if (IS_ERR(smbdirect_mr->mr)) { log_rdma_mr(ERR, "ib_alloc_mr failed mr_type=%x max_frmr_depth=%x\n", - info->mr_type, info->max_frmr_depth); + info->mr_type, sp->max_frmr_depth); goto out; } - smbdirect_mr->sgt.sgl = kcalloc(info->max_frmr_depth, + smbdirect_mr->sgt.sgl = kcalloc(sp->max_frmr_depth, sizeof(struct scatterlist), GFP_KERNEL); if (!smbdirect_mr->sgt.sgl) { @@ -2459,15 +2460,16 @@ struct smbdirect_mr_io *smbd_register_mr(struct smbd_connection *info, bool writing, bool need_invalidate) { struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; struct smbdirect_mr_io *smbdirect_mr; int rc, num_pages; enum dma_data_direction dir; struct ib_reg_wr *reg_wr; - num_pages = iov_iter_npages(iter, info->max_frmr_depth + 1); - if (num_pages > info->max_frmr_depth) { + num_pages = iov_iter_npages(iter, sp->max_frmr_depth + 1); + if (num_pages > sp->max_frmr_depth) { log_rdma_mr(ERR, "num_pages=%d max_frmr_depth=%d\n", - num_pages, info->max_frmr_depth); + num_pages, sp->max_frmr_depth); WARN_ON_ONCE(1); return NULL; } @@ -2485,8 +2487,8 @@ struct smbdirect_mr_io *smbd_register_mr(struct smbd_connection *info, smbdirect_mr->sgt.orig_nents = 0; log_rdma_mr(INFO, "num_pages=0x%x count=0x%zx depth=%u\n", - num_pages, iov_iter_count(iter), info->max_frmr_depth); - smbd_iter_to_mr(info, iter, &smbdirect_mr->sgt, info->max_frmr_depth); + num_pages, iov_iter_count(iter), sp->max_frmr_depth); + smbd_iter_to_mr(info, iter, &smbdirect_mr->sgt, sp->max_frmr_depth); rc = ib_dma_map_sg(sc->ib.dev, smbdirect_mr->sgt.sgl, smbdirect_mr->sgt.nents, dir); diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index 83e726967b2f..c88ba6e11dd1 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -41,8 +41,6 @@ struct smbd_connection { /* Memory registrations */ - /* Maximum number of pages in a single RDMA write/read on this connection */ - int max_frmr_depth; enum ib_mr_type mr_type; struct list_head mr_list; spinlock_t mr_list_lock; From 02e6f092c7aa1fa12337978837ad64d1b75bbc82 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 00:57:19 +0200 Subject: [PATCH 057/159] smb: client: make use of smbdirect_socket.mr_io Now struct smbd_connection only contains struct smbdirect_socket, this is an important step towards having common functions as well. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/cifs_debug.c | 6 +-- fs/smb/client/smbdirect.c | 81 +++++++++++++++++--------------------- fs/smb/client/smbdirect.h | 13 ------ 3 files changed, 40 insertions(+), 60 deletions(-) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index 72d1ae56290f..35c4d27d2cc0 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -502,10 +502,10 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) "max_frmr_depth: %u mr_type: 0x%x", sp->responder_resources, sp->max_frmr_depth, - server->smbd_conn->mr_type); + sc->mr_io.type); seq_printf(m, "\nMR mr_ready_count: %u mr_used_count: %u", - atomic_read(&server->smbd_conn->mr_ready_count), - atomic_read(&server->smbd_conn->mr_used_count)); + atomic_read(&sc->mr_io.ready.count), + atomic_read(&sc->mr_io.used.count)); skip_rdma: #endif seq_printf(m, "\nNumber of credits: %d,%d,%d Dialect 0x%x", diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index f85c14261c59..12235aa6e555 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -169,8 +169,6 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) { struct smbdirect_socket *sc = container_of(work, struct smbdirect_socket, disconnect_work); - struct smbd_connection *info = - container_of(sc, struct smbd_connection, socket); /* * make sure this and other work is not queued again @@ -179,7 +177,7 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) */ disable_work(&sc->disconnect_work); disable_work(&sc->recv_io.posted.refill_work); - disable_work(&info->mr_recovery_work); + disable_work(&sc->mr_io.recovery_work); disable_work(&sc->idle.immediate_work); disable_delayed_work(&sc->idle.timer_work); @@ -859,9 +857,9 @@ static int smbd_ia_open( sp->max_frmr_depth = min_t(u32, sp->max_frmr_depth, sc->ib.dev->attrs.max_fast_reg_page_list_len); - info->mr_type = IB_MR_TYPE_MEM_REG; + sc->mr_io.type = IB_MR_TYPE_MEM_REG; if (sc->ib.dev->attrs.kernel_cap_flags & IBK_SG_GAPS_REG) - info->mr_type = IB_MR_TYPE_SG_GAPS; + sc->mr_io.type = IB_MR_TYPE_SG_GAPS; sc->ib.pd = ib_alloc_pd(sc->ib.dev, 0); if (IS_ERR(sc->ib.pd)) { @@ -1585,8 +1583,8 @@ void smbd_destroy(struct TCP_Server_Info *server) * path when sending data, and then release memory registrations. */ log_rdma_event(INFO, "freeing mr list\n"); - wake_up_all(&info->wait_mr); - while (atomic_read(&info->mr_used_count)) { + wake_up_all(&sc->mr_io.ready.wait_queue); + while (atomic_read(&sc->mr_io.used.count)) { cifs_server_unlock(server); msleep(1000); cifs_server_lock(server); @@ -2252,14 +2250,15 @@ static void register_mr_done(struct ib_cq *cq, struct ib_wc *wc) */ static void smbd_mr_recovery_work(struct work_struct *work) { - struct smbd_connection *info = - container_of(work, struct smbd_connection, mr_recovery_work); - struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket *sc = + container_of(work, struct smbdirect_socket, mr_io.recovery_work); struct smbdirect_socket_parameters *sp = &sc->parameters; + struct smbd_connection *info = + container_of(sc, struct smbd_connection, socket); struct smbdirect_mr_io *smbdirect_mr; int rc; - list_for_each_entry(smbdirect_mr, &info->mr_list, list) { + list_for_each_entry(smbdirect_mr, &sc->mr_io.all.list, list) { if (smbdirect_mr->state == SMBDIRECT_MR_ERROR) { /* recover this MR entry */ @@ -2273,11 +2272,11 @@ static void smbd_mr_recovery_work(struct work_struct *work) } smbdirect_mr->mr = ib_alloc_mr( - sc->ib.pd, info->mr_type, + sc->ib.pd, sc->mr_io.type, sp->max_frmr_depth); if (IS_ERR(smbdirect_mr->mr)) { log_rdma_mr(ERR, "ib_alloc_mr failed mr_type=%x max_frmr_depth=%x\n", - info->mr_type, + sc->mr_io.type, sp->max_frmr_depth); smbd_disconnect_rdma_connection(info); continue; @@ -2295,8 +2294,8 @@ static void smbd_mr_recovery_work(struct work_struct *work) * value is updated before waking up any calls to * get_mr() from the I/O issuing CPUs */ - if (atomic_inc_return(&info->mr_ready_count) == 1) - wake_up(&info->wait_mr); + if (atomic_inc_return(&sc->mr_io.ready.count) == 1) + wake_up(&sc->mr_io.ready.wait_queue); } } @@ -2305,8 +2304,8 @@ static void destroy_mr_list(struct smbd_connection *info) struct smbdirect_socket *sc = &info->socket; struct smbdirect_mr_io *mr, *tmp; - disable_work_sync(&info->mr_recovery_work); - list_for_each_entry_safe(mr, tmp, &info->mr_list, list) { + disable_work_sync(&sc->mr_io.recovery_work); + list_for_each_entry_safe(mr, tmp, &sc->mr_io.all.list, list) { if (mr->state == SMBDIRECT_MR_INVALIDATED) ib_dma_unmap_sg(sc->ib.dev, mr->sgt.sgl, mr->sgt.nents, mr->dir); @@ -2330,13 +2329,7 @@ static int allocate_mr_list(struct smbd_connection *info) int i; struct smbdirect_mr_io *smbdirect_mr, *tmp; - INIT_LIST_HEAD(&info->mr_list); - init_waitqueue_head(&info->wait_mr); - spin_lock_init(&info->mr_list_lock); - atomic_set(&info->mr_ready_count, 0); - atomic_set(&info->mr_used_count, 0); - init_waitqueue_head(&info->wait_for_mr_cleanup); - INIT_WORK(&info->mr_recovery_work, smbd_mr_recovery_work); + INIT_WORK(&sc->mr_io.recovery_work, smbd_mr_recovery_work); if (sp->responder_resources == 0) { log_rdma_mr(ERR, "responder_resources negotiated as 0\n"); @@ -2348,11 +2341,11 @@ static int allocate_mr_list(struct smbd_connection *info) smbdirect_mr = kzalloc(sizeof(*smbdirect_mr), GFP_KERNEL); if (!smbdirect_mr) goto cleanup_entries; - smbdirect_mr->mr = ib_alloc_mr(sc->ib.pd, info->mr_type, + smbdirect_mr->mr = ib_alloc_mr(sc->ib.pd, sc->mr_io.type, sp->max_frmr_depth); if (IS_ERR(smbdirect_mr->mr)) { log_rdma_mr(ERR, "ib_alloc_mr failed mr_type=%x max_frmr_depth=%x\n", - info->mr_type, sp->max_frmr_depth); + sc->mr_io.type, sp->max_frmr_depth); goto out; } smbdirect_mr->sgt.sgl = kcalloc(sp->max_frmr_depth, @@ -2366,15 +2359,15 @@ static int allocate_mr_list(struct smbd_connection *info) smbdirect_mr->state = SMBDIRECT_MR_READY; smbdirect_mr->socket = sc; - list_add_tail(&smbdirect_mr->list, &info->mr_list); - atomic_inc(&info->mr_ready_count); + list_add_tail(&smbdirect_mr->list, &sc->mr_io.all.list); + atomic_inc(&sc->mr_io.ready.count); } return 0; out: kfree(smbdirect_mr); cleanup_entries: - list_for_each_entry_safe(smbdirect_mr, tmp, &info->mr_list, list) { + list_for_each_entry_safe(smbdirect_mr, tmp, &sc->mr_io.all.list, list) { list_del(&smbdirect_mr->list); ib_dereg_mr(smbdirect_mr->mr); kfree(smbdirect_mr->sgt.sgl); @@ -2397,8 +2390,8 @@ static struct smbdirect_mr_io *get_mr(struct smbd_connection *info) struct smbdirect_mr_io *ret; int rc; again: - rc = wait_event_interruptible(info->wait_mr, - atomic_read(&info->mr_ready_count) || + rc = wait_event_interruptible(sc->mr_io.ready.wait_queue, + atomic_read(&sc->mr_io.ready.count) || sc->status != SMBDIRECT_SOCKET_CONNECTED); if (rc) { log_rdma_mr(ERR, "wait_event_interruptible rc=%x\n", rc); @@ -2410,18 +2403,18 @@ static struct smbdirect_mr_io *get_mr(struct smbd_connection *info) return NULL; } - spin_lock(&info->mr_list_lock); - list_for_each_entry(ret, &info->mr_list, list) { + spin_lock(&sc->mr_io.all.lock); + list_for_each_entry(ret, &sc->mr_io.all.list, list) { if (ret->state == SMBDIRECT_MR_READY) { ret->state = SMBDIRECT_MR_REGISTERED; - spin_unlock(&info->mr_list_lock); - atomic_dec(&info->mr_ready_count); - atomic_inc(&info->mr_used_count); + spin_unlock(&sc->mr_io.all.lock); + atomic_dec(&sc->mr_io.ready.count); + atomic_inc(&sc->mr_io.used.count); return ret; } } - spin_unlock(&info->mr_list_lock); + spin_unlock(&sc->mr_io.all.lock); /* * It is possible that we could fail to get MR because other processes may * try to acquire a MR at the same time. If this is the case, retry it. @@ -2540,8 +2533,8 @@ struct smbdirect_mr_io *smbd_register_mr(struct smbd_connection *info, dma_map_error: smbdirect_mr->state = SMBDIRECT_MR_ERROR; - if (atomic_dec_and_test(&info->mr_used_count)) - wake_up(&info->wait_for_mr_cleanup); + if (atomic_dec_and_test(&sc->mr_io.used.count)) + wake_up(&sc->mr_io.cleanup.wait_queue); smbd_disconnect_rdma_connection(info); @@ -2609,18 +2602,18 @@ int smbd_deregister_mr(struct smbdirect_mr_io *smbdirect_mr) smbdirect_mr->sgt.nents, smbdirect_mr->dir); smbdirect_mr->state = SMBDIRECT_MR_READY; - if (atomic_inc_return(&info->mr_ready_count) == 1) - wake_up(&info->wait_mr); + if (atomic_inc_return(&sc->mr_io.ready.count) == 1) + wake_up(&sc->mr_io.ready.wait_queue); } else /* * Schedule the work to do MR recovery for future I/Os MR * recovery is slow and don't want it to block current I/O */ - queue_work(sc->workqueue, &info->mr_recovery_work); + queue_work(sc->workqueue, &sc->mr_io.recovery_work); done: - if (atomic_dec_and_test(&info->mr_used_count)) - wake_up(&info->wait_for_mr_cleanup); + if (atomic_dec_and_test(&sc->mr_io.used.count)) + wake_up(&sc->mr_io.cleanup.wait_queue); return rc; } diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index c88ba6e11dd1..d67ac5ddaff4 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -38,19 +38,6 @@ extern int smbd_receive_credit_max; */ struct smbd_connection { struct smbdirect_socket socket; - - - /* Memory registrations */ - enum ib_mr_type mr_type; - struct list_head mr_list; - spinlock_t mr_list_lock; - /* The number of available MRs ready for memory registration */ - atomic_t mr_ready_count; - atomic_t mr_used_count; - wait_queue_head_t wait_mr; - struct work_struct mr_recovery_work; - /* Used by transport to wait until all MRs are returned */ - wait_queue_head_t wait_for_mr_cleanup; }; /* Create a SMBDirect session */ From f6de7482b42941056f2b3cef0e831abce62ebfa7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 01:07:11 +0200 Subject: [PATCH 058/159] smb: client: pass struct smbdirect_socket to {get,put}_receive_buffer() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 12235aa6e555..db37676ced7e 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -21,9 +21,9 @@ const struct smbdirect_socket_parameters *smbd_get_parameters(struct smbd_connec } static struct smbdirect_recv_io *get_receive_buffer( - struct smbd_connection *info); + struct smbdirect_socket *sc); static void put_receive_buffer( - struct smbd_connection *info, + struct smbdirect_socket *sc, struct smbdirect_recv_io *response); static int allocate_receive_buffers(struct smbd_connection *info, int num_buf); static void destroy_receive_buffers(struct smbd_connection *info); @@ -548,7 +548,7 @@ static void smbd_post_send_credits(struct work_struct *work) if (sc->recv_io.credits.target > atomic_read(&sc->recv_io.credits.count)) { while (true) { - response = get_receive_buffer(info); + response = get_receive_buffer(sc); if (!response) break; @@ -557,7 +557,7 @@ static void smbd_post_send_credits(struct work_struct *work) if (rc) { log_rdma_recv(ERR, "post_recv failed rc=%d\n", rc); - put_receive_buffer(info, response); + put_receive_buffer(sc, response); break; } @@ -623,7 +623,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) sc->recv_io.reassembly.full_packet_received = true; negotiate_done = process_negotiation_response(response, wc->byte_len); - put_receive_buffer(info, response); + put_receive_buffer(sc, response); WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_NEGOTIATE_RUNNING); if (!negotiate_done) { sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED; @@ -708,7 +708,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) enqueue_reassembly(info, response, data_length); wake_up(&sc->recv_io.reassembly.wait_queue); } else - put_receive_buffer(info, response); + put_receive_buffer(sc, response); return; @@ -723,7 +723,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) log_rdma_recv(ERR, "unexpected response type=%d\n", sc->recv_io.expected); WARN_ON_ONCE(sc->recv_io.expected != SMBDIRECT_EXPECT_DATA_TRANSFER); error: - put_receive_buffer(info, response); + put_receive_buffer(sc, response); smbd_disconnect_rdma_connection(info); } @@ -1287,7 +1287,7 @@ static int smbd_negotiate(struct smbd_connection *info) struct smbdirect_socket *sc = &info->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; int rc; - struct smbdirect_recv_io *response = get_receive_buffer(info); + struct smbdirect_recv_io *response = get_receive_buffer(sc); WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_NEGOTIATE_NEEDED); sc->status = SMBDIRECT_SOCKET_NEGOTIATE_RUNNING; @@ -1298,7 +1298,7 @@ static int smbd_negotiate(struct smbd_connection *info) rc, response->sge.addr, response->sge.length, response->sge.lkey); if (rc) { - put_receive_buffer(info, response); + put_receive_buffer(sc, response); return rc; } @@ -1381,9 +1381,8 @@ static struct smbdirect_recv_io *_get_first_reassembly(struct smbd_connection *i * pre-allocated in advance. * return value: the receive buffer, NULL if none is available */ -static struct smbdirect_recv_io *get_receive_buffer(struct smbd_connection *info) +static struct smbdirect_recv_io *get_receive_buffer(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &info->socket; struct smbdirect_recv_io *ret = NULL; unsigned long flags; @@ -1407,9 +1406,8 @@ static struct smbdirect_recv_io *get_receive_buffer(struct smbd_connection *info * receive buffer is returned. */ static void put_receive_buffer( - struct smbd_connection *info, struct smbdirect_recv_io *response) + struct smbdirect_socket *sc, struct smbdirect_recv_io *response) { - struct smbdirect_socket *sc = &info->socket; unsigned long flags; if (likely(response->sge.length != 0)) { @@ -1464,7 +1462,7 @@ static void destroy_receive_buffers(struct smbd_connection *info) struct smbdirect_socket *sc = &info->socket; struct smbdirect_recv_io *response; - while ((response = get_receive_buffer(info))) + while ((response = get_receive_buffer(sc))) mempool_free(response, sc->recv_io.mem.pool); } @@ -1565,7 +1563,7 @@ void smbd_destroy(struct TCP_Server_Info *server) list_del(&response->list); spin_unlock_irqrestore( &sc->recv_io.reassembly.lock, flags); - put_receive_buffer(info, response); + put_receive_buffer(sc, response); } else spin_unlock_irqrestore( &sc->recv_io.reassembly.lock, flags); @@ -2092,7 +2090,7 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg) } queue_removed++; sc->statistics.dequeue_reassembly_queue++; - put_receive_buffer(info, response); + put_receive_buffer(sc, response); offset = 0; log_read(INFO, "put_receive_buffer offset=0\n"); } else From 163e0ff8c6e1ba5d436e125291d05951dcc6ba1c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 01:11:36 +0200 Subject: [PATCH 059/159] smb: client: pass struct smbdirect_socket to {allocate,destroy}_receive_buffers() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index db37676ced7e..91bdf1e34f8c 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -25,8 +25,8 @@ static struct smbdirect_recv_io *get_receive_buffer( static void put_receive_buffer( struct smbdirect_socket *sc, struct smbdirect_recv_io *response); -static int allocate_receive_buffers(struct smbd_connection *info, int num_buf); -static void destroy_receive_buffers(struct smbd_connection *info); +static int allocate_receive_buffers(struct smbdirect_socket *sc, int num_buf); +static void destroy_receive_buffers(struct smbdirect_socket *sc); static void enqueue_reassembly( struct smbd_connection *info, @@ -1427,9 +1427,8 @@ static void put_receive_buffer( } /* Preallocate all receive buffer on transport establishment */ -static int allocate_receive_buffers(struct smbd_connection *info, int num_buf) +static int allocate_receive_buffers(struct smbdirect_socket *sc, int num_buf) { - struct smbdirect_socket *sc = &info->socket; struct smbdirect_recv_io *response; int i; @@ -1457,9 +1456,8 @@ static int allocate_receive_buffers(struct smbd_connection *info, int num_buf) return -ENOMEM; } -static void destroy_receive_buffers(struct smbd_connection *info) +static void destroy_receive_buffers(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &info->socket; struct smbdirect_recv_io *response; while ((response = get_receive_buffer(sc))) @@ -1571,7 +1569,7 @@ void smbd_destroy(struct TCP_Server_Info *server) sc->recv_io.reassembly.data_length = 0; log_rdma_event(INFO, "free receive buffers\n"); - destroy_receive_buffers(info); + destroy_receive_buffers(sc); /* * For performance reasons, memory registration and deregistration @@ -1649,7 +1647,7 @@ static void destroy_caches_and_workqueue(struct smbd_connection *info) { struct smbdirect_socket *sc = &info->socket; - destroy_receive_buffers(info); + destroy_receive_buffers(sc); destroy_workqueue(sc->workqueue); mempool_destroy(sc->recv_io.mem.pool); kmem_cache_destroy(sc->recv_io.mem.cache); @@ -1710,7 +1708,7 @@ static int allocate_caches_and_workqueue(struct smbd_connection *info) if (!sc->workqueue) goto out4; - rc = allocate_receive_buffers(info, sp->recv_credit_max); + rc = allocate_receive_buffers(sc, sp->recv_credit_max); if (rc) { log_rdma_event(ERR, "failed to allocate receive buffers\n"); goto out5; From b8a5d5d1aa00728a4604cc2c2775c0664e821173 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 01:14:38 +0200 Subject: [PATCH 060/159] smb: client: pass struct smbdirect_socket to {allocate,destroy}_caches_and_workqueue() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 91bdf1e34f8c..0ac4b76ed76b 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -1643,10 +1643,8 @@ int smbd_reconnect(struct TCP_Server_Info *server) return -ENOENT; } -static void destroy_caches_and_workqueue(struct smbd_connection *info) +static void destroy_caches_and_workqueue(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &info->socket; - destroy_receive_buffers(sc); destroy_workqueue(sc->workqueue); mempool_destroy(sc->recv_io.mem.pool); @@ -1656,9 +1654,8 @@ static void destroy_caches_and_workqueue(struct smbd_connection *info) } #define MAX_NAME_LEN 80 -static int allocate_caches_and_workqueue(struct smbd_connection *info) +static int allocate_caches_and_workqueue(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &info->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; char name[MAX_NAME_LEN]; int rc; @@ -1666,7 +1663,7 @@ static int allocate_caches_and_workqueue(struct smbd_connection *info) if (WARN_ON_ONCE(sp->max_recv_size < sizeof(struct smbdirect_data_transfer))) return -ENOMEM; - scnprintf(name, MAX_NAME_LEN, "smbdirect_send_io_%p", info); + scnprintf(name, MAX_NAME_LEN, "smbdirect_send_io_%p", sc); sc->send_io.mem.cache = kmem_cache_create( name, @@ -1682,7 +1679,7 @@ static int allocate_caches_and_workqueue(struct smbd_connection *info) if (!sc->send_io.mem.pool) goto out1; - scnprintf(name, MAX_NAME_LEN, "smbdirect_recv_io_%p", info); + scnprintf(name, MAX_NAME_LEN, "smbdirect_recv_io_%p", sc); struct kmem_cache_args response_args = { .align = __alignof__(struct smbdirect_recv_io), @@ -1703,7 +1700,7 @@ static int allocate_caches_and_workqueue(struct smbd_connection *info) if (!sc->recv_io.mem.pool) goto out3; - scnprintf(name, MAX_NAME_LEN, "smbd_%p", info); + scnprintf(name, MAX_NAME_LEN, "smbd_%p", sc); sc->workqueue = create_workqueue(name); if (!sc->workqueue) goto out4; @@ -1889,7 +1886,7 @@ static struct smbd_connection *_smbd_get_connection( log_rdma_event(INFO, "rdma_connect connected\n"); - rc = allocate_caches_and_workqueue(info); + rc = allocate_caches_and_workqueue(sc); if (rc) { log_rdma_event(ERR, "cache allocation failed\n"); goto allocate_cache_failed; @@ -1929,7 +1926,7 @@ static struct smbd_connection *_smbd_get_connection( negotiation_failed: disable_delayed_work_sync(&sc->idle.timer_work); - destroy_caches_and_workqueue(info); + destroy_caches_and_workqueue(sc); sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED; rdma_disconnect(sc->rdma.cm_id); wait_event(sc->status_wait, From 419fc78fd81ffa6d6da847ba46050db1da64b874 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 01:17:35 +0200 Subject: [PATCH 061/159] smb: client: pass struct smbdirect_socket to {enqueue,_get_first}_reassembly() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 0ac4b76ed76b..8e354d10038a 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -29,10 +29,10 @@ static int allocate_receive_buffers(struct smbdirect_socket *sc, int num_buf); static void destroy_receive_buffers(struct smbdirect_socket *sc); static void enqueue_reassembly( - struct smbd_connection *info, + struct smbdirect_socket *sc, struct smbdirect_recv_io *response, int data_length); static struct smbdirect_recv_io *_get_first_reassembly( - struct smbd_connection *info); + struct smbdirect_socket *sc); static int smbd_post_recv( struct smbd_connection *info, @@ -705,7 +705,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) if (sc->recv_io.credits.target > old_recv_credit_target) queue_work(sc->workqueue, &sc->recv_io.posted.refill_work); - enqueue_reassembly(info, response, data_length); + enqueue_reassembly(sc, response, data_length); wake_up(&sc->recv_io.reassembly.wait_queue); } else put_receive_buffer(sc, response); @@ -1336,12 +1336,10 @@ static int smbd_negotiate(struct smbd_connection *info) * data_length: the size of payload in this packet */ static void enqueue_reassembly( - struct smbd_connection *info, + struct smbdirect_socket *sc, struct smbdirect_recv_io *response, int data_length) { - struct smbdirect_socket *sc = &info->socket; - spin_lock(&sc->recv_io.reassembly.lock); list_add_tail(&response->list, &sc->recv_io.reassembly.list); sc->recv_io.reassembly.queue_length++; @@ -1362,9 +1360,8 @@ static void enqueue_reassembly( * Caller is responsible for locking * return value: the first entry if any, NULL if queue is empty */ -static struct smbdirect_recv_io *_get_first_reassembly(struct smbd_connection *info) +static struct smbdirect_recv_io *_get_first_reassembly(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &info->socket; struct smbdirect_recv_io *ret = NULL; if (!list_empty(&sc->recv_io.reassembly.list)) { @@ -1556,7 +1553,7 @@ void smbd_destroy(struct TCP_Server_Info *server) log_rdma_event(INFO, "drain the reassembly queue\n"); do { spin_lock_irqsave(&sc->recv_io.reassembly.lock, flags); - response = _get_first_reassembly(info); + response = _get_first_reassembly(sc); if (response) { list_del(&response->list); spin_unlock_irqrestore( @@ -2032,7 +2029,7 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg) to_read = size; offset = sc->recv_io.reassembly.first_entry_offset; while (data_read < size) { - response = _get_first_reassembly(info); + response = _get_first_reassembly(sc); data_transfer = smbdirect_recv_io_payload(response); data_length = le32_to_cpu(data_transfer->data_length); remaining_data_length = From a8a45d4c9597ff5357a44e88ce9910ccb52add06 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 10:10:10 +0200 Subject: [PATCH 062/159] smb: client: pass struct smbdirect_socket to {allocate,destroy}_mr_list() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 8e354d10038a..de0ac75b975b 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -40,8 +40,8 @@ static int smbd_post_recv( static int smbd_post_send_empty(struct smbd_connection *info); -static void destroy_mr_list(struct smbd_connection *info); -static int allocate_mr_list(struct smbd_connection *info); +static void destroy_mr_list(struct smbdirect_socket *sc); +static int allocate_mr_list(struct smbdirect_socket *sc); struct smb_extract_to_rdma { struct ib_sge *sge; @@ -1582,7 +1582,7 @@ void smbd_destroy(struct TCP_Server_Info *server) msleep(1000); cifs_server_lock(server); } - destroy_mr_list(info); + destroy_mr_list(sc); ib_free_cq(sc->ib.send_cq); ib_free_cq(sc->ib.recv_cq); @@ -1907,7 +1907,7 @@ static struct smbd_connection *_smbd_get_connection( goto negotiation_failed; } - rc = allocate_mr_list(info); + rc = allocate_mr_list(sc); if (rc) { log_rdma_mr(ERR, "memory registration allocation failed\n"); goto allocate_mr_failed; @@ -2289,9 +2289,8 @@ static void smbd_mr_recovery_work(struct work_struct *work) } } -static void destroy_mr_list(struct smbd_connection *info) +static void destroy_mr_list(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &info->socket; struct smbdirect_mr_io *mr, *tmp; disable_work_sync(&sc->mr_io.recovery_work); @@ -2312,9 +2311,8 @@ static void destroy_mr_list(struct smbd_connection *info) * Recovery is done in smbd_mr_recovery_work. The content of list entry changes * as MRs are used and recovered for I/O, but the list links will not change */ -static int allocate_mr_list(struct smbd_connection *info) +static int allocate_mr_list(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &info->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; int i; struct smbdirect_mr_io *smbdirect_mr, *tmp; From c7e4d5facb47698411d144ea1c968ef3e1794be9 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 10:12:35 +0200 Subject: [PATCH 063/159] smb: client: pass struct smbdirect_socket to smbd_disconnect_rdma_connection() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 41 +++++++++++++-------------------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index de0ac75b975b..9c2fb138ce1f 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -215,10 +215,8 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) } } -static void smbd_disconnect_rdma_connection(struct smbd_connection *info) +static void smbd_disconnect_rdma_connection(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &info->socket; - queue_work(sc->workqueue, &sc->disconnect_work); } @@ -390,6 +388,7 @@ static void smbd_qp_async_error_upcall(struct ib_event *event, void *context) { struct smbd_connection *info = context; + struct smbdirect_socket *sc = &info->socket; log_rdma_event(ERR, "%s on device %s info %p\n", ib_event_msg(event->event), event->device->name, info); @@ -397,7 +396,7 @@ smbd_qp_async_error_upcall(struct ib_event *event, void *context) switch (event->event) { case IB_EVENT_CQ_ERR: case IB_EVENT_QP_FATAL: - smbd_disconnect_rdma_connection(info); + smbd_disconnect_rdma_connection(sc); break; default: @@ -422,8 +421,6 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc) struct smbdirect_send_io *request = container_of(wc->wr_cqe, struct smbdirect_send_io, cqe); struct smbdirect_socket *sc = request->socket; - struct smbd_connection *info = - container_of(sc, struct smbd_connection, socket); log_rdma_send(INFO, "smbdirect_send_io 0x%p completed wc->status=%s\n", request, ib_wc_status_msg(wc->status)); @@ -439,7 +436,7 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc) log_rdma_send(ERR, "wc->status=%s wc->opcode=%d\n", ib_wc_status_msg(wc->status), wc->opcode); mempool_free(request, sc->send_io.mem.pool); - smbd_disconnect_rdma_connection(info); + smbd_disconnect_rdma_connection(sc); return; } @@ -581,8 +578,6 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) container_of(wc->wr_cqe, struct smbdirect_recv_io, cqe); struct smbdirect_socket *sc = response->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; - struct smbd_connection *info = - container_of(sc, struct smbd_connection, socket); u16 old_recv_credit_target; u32 data_offset = 0; u32 data_length = 0; @@ -724,7 +719,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) WARN_ON_ONCE(sc->recv_io.expected != SMBDIRECT_EXPECT_DATA_TRANSFER); error: put_receive_buffer(sc, response); - smbd_disconnect_rdma_connection(info); + smbd_disconnect_rdma_connection(sc); } static struct rdma_cm_id *smbd_create_id( @@ -949,7 +944,7 @@ static int smbd_post_send_negotiate_req(struct smbd_connection *info) ib_dma_unmap_single(sc->ib.dev, request->sge[0].addr, request->sge[0].length, DMA_TO_DEVICE); - smbd_disconnect_rdma_connection(info); + smbd_disconnect_rdma_connection(sc); dma_mapping_failed: mempool_free(request, sc->send_io.mem.pool); @@ -1041,7 +1036,7 @@ static int smbd_post_send(struct smbd_connection *info, rc = ib_post_send(sc->ib.qp, &send_wr, NULL); if (rc) { log_rdma_send(ERR, "ib_post_send failed rc=%d\n", rc); - smbd_disconnect_rdma_connection(info); + smbd_disconnect_rdma_connection(sc); rc = -EAGAIN; } @@ -1274,7 +1269,7 @@ static int smbd_post_recv( ib_dma_unmap_single(sc->ib.dev, response->sge.addr, response->sge.length, DMA_FROM_DEVICE); response->sge.length = 0; - smbd_disconnect_rdma_connection(info); + smbd_disconnect_rdma_connection(sc); log_rdma_recv(ERR, "ib_post_recv failed rc=%d\n", rc); } @@ -1481,14 +1476,12 @@ static void idle_connection_timer(struct work_struct *work) struct smbdirect_socket *sc = container_of(work, struct smbdirect_socket, idle.timer_work.work); struct smbdirect_socket_parameters *sp = &sc->parameters; - struct smbd_connection *info = - container_of(sc, struct smbd_connection, socket); if (sc->idle.keepalive != SMBDIRECT_KEEPALIVE_NONE) { log_keep_alive(ERR, "error status sc->idle.keepalive=%d\n", sc->idle.keepalive); - smbd_disconnect_rdma_connection(info); + smbd_disconnect_rdma_connection(sc); return; } @@ -2220,12 +2213,10 @@ static void register_mr_done(struct ib_cq *cq, struct ib_wc *wc) struct smbdirect_mr_io *mr = container_of(wc->wr_cqe, struct smbdirect_mr_io, cqe); struct smbdirect_socket *sc = mr->socket; - struct smbd_connection *info = - container_of(sc, struct smbd_connection, socket); if (wc->status) { log_rdma_mr(ERR, "status=%d\n", wc->status); - smbd_disconnect_rdma_connection(info); + smbd_disconnect_rdma_connection(sc); } } @@ -2243,8 +2234,6 @@ static void smbd_mr_recovery_work(struct work_struct *work) struct smbdirect_socket *sc = container_of(work, struct smbdirect_socket, mr_io.recovery_work); struct smbdirect_socket_parameters *sp = &sc->parameters; - struct smbd_connection *info = - container_of(sc, struct smbd_connection, socket); struct smbdirect_mr_io *smbdirect_mr; int rc; @@ -2257,7 +2246,7 @@ static void smbd_mr_recovery_work(struct work_struct *work) log_rdma_mr(ERR, "ib_dereg_mr failed rc=%x\n", rc); - smbd_disconnect_rdma_connection(info); + smbd_disconnect_rdma_connection(sc); continue; } @@ -2268,7 +2257,7 @@ static void smbd_mr_recovery_work(struct work_struct *work) log_rdma_mr(ERR, "ib_alloc_mr failed mr_type=%x max_frmr_depth=%x\n", sc->mr_io.type, sp->max_frmr_depth); - smbd_disconnect_rdma_connection(info); + smbd_disconnect_rdma_connection(sc); continue; } } else @@ -2524,7 +2513,7 @@ struct smbdirect_mr_io *smbd_register_mr(struct smbd_connection *info, if (atomic_dec_and_test(&sc->mr_io.used.count)) wake_up(&sc->mr_io.cleanup.wait_queue); - smbd_disconnect_rdma_connection(info); + smbd_disconnect_rdma_connection(sc); return NULL; } @@ -2554,8 +2543,6 @@ int smbd_deregister_mr(struct smbdirect_mr_io *smbdirect_mr) { struct ib_send_wr *wr; struct smbdirect_socket *sc = smbdirect_mr->socket; - struct smbd_connection *info = - container_of(sc, struct smbd_connection, socket); int rc = 0; if (smbdirect_mr->need_invalidate) { @@ -2572,7 +2559,7 @@ int smbd_deregister_mr(struct smbdirect_mr_io *smbdirect_mr) rc = ib_post_send(sc->ib.qp, wr, NULL); if (rc) { log_rdma_mr(ERR, "ib_post_send failed rc=%x\n", rc); - smbd_disconnect_rdma_connection(info); + smbd_disconnect_rdma_connection(sc); goto done; } wait_for_completion(&smbdirect_mr->invalidate_done); From be8602d47d4116da477cba0e4284295892887b24 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 10:14:29 +0200 Subject: [PATCH 064/159] smb: client: pass struct smbdirect_socket to smbd_post_recv() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 9c2fb138ce1f..809c529b1b3c 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -35,7 +35,7 @@ static struct smbdirect_recv_io *_get_first_reassembly( struct smbdirect_socket *sc); static int smbd_post_recv( - struct smbd_connection *info, + struct smbdirect_socket *sc, struct smbdirect_recv_io *response); static int smbd_post_send_empty(struct smbd_connection *info); @@ -535,8 +535,6 @@ static void smbd_post_send_credits(struct work_struct *work) struct smbdirect_recv_io *response; struct smbdirect_socket *sc = container_of(work, struct smbdirect_socket, recv_io.posted.refill_work); - struct smbd_connection *info = - container_of(sc, struct smbd_connection, socket); if (sc->status != SMBDIRECT_SOCKET_CONNECTED) { return; @@ -550,7 +548,7 @@ static void smbd_post_send_credits(struct work_struct *work) break; response->first_segment = false; - rc = smbd_post_recv(info, response); + rc = smbd_post_recv(sc, response); if (rc) { log_rdma_recv(ERR, "post_recv failed rc=%d\n", rc); @@ -1241,9 +1239,8 @@ static int smbd_post_send_full_iter(struct smbd_connection *info, * The interaction is controlled by send/receive credit system */ static int smbd_post_recv( - struct smbd_connection *info, struct smbdirect_recv_io *response) + struct smbdirect_socket *sc, struct smbdirect_recv_io *response) { - struct smbdirect_socket *sc = &info->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; struct ib_recv_wr recv_wr; int rc = -EIO; @@ -1288,7 +1285,7 @@ static int smbd_negotiate(struct smbd_connection *info) sc->status = SMBDIRECT_SOCKET_NEGOTIATE_RUNNING; sc->recv_io.expected = SMBDIRECT_EXPECT_NEGOTIATE_REP; - rc = smbd_post_recv(info, response); + rc = smbd_post_recv(sc, response); log_rdma_event(INFO, "smbd_post_recv rc=%d iov.addr=0x%llx iov.length=%u iov.lkey=0x%x\n", rc, response->sge.addr, response->sge.length, response->sge.lkey); From 869bb7284fb2976b59ad29455cddd44bce0976f7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 10:18:12 +0200 Subject: [PATCH 065/159] smb: client: pass struct smbdirect_socket to manage_credits_prior_sending() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 809c529b1b3c..adebee32442a 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -957,9 +957,8 @@ static int smbd_post_send_negotiate_req(struct smbd_connection *info) * buffer as possible, and extend the receive credits to remote peer * return value: the new credtis being granted. */ -static int manage_credits_prior_sending(struct smbd_connection *info) +static int manage_credits_prior_sending(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &info->socket; int new_credits; if (atomic_read(&sc->recv_io.credits.count) >= sc->recv_io.credits.target) @@ -1127,7 +1126,7 @@ static int smbd_post_send_iter(struct smbd_connection *info, packet = smbdirect_send_io_payload(request); packet->credits_requested = cpu_to_le16(sp->send_credit_target); - new_credits = manage_credits_prior_sending(info); + new_credits = manage_credits_prior_sending(sc); atomic_add(new_credits, &sc->recv_io.credits.count); packet->credits_granted = cpu_to_le16(new_credits); From 8a9919b2bf8199206e5c5e223e2dd3d04b93a4e2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 10:19:28 +0200 Subject: [PATCH 066/159] smb: client: pass struct smbdirect_socket to smbd_post_send() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index adebee32442a..dc3b2f0aab06 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -1003,10 +1003,9 @@ static int manage_keep_alive_before_sending(struct smbd_connection *info) } /* Post the send request */ -static int smbd_post_send(struct smbd_connection *info, +static int smbd_post_send(struct smbdirect_socket *sc, struct smbdirect_send_io *request) { - struct smbdirect_socket *sc = &info->socket; struct ib_send_wr send_wr; int rc, i; @@ -1169,7 +1168,7 @@ static int smbd_post_send_iter(struct smbd_connection *info, request->sge[0].length = header_length; request->sge[0].lkey = sc->ib.pd->local_dma_lkey; - rc = smbd_post_send(info, request); + rc = smbd_post_send(sc, request); if (!rc) return 0; From 8cead970e37c40727d9b93ce49e7c445c2caf7d0 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 10:21:16 +0200 Subject: [PATCH 067/159] smb: client: pass struct smbdirect_socket to manage_keep_alive_before_sending() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index dc3b2f0aab06..7990c0409193 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -984,9 +984,8 @@ static int manage_credits_prior_sending(struct smbdirect_socket *sc) * 1 if SMBDIRECT_FLAG_RESPONSE_REQUESTED needs to be set * 0: otherwise */ -static int manage_keep_alive_before_sending(struct smbd_connection *info) +static int manage_keep_alive_before_sending(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &info->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; if (sc->idle.keepalive == SMBDIRECT_KEEPALIVE_PENDING) { @@ -1130,7 +1129,7 @@ static int smbd_post_send_iter(struct smbd_connection *info, packet->credits_granted = cpu_to_le16(new_credits); packet->flags = 0; - if (manage_keep_alive_before_sending(info)) + if (manage_keep_alive_before_sending(sc)) packet->flags |= cpu_to_le16(SMBDIRECT_FLAG_RESPONSE_REQUESTED); packet->reserved = 0; From 46b8fe2bd18c487aa4fd5c45e6f9c23a1c4c859a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 10:27:01 +0200 Subject: [PATCH 068/159] smb: client: pass struct smbdirect_socket to smbd_post_send_iter() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 7990c0409193..211cf391edb5 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -1038,11 +1038,10 @@ static int smbd_post_send(struct smbdirect_socket *sc, return rc; } -static int smbd_post_send_iter(struct smbd_connection *info, +static int smbd_post_send_iter(struct smbdirect_socket *sc, struct iov_iter *iter, int *_remaining_data_length) { - struct smbdirect_socket *sc = &info->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; int i, rc; int header_length; @@ -1206,13 +1205,14 @@ static int smbd_post_send_empty(struct smbd_connection *info) int remaining_data_length = 0; sc->statistics.send_empty++; - return smbd_post_send_iter(info, NULL, &remaining_data_length); + return smbd_post_send_iter(sc, NULL, &remaining_data_length); } static int smbd_post_send_full_iter(struct smbd_connection *info, struct iov_iter *iter, int *_remaining_data_length) { + struct smbdirect_socket *sc = &info->socket; int rc = 0; /* @@ -1222,7 +1222,7 @@ static int smbd_post_send_full_iter(struct smbd_connection *info, */ while (iov_iter_count(iter) > 0) { - rc = smbd_post_send_iter(info, iter, _remaining_data_length); + rc = smbd_post_send_iter(sc, iter, _remaining_data_length); if (rc < 0) break; } From d76e8c7f546b2d2a49149b4ee59583aad0282c93 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 10:47:06 +0200 Subject: [PATCH 069/159] smb: client: pass struct smbdirect_socket to smbd_post_send_empty() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 211cf391edb5..5784e82f7911 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -38,7 +38,7 @@ static int smbd_post_recv( struct smbdirect_socket *sc, struct smbdirect_recv_io *response); -static int smbd_post_send_empty(struct smbd_connection *info); +static int smbd_post_send_empty(struct smbdirect_socket *sc); static void destroy_mr_list(struct smbdirect_socket *sc); static int allocate_mr_list(struct smbdirect_socket *sc); @@ -1199,9 +1199,8 @@ static int smbd_post_send_iter(struct smbdirect_socket *sc, * Empty message is used to extend credits to peer to for keep live * while there is no upper layer payload to send at the time */ -static int smbd_post_send_empty(struct smbd_connection *info) +static int smbd_post_send_empty(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &info->socket; int remaining_data_length = 0; sc->statistics.send_empty++; @@ -1454,14 +1453,12 @@ static void send_immediate_empty_message(struct work_struct *work) { struct smbdirect_socket *sc = container_of(work, struct smbdirect_socket, idle.immediate_work); - struct smbd_connection *info = - container_of(sc, struct smbd_connection, socket); if (sc->status != SMBDIRECT_SOCKET_CONNECTED) return; log_keep_alive(INFO, "send an empty message\n"); - smbd_post_send_empty(info); + smbd_post_send_empty(sc); } /* Implement idle connection timer [MS-SMBD] 3.1.6.2 */ From 05bd1378c821f4cea2818b0bef6b28415ffca56f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 11:03:52 +0200 Subject: [PATCH 070/159] smb: client: pass struct smbdirect_socket to smbd_post_send_full_iter() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 5784e82f7911..951e70403aa5 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -1207,11 +1207,10 @@ static int smbd_post_send_empty(struct smbdirect_socket *sc) return smbd_post_send_iter(sc, NULL, &remaining_data_length); } -static int smbd_post_send_full_iter(struct smbd_connection *info, +static int smbd_post_send_full_iter(struct smbdirect_socket *sc, struct iov_iter *iter, int *_remaining_data_length) { - struct smbdirect_socket *sc = &info->socket; int rc = 0; /* @@ -2168,13 +2167,13 @@ int smbd_send(struct TCP_Server_Info *server, 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); + rc = smbd_post_send_full_iter(sc, &iter, &remaining_data_length); 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, + rc = smbd_post_send_full_iter(sc, &rqst->rq_iter, &remaining_data_length); if (rc < 0) break; From e3f095cca6563e6aaf9163690e22800f765cd193 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 11:07:48 +0200 Subject: [PATCH 071/159] smb: client: pass struct smbdirect_socket to smbd_conn_upcall() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 951e70403aa5..90bfb9986848 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -224,8 +224,7 @@ static void smbd_disconnect_rdma_connection(struct smbdirect_socket *sc) static int smbd_conn_upcall( struct rdma_cm_id *id, struct rdma_cm_event *event) { - struct smbd_connection *info = id->context; - struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket *sc = id->context; struct smbdirect_socket_parameters *sp = &sc->parameters; const char *event_name = rdma_event_msg(event->event); u8 peer_initiator_depth; @@ -730,7 +729,7 @@ static struct rdma_cm_id *smbd_create_id( int rc; __be16 *sport; - id = rdma_create_id(&init_net, smbd_conn_upcall, info, + id = rdma_create_id(&init_net, smbd_conn_upcall, sc, RDMA_PS_TCP, IB_QPT_RC); if (IS_ERR(id)) { rc = PTR_ERR(id); From 94a0e794b77f3300c99fcac65d1a4fc83fd4684f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 11:08:13 +0200 Subject: [PATCH 072/159] smb: client: pass struct smbdirect_socket to smbd_qp_async_error_upcall() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 90bfb9986848..dd1722443365 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -386,11 +386,10 @@ static int smbd_conn_upcall( static void smbd_qp_async_error_upcall(struct ib_event *event, void *context) { - struct smbd_connection *info = context; - struct smbdirect_socket *sc = &info->socket; + struct smbdirect_socket *sc = context; - log_rdma_event(ERR, "%s on device %s info %p\n", - ib_event_msg(event->event), event->device->name, info); + log_rdma_event(ERR, "%s on device %s socket %p\n", + ib_event_msg(event->event), event->device->name, sc); switch (event->event) { case IB_EVENT_CQ_ERR: @@ -1779,7 +1778,7 @@ static struct smbd_connection *_smbd_get_connection( } sc->ib.send_cq = - ib_alloc_cq_any(sc->ib.dev, info, + ib_alloc_cq_any(sc->ib.dev, sc, sp->send_credit_target, IB_POLL_SOFTIRQ); if (IS_ERR(sc->ib.send_cq)) { sc->ib.send_cq = NULL; @@ -1787,7 +1786,7 @@ static struct smbd_connection *_smbd_get_connection( } sc->ib.recv_cq = - ib_alloc_cq_any(sc->ib.dev, info, + ib_alloc_cq_any(sc->ib.dev, sc, sp->recv_credit_max, IB_POLL_SOFTIRQ); if (IS_ERR(sc->ib.recv_cq)) { sc->ib.recv_cq = NULL; @@ -1796,7 +1795,7 @@ static struct smbd_connection *_smbd_get_connection( memset(&qp_attr, 0, sizeof(qp_attr)); qp_attr.event_handler = smbd_qp_async_error_upcall; - qp_attr.qp_context = info; + qp_attr.qp_context = sc; qp_attr.cap.max_send_wr = sp->send_credit_target; qp_attr.cap.max_recv_wr = sp->recv_credit_max; qp_attr.cap.max_send_sge = SMBDIRECT_SEND_IO_MAX_SGE; From 2569536b0c69eb3c38deacf2b9ce82cd5f8b4633 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 11:10:57 +0200 Subject: [PATCH 073/159] smb: client: pass struct smbdirect_socket to smbd_create_id() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index dd1722443365..414127b3bf65 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -719,10 +719,9 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) } static struct rdma_cm_id *smbd_create_id( - struct smbd_connection *info, + struct smbdirect_socket *sc, struct sockaddr *dstaddr, int port) { - struct smbdirect_socket *sc = &info->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; struct rdma_cm_id *id; int rc; @@ -830,7 +829,7 @@ static int smbd_ia_open( WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_CREATED); sc->status = SMBDIRECT_SOCKET_RESOLVE_ADDR_NEEDED; - sc->rdma.cm_id = smbd_create_id(info, dstaddr, port); + sc->rdma.cm_id = smbd_create_id(sc, dstaddr, port); if (IS_ERR(sc->rdma.cm_id)) { rc = PTR_ERR(sc->rdma.cm_id); goto out1; From 0a5dc5fc7c014d88c31aff327a65d610d8006454 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 11:34:05 +0200 Subject: [PATCH 074/159] smb: client: pass struct smbdirect_socket to smbd_ia_open() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 414127b3bf65..b9eb3ab52ac3 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -819,10 +819,9 @@ static bool frwr_is_supported(struct ib_device_attr *attrs) } static int smbd_ia_open( - struct smbd_connection *info, + struct smbdirect_socket *sc, struct sockaddr *dstaddr, int port) { - struct smbdirect_socket *sc = &info->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; int rc; @@ -1741,7 +1740,7 @@ static struct smbd_connection *_smbd_get_connection( sp->keepalive_interval_msec = smbd_keep_alive_interval * 1000; sp->keepalive_timeout_msec = KEEPALIVE_RECV_TIMEOUT * 1000; - rc = smbd_ia_open(info, dstaddr, port); + rc = smbd_ia_open(sc, dstaddr, port); if (rc) { log_rdma_event(INFO, "smbd_ia_open rc=%d\n", rc); goto create_id_failed; From c612e60de5aa0b1cb60ac6c9e7d96eb3c4528b13 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 11:52:24 +0200 Subject: [PATCH 075/159] smb: client: pass struct smbdirect_socket to smbd_post_send_negotiate_req() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index b9eb3ab52ac3..b4f257b55d99 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -873,9 +873,8 @@ static int smbd_ia_open( * After negotiation, the transport is connected and ready for * carrying upper layer SMB payload */ -static int smbd_post_send_negotiate_req(struct smbd_connection *info) +static int smbd_post_send_negotiate_req(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &info->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; struct ib_send_wr send_wr; int rc = -ENOMEM; @@ -1285,7 +1284,7 @@ static int smbd_negotiate(struct smbd_connection *info) return rc; } - rc = smbd_post_send_negotiate_req(info); + rc = smbd_post_send_negotiate_req(sc); if (rc) return rc; From 2c6b999a90987a86285865569eac8a5a51ce18a1 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 11:54:30 +0200 Subject: [PATCH 076/159] smb: client: pass struct smbdirect_socket to smbd_negotiate() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index b4f257b55d99..2304a5c6f426 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -1264,9 +1264,8 @@ static int smbd_post_recv( } /* Perform SMBD negotiate according to [MS-SMBD] 3.1.5.2 */ -static int smbd_negotiate(struct smbd_connection *info) +static int smbd_negotiate(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &info->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; int rc; struct smbdirect_recv_io *response = get_receive_buffer(sc); @@ -1879,7 +1878,7 @@ static struct smbd_connection *_smbd_get_connection( INIT_WORK(&sc->recv_io.posted.refill_work, smbd_post_send_credits); - rc = smbd_negotiate(info); + rc = smbd_negotiate(sc); if (rc) { log_rdma_event(ERR, "smbd_negotiate rc=%d\n", rc); goto negotiation_failed; From 4c4b1d1122fb49a207b86318b0940e09898d8e62 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 01:14:38 +0200 Subject: [PATCH 077/159] smb: client: pass struct smbdirect_socket to get_mr() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 2304a5c6f426..e453b998a859 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -2345,9 +2345,8 @@ static int allocate_mr_list(struct smbdirect_socket *sc) * issuing I/O trying to get MR at the same time, mr_list_lock is used to * protect this situation. */ -static struct smbdirect_mr_io *get_mr(struct smbd_connection *info) +static struct smbdirect_mr_io *get_mr(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &info->socket; struct smbdirect_mr_io *ret; int rc; again: @@ -2428,7 +2427,7 @@ struct smbdirect_mr_io *smbd_register_mr(struct smbd_connection *info, return NULL; } - smbdirect_mr = get_mr(info); + smbdirect_mr = get_mr(sc); if (!smbdirect_mr) { log_rdma_mr(ERR, "get_mr returning NULL\n"); return NULL; From 114347dad6e7955b25aa707d62936023e501d8ed Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 01:14:38 +0200 Subject: [PATCH 078/159] smb: client: remove unused struct smbdirect_socket argument of smbd_iter_to_mr() This will make it easier to move function to the common code in future. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index e453b998a859..dba3f461b5cf 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -2385,8 +2385,7 @@ static struct smbdirect_mr_io *get_mr(struct smbdirect_socket *sc) /* * Transcribe the pages from an iterator into an MR scatterlist. */ -static int smbd_iter_to_mr(struct smbd_connection *info, - struct iov_iter *iter, +static int smbd_iter_to_mr(struct iov_iter *iter, struct sg_table *sgt, unsigned int max_sg) { @@ -2441,7 +2440,7 @@ struct smbdirect_mr_io *smbd_register_mr(struct smbd_connection *info, log_rdma_mr(INFO, "num_pages=0x%x count=0x%zx depth=%u\n", num_pages, iov_iter_count(iter), sp->max_frmr_depth); - smbd_iter_to_mr(info, iter, &smbdirect_mr->sgt, sp->max_frmr_depth); + smbd_iter_to_mr(iter, &smbdirect_mr->sgt, sp->max_frmr_depth); rc = ib_dma_map_sg(sc->ib.dev, smbdirect_mr->sgt.sgl, smbdirect_mr->sgt.nents, dir); From ffbfc73e84eb829f7e2f901594271557de860827 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 28 Aug 2025 10:39:56 +0200 Subject: [PATCH 079/159] smb: client: let smbd_disconnect_rdma_connection() set SMBDIRECT_SOCKET_ERROR... smbd_disconnect_rdma_connection() should turn the status into an error state instead of leaving it as is until smbd_disconnect_rdma_work() is running. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 40 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index dba3f461b5cf..45f137487ba1 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -217,6 +217,46 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) static void smbd_disconnect_rdma_connection(struct smbdirect_socket *sc) { + switch (sc->status) { + case SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED: + case SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED: + case SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED: + case SMBDIRECT_SOCKET_NEGOTIATE_FAILED: + case SMBDIRECT_SOCKET_ERROR: + case SMBDIRECT_SOCKET_DISCONNECTING: + case SMBDIRECT_SOCKET_DISCONNECTED: + case SMBDIRECT_SOCKET_DESTROYED: + /* + * Keep the current error status + */ + break; + + case SMBDIRECT_SOCKET_RESOLVE_ADDR_NEEDED: + case SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING: + sc->status = SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED; + break; + + case SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED: + case SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING: + sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED; + break; + + case SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED: + case SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING: + sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED; + break; + + case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: + case SMBDIRECT_SOCKET_NEGOTIATE_RUNNING: + sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED; + break; + + case SMBDIRECT_SOCKET_CREATED: + case SMBDIRECT_SOCKET_CONNECTED: + sc->status = SMBDIRECT_SOCKET_ERROR; + break; + } + queue_work(sc->workqueue, &sc->disconnect_work); } From 98a1cdca35eac55407c76067cdffd19aade0026c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 28 Aug 2025 12:12:09 +0200 Subject: [PATCH 080/159] smb: client: fill in smbdirect_socket.first_error on error For now we just use -ECONNABORTED, but it will get more detailed later. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 45f137487ba1..86d32bd5f113 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -181,6 +181,9 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) disable_work(&sc->idle.immediate_work); disable_delayed_work(&sc->idle.timer_work); + if (sc->first_error == 0) + sc->first_error = -ECONNABORTED; + switch (sc->status) { case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: case SMBDIRECT_SOCKET_NEGOTIATE_RUNNING: @@ -217,6 +220,9 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) static void smbd_disconnect_rdma_connection(struct smbdirect_socket *sc) { + if (sc->first_error == 0) + sc->first_error = -ECONNABORTED; + switch (sc->status) { case SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED: case SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED: From 0cb7ed37af614bbda39dab3d13f0639458d77cae Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 28 Aug 2025 12:15:11 +0200 Subject: [PATCH 081/159] smb: client: let smbd_disconnect_rdma_connection() disable all work but disconnect_work There's no point run these if we already know the connection is broken. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 86d32bd5f113..155d69745adf 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -220,6 +220,16 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) static void smbd_disconnect_rdma_connection(struct smbdirect_socket *sc) { + /* + * make sure other work (than disconnect_work) is + * not queued again but here we don't block and avoid + * disable[_delayed]_work_sync() + */ + disable_work(&sc->recv_io.posted.refill_work); + disable_work(&sc->mr_io.recovery_work); + disable_work(&sc->idle.immediate_work); + disable_delayed_work(&sc->idle.timer_work); + if (sc->first_error == 0) sc->first_error = -ECONNABORTED; From 1b128ec1c76dcf08b752b5f5268da813fea58a01 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 2 Sep 2025 12:17:56 +0200 Subject: [PATCH 082/159] smb: client: let smbd_{destroy,disconnect_rdma_{work,connection}}() wake up all wait queues This is important in order to let all waiters notice a broken connection. We also go via smbd_disconnect_rdma_{work,connection}() for broken connections. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 52 ++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 155d69745adf..6d9c9e68c765 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -165,6 +165,21 @@ do { \ #define log_rdma_mr(level, fmt, args...) \ log_rdma(level, LOG_RDMA_MR, fmt, ##args) +static void smbd_disconnect_wake_up_all(struct smbdirect_socket *sc) +{ + /* + * Wake up all waiters in all wait queues + * in order to notice the broken connection. + */ + wake_up_all(&sc->status_wait); + wake_up_all(&sc->send_io.credits.wait_queue); + wake_up_all(&sc->send_io.pending.dec_wait_queue); + wake_up_all(&sc->send_io.pending.zero_wait_queue); + wake_up_all(&sc->recv_io.reassembly.wait_queue); + wake_up_all(&sc->mr_io.ready.wait_queue); + wake_up_all(&sc->mr_io.cleanup.wait_queue); +} + static void smbd_disconnect_rdma_work(struct work_struct *work) { struct smbdirect_socket *sc = @@ -216,6 +231,12 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) case SMBDIRECT_SOCKET_DESTROYED: break; } + + /* + * Wake up all waiters in all wait queues + * in order to notice the broken connection. + */ + smbd_disconnect_wake_up_all(sc); } static void smbd_disconnect_rdma_connection(struct smbdirect_socket *sc) @@ -273,6 +294,12 @@ static void smbd_disconnect_rdma_connection(struct smbdirect_socket *sc) break; } + /* + * Wake up all waiters in all wait queues + * in order to notice the broken connection. + */ + smbd_disconnect_wake_up_all(sc); + queue_work(sc->workqueue, &sc->disconnect_work); } @@ -306,14 +333,14 @@ static int smbd_conn_upcall( log_rdma_event(ERR, "connecting failed event=%s\n", event_name); WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING); sc->status = SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED; - wake_up_all(&sc->status_wait); + smbd_disconnect_rdma_work(&sc->disconnect_work); break; case RDMA_CM_EVENT_ROUTE_ERROR: log_rdma_event(ERR, "connecting failed event=%s\n", event_name); WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING); sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED; - wake_up_all(&sc->status_wait); + smbd_disconnect_rdma_work(&sc->disconnect_work); break; case RDMA_CM_EVENT_ESTABLISHED: @@ -408,7 +435,7 @@ static int smbd_conn_upcall( log_rdma_event(ERR, "connecting failed event=%s\n", event_name); WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING); sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED; - wake_up_all(&sc->status_wait); + smbd_disconnect_rdma_work(&sc->disconnect_work); break; case RDMA_CM_EVENT_DEVICE_REMOVAL: @@ -416,17 +443,10 @@ static int smbd_conn_upcall( /* This happens when we fail the negotiation */ if (sc->status == SMBDIRECT_SOCKET_NEGOTIATE_FAILED) { log_rdma_event(ERR, "event=%s during negotiation\n", event_name); - sc->status = SMBDIRECT_SOCKET_DISCONNECTED; - smbd_disconnect_rdma_work(&sc->disconnect_work); - wake_up_all(&sc->status_wait); - break; } sc->status = SMBDIRECT_SOCKET_DISCONNECTED; smbd_disconnect_rdma_work(&sc->disconnect_work); - wake_up_all(&sc->status_wait); - wake_up_all(&sc->recv_io.reassembly.wait_queue); - wake_up_all(&sc->send_io.credits.wait_queue); break; default: @@ -674,7 +694,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_NEGOTIATE_RUNNING); if (!negotiate_done) { sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED; - wake_up_all(&sc->status_wait); + smbd_disconnect_rdma_connection(sc); } else { sc->status = SMBDIRECT_SOCKET_CONNECTED; wake_up(&sc->status_wait); @@ -1569,6 +1589,15 @@ void smbd_destroy(struct TCP_Server_Info *server) sc->status == SMBDIRECT_SOCKET_DISCONNECTED); } + /* + * Wake up all waiters in all wait queues + * in order to notice the broken connection. + * + * Most likely this was already called via + * smbd_disconnect_rdma_work(), but call it again... + */ + smbd_disconnect_wake_up_all(sc); + log_rdma_event(INFO, "cancelling recv_io.posted.refill_work\n"); disable_work_sync(&sc->recv_io.posted.refill_work); @@ -1609,7 +1638,6 @@ void smbd_destroy(struct TCP_Server_Info *server) * path when sending data, and then release memory registrations. */ log_rdma_event(INFO, "freeing mr list\n"); - wake_up_all(&sc->mr_io.ready.wait_queue); while (atomic_read(&sc->mr_io.used.count)) { cifs_server_unlock(server); msleep(1000); From a437c9cebcc3c4193fe0143e6fbc72c6b7529ad2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 27 Aug 2025 15:34:09 +0200 Subject: [PATCH 083/159] smb: client: make consitent use of spin_lock_irq{save,restore}() in smbdirect.c There is a mix of using spin_lock(), spin_lock_irq() and spin_lock_irqsave() and it seems at least enqueue_reassembly() was wrong in using just spin_lock() as it's called via recv_done() from a SOFTIRQ as we're using IB_POLL_SOFTIRQ. And Documentation/kernel-hacking/locking.rst section "Cheat Sheet For Locking" says: - Otherwise (== data can be touched in an interrupt), use spin_lock_irqsave() and spin_unlock_irqrestore(). So in order to keep it simple and safe we use that version now. It will help merging functions into common code and have consistent locking in all cases. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 6d9c9e68c765..8e10a43c8cb1 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -1397,7 +1397,9 @@ static void enqueue_reassembly( struct smbdirect_recv_io *response, int data_length) { - spin_lock(&sc->recv_io.reassembly.lock); + unsigned long flags; + + spin_lock_irqsave(&sc->recv_io.reassembly.lock, flags); list_add_tail(&response->list, &sc->recv_io.reassembly.list); sc->recv_io.reassembly.queue_length++; /* @@ -1408,7 +1410,7 @@ static void enqueue_reassembly( */ virt_wmb(); sc->recv_io.reassembly.data_length += data_length; - spin_unlock(&sc->recv_io.reassembly.lock); + spin_unlock_irqrestore(&sc->recv_io.reassembly.lock, flags); sc->statistics.enqueue_reassembly_queue++; } @@ -2076,6 +2078,7 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg) if (sc->recv_io.reassembly.data_length >= size) { int queue_length; int queue_removed = 0; + unsigned long flags; /* * Need to make sure reassembly_data_length is read before @@ -2135,11 +2138,11 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg) if (queue_length) list_del(&response->list); else { - spin_lock_irq( - &sc->recv_io.reassembly.lock); + spin_lock_irqsave( + &sc->recv_io.reassembly.lock, flags); list_del(&response->list); - spin_unlock_irq( - &sc->recv_io.reassembly.lock); + spin_unlock_irqrestore( + &sc->recv_io.reassembly.lock, flags); } queue_removed++; sc->statistics.dequeue_reassembly_queue++; @@ -2157,10 +2160,10 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg) to_read, data_read, offset); } - spin_lock_irq(&sc->recv_io.reassembly.lock); + spin_lock_irqsave(&sc->recv_io.reassembly.lock, flags); sc->recv_io.reassembly.data_length -= data_read; sc->recv_io.reassembly.queue_length -= queue_removed; - spin_unlock_irq(&sc->recv_io.reassembly.lock); + spin_unlock_irqrestore(&sc->recv_io.reassembly.lock, flags); sc->recv_io.reassembly.first_entry_offset = offset; log_read(INFO, "returning to thread data_read=%d reassembly_data_length=%d first_entry_offset=%d\n", @@ -2432,6 +2435,7 @@ static int allocate_mr_list(struct smbdirect_socket *sc) static struct smbdirect_mr_io *get_mr(struct smbdirect_socket *sc) { struct smbdirect_mr_io *ret; + unsigned long flags; int rc; again: rc = wait_event_interruptible(sc->mr_io.ready.wait_queue, @@ -2447,18 +2451,18 @@ static struct smbdirect_mr_io *get_mr(struct smbdirect_socket *sc) return NULL; } - spin_lock(&sc->mr_io.all.lock); + spin_lock_irqsave(&sc->mr_io.all.lock, flags); list_for_each_entry(ret, &sc->mr_io.all.list, list) { if (ret->state == SMBDIRECT_MR_READY) { ret->state = SMBDIRECT_MR_REGISTERED; - spin_unlock(&sc->mr_io.all.lock); + spin_unlock_irqrestore(&sc->mr_io.all.lock, flags); atomic_dec(&sc->mr_io.ready.count); atomic_inc(&sc->mr_io.used.count); return ret; } } - spin_unlock(&sc->mr_io.all.lock); + spin_unlock_irqrestore(&sc->mr_io.all.lock, flags); /* * It is possible that we could fail to get MR because other processes may * try to acquire a MR at the same time. If this is the case, retry it. From 17a6bc60f47b344b831da8cf66adef5c2ea3d9c1 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 26 Aug 2025 15:54:10 +0200 Subject: [PATCH 084/159] smb: client: allocate smbdirect workqueue at the beginning of _smbd_get_connection() This will simplify further changes when moving to common code. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 8e10a43c8cb1..788b378fa1f4 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -1703,10 +1703,9 @@ int smbd_reconnect(struct TCP_Server_Info *server) return -ENOENT; } -static void destroy_caches_and_workqueue(struct smbdirect_socket *sc) +static void destroy_caches(struct smbdirect_socket *sc) { destroy_receive_buffers(sc); - destroy_workqueue(sc->workqueue); mempool_destroy(sc->recv_io.mem.pool); kmem_cache_destroy(sc->recv_io.mem.cache); mempool_destroy(sc->send_io.mem.pool); @@ -1714,7 +1713,7 @@ static void destroy_caches_and_workqueue(struct smbdirect_socket *sc) } #define MAX_NAME_LEN 80 -static int allocate_caches_and_workqueue(struct smbdirect_socket *sc) +static int allocate_caches(struct smbdirect_socket *sc) { struct smbdirect_socket_parameters *sp = &sc->parameters; char name[MAX_NAME_LEN]; @@ -1760,21 +1759,14 @@ static int allocate_caches_and_workqueue(struct smbdirect_socket *sc) if (!sc->recv_io.mem.pool) goto out3; - scnprintf(name, MAX_NAME_LEN, "smbd_%p", sc); - sc->workqueue = create_workqueue(name); - if (!sc->workqueue) - goto out4; - rc = allocate_receive_buffers(sc, sp->recv_credit_max); if (rc) { log_rdma_event(ERR, "failed to allocate receive buffers\n"); - goto out5; + goto out4; } return 0; -out5: - destroy_workqueue(sc->workqueue); out4: mempool_destroy(sc->recv_io.mem.pool); out3: @@ -1799,12 +1791,19 @@ static struct smbd_connection *_smbd_get_connection( struct sockaddr_in *addr_in = (struct sockaddr_in *) dstaddr; struct ib_port_immutable port_immutable; __be32 ird_ord_hdr[2]; + char wq_name[80]; + struct workqueue_struct *workqueue; info = kzalloc(sizeof(struct smbd_connection), GFP_KERNEL); if (!info) return NULL; sc = &info->socket; + scnprintf(wq_name, ARRAY_SIZE(wq_name), "smbd_%p", sc); + workqueue = create_workqueue(wq_name); + if (!workqueue) + goto create_wq_failed; smbdirect_socket_init(sc); + sc->workqueue = workqueue; sp = &sc->parameters; INIT_WORK(&sc->disconnect_work, smbd_disconnect_rdma_work); @@ -1946,7 +1945,7 @@ static struct smbd_connection *_smbd_get_connection( log_rdma_event(INFO, "rdma_connect connected\n"); - rc = allocate_caches_and_workqueue(sc); + rc = allocate_caches(sc); if (rc) { log_rdma_event(ERR, "cache allocation failed\n"); goto allocate_cache_failed; @@ -1986,7 +1985,7 @@ static struct smbd_connection *_smbd_get_connection( negotiation_failed: disable_delayed_work_sync(&sc->idle.timer_work); - destroy_caches_and_workqueue(sc); + destroy_caches(sc); sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED; rdma_disconnect(sc->rdma.cm_id); wait_event(sc->status_wait, @@ -2008,6 +2007,8 @@ static struct smbd_connection *_smbd_get_connection( rdma_destroy_id(sc->rdma.cm_id); create_id_failed: + destroy_workqueue(sc->workqueue); +create_wq_failed: kfree(info); return NULL; } From c4709e61ef253eed4257328b614e7c57fed259ec Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 15 Sep 2025 23:32:15 +0200 Subject: [PATCH 085/159] smb: client: defer calling ib_alloc_pd() after we are connected The protection domain is not needed until we're connected. This makes further changes easier to follow... Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 788b378fa1f4..1d81ead875d0 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -926,13 +926,6 @@ static int smbd_ia_open( if (sc->ib.dev->attrs.kernel_cap_flags & IBK_SG_GAPS_REG) sc->mr_io.type = IB_MR_TYPE_SG_GAPS; - sc->ib.pd = ib_alloc_pd(sc->ib.dev, 0); - if (IS_ERR(sc->ib.pd)) { - rc = PTR_ERR(sc->ib.pd); - log_rdma_event(ERR, "ib_alloc_pd() returned %d\n", rc); - goto out2; - } - return 0; out2: @@ -1858,6 +1851,14 @@ static struct smbd_connection *_smbd_get_connection( goto config_failed; } + sc->ib.pd = ib_alloc_pd(sc->ib.dev, 0); + if (IS_ERR(sc->ib.pd)) { + rc = PTR_ERR(sc->ib.pd); + sc->ib.pd = NULL; + log_rdma_event(ERR, "ib_alloc_pd() returned %d\n", rc); + goto alloc_pd_failed; + } + sc->ib.send_cq = ib_alloc_cq_any(sc->ib.dev, sc, sp->send_credit_target, IB_POLL_SOFTIRQ); @@ -2002,8 +2003,10 @@ static struct smbd_connection *_smbd_get_connection( if (sc->ib.recv_cq) ib_free_cq(sc->ib.recv_cq); -config_failed: ib_dealloc_pd(sc->ib.pd); + +alloc_pd_failed: +config_failed: rdma_destroy_id(sc->rdma.cm_id); create_id_failed: From 2dad0b15bbe86ffa6d2f234c40609aa59894e9ec Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 15 Sep 2025 00:55:31 +0200 Subject: [PATCH 086/159] smb: client: let smbd_post_send_iter() call ib_dma_map_single() for the header first This will simplify further changes, the important part is that request->num_sge >= 1 is only set if request->sge[0].* is valid. Note that ib_dma_sync_single_for_device() is called in smbd_post_send() for each sge, so the device will still see the packet header even if it's modified after calling ib_dma_map_single(). Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 43 +++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 1d81ead875d0..316f398c70f4 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -1158,10 +1158,30 @@ static int smbd_post_send_iter(struct smbdirect_socket *sc, request->socket = sc; memset(request->sge, 0, sizeof(request->sge)); + /* Map the packet to DMA */ + header_length = sizeof(struct smbdirect_data_transfer); + /* If this is a packet without payload, don't send padding */ + if (!iter) + header_length = offsetof(struct smbdirect_data_transfer, padding); + + packet = smbdirect_send_io_payload(request); + request->sge[0].addr = ib_dma_map_single(sc->ib.dev, + (void *)packet, + header_length, + DMA_TO_DEVICE); + if (ib_dma_mapping_error(sc->ib.dev, request->sge[0].addr)) { + rc = -EIO; + goto err_dma; + } + + request->sge[0].length = header_length; + request->sge[0].lkey = sc->ib.pd->local_dma_lkey; + request->num_sge = 1; + /* Fill in the data payload to find out how much data we can add */ if (iter) { struct smb_extract_to_rdma extract = { - .nr_sge = 1, + .nr_sge = request->num_sge, .max_sge = SMBDIRECT_SEND_IO_MAX_SGE, .sge = request->sge, .device = sc->ib.dev, @@ -1180,11 +1200,9 @@ static int smbd_post_send_iter(struct smbdirect_socket *sc, *_remaining_data_length -= data_length; } else { data_length = 0; - request->num_sge = 1; } /* Fill in the packet header */ - packet = smbdirect_send_io_payload(request); packet->credits_requested = cpu_to_le16(sp->send_credit_target); new_credits = manage_credits_prior_sending(sc); @@ -1211,25 +1229,6 @@ static int smbd_post_send_iter(struct smbdirect_socket *sc, le32_to_cpu(packet->data_length), le32_to_cpu(packet->remaining_data_length)); - /* Map the packet to DMA */ - header_length = sizeof(struct smbdirect_data_transfer); - /* If this is a packet without payload, don't send padding */ - if (!data_length) - header_length = offsetof(struct smbdirect_data_transfer, padding); - - request->sge[0].addr = ib_dma_map_single(sc->ib.dev, - (void *)packet, - header_length, - DMA_TO_DEVICE); - if (ib_dma_mapping_error(sc->ib.dev, request->sge[0].addr)) { - rc = -EIO; - request->sge[0].addr = 0; - goto err_dma; - } - - request->sge[0].length = header_length; - request->sge[0].lkey = sc->ib.pd->local_dma_lkey; - rc = smbd_post_send(sc, request); if (!rc) return 0; From fad988a2158d743da7971884b93482a73735b25e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 20 Aug 2025 15:34:58 +0200 Subject: [PATCH 087/159] smb: server: fix IRD/ORD negotiation with the client Already do real negotiation in smb_direct_handle_connect_request() where we see the requested initiator_depth and responder_resources from the client. We should detect legacy iwarp clients using MPA v1 with the custom IRD/ORD negotiation. We need to send the custom IRD/ORD in big endian, but we need to try to let clients with broken requests using little endian (older cifs.ko) to work. Note the reason why this uses u8 for initiator_depth and responder_resources is that the rdma layer also uses it. Acked-by: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Cc: linux-rdma@vger.kernel.org Fixes: 0626e6641f6b ("cifsd: add server handler for central processing and tranport layers") Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 97 +++++++++++++++++++++++++++++----- 1 file changed, 84 insertions(+), 13 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 74dfb6496095..e1f659d3b4cf 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -153,6 +153,10 @@ struct smb_direct_transport { struct work_struct disconnect_work; bool negotiation_requested; + + bool legacy_iwarp; + u8 initiator_depth; + u8 responder_resources; }; #define KSMBD_TRANS(t) ((struct ksmbd_transport *)&((t)->transport)) @@ -347,6 +351,9 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) t->cm_id = cm_id; cm_id->context = t; + t->initiator_depth = SMB_DIRECT_CM_INITIATOR_DEPTH; + t->responder_resources = 1; + t->status = SMB_DIRECT_CS_NEW; init_waitqueue_head(&t->wait_status); @@ -1676,21 +1683,21 @@ static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, static int smb_direct_accept_client(struct smb_direct_transport *t) { struct rdma_conn_param conn_param; - struct ib_port_immutable port_immutable; - u32 ird_ord_hdr[2]; + __be32 ird_ord_hdr[2]; int ret; + /* + * smb_direct_handle_connect_request() + * already negotiated t->initiator_depth + * and t->responder_resources + */ memset(&conn_param, 0, sizeof(conn_param)); - conn_param.initiator_depth = min_t(u8, t->cm_id->device->attrs.max_qp_rd_atom, - SMB_DIRECT_CM_INITIATOR_DEPTH); - conn_param.responder_resources = 0; + conn_param.initiator_depth = t->initiator_depth; + conn_param.responder_resources = t->responder_resources; - t->cm_id->device->ops.get_port_immutable(t->cm_id->device, - t->cm_id->port_num, - &port_immutable); - if (port_immutable.core_cap_flags & RDMA_CORE_PORT_IWARP) { - ird_ord_hdr[0] = conn_param.responder_resources; - ird_ord_hdr[1] = 1; + if (t->legacy_iwarp) { + ird_ord_hdr[0] = cpu_to_be32(conn_param.responder_resources); + ird_ord_hdr[1] = cpu_to_be32(conn_param.initiator_depth); conn_param.private_data = ird_ord_hdr; conn_param.private_data_len = sizeof(ird_ord_hdr); } else { @@ -2081,10 +2088,13 @@ static bool rdma_frwr_is_supported(struct ib_device_attr *attrs) return true; } -static int smb_direct_handle_connect_request(struct rdma_cm_id *new_cm_id) +static int smb_direct_handle_connect_request(struct rdma_cm_id *new_cm_id, + struct rdma_cm_event *event) { struct smb_direct_transport *t; struct task_struct *handler; + u8 peer_initiator_depth; + u8 peer_responder_resources; int ret; if (!rdma_frwr_is_supported(&new_cm_id->device->attrs)) { @@ -2098,6 +2108,67 @@ static int smb_direct_handle_connect_request(struct rdma_cm_id *new_cm_id) if (!t) return -ENOMEM; + peer_initiator_depth = event->param.conn.initiator_depth; + peer_responder_resources = event->param.conn.responder_resources; + if (rdma_protocol_iwarp(new_cm_id->device, new_cm_id->port_num) && + event->param.conn.private_data_len == 8) { + /* + * Legacy clients with only iWarp MPA v1 support + * need a private blob in order to negotiate + * the IRD/ORD values. + */ + const __be32 *ird_ord_hdr = event->param.conn.private_data; + u32 ird32 = be32_to_cpu(ird_ord_hdr[0]); + u32 ord32 = be32_to_cpu(ird_ord_hdr[1]); + + /* + * cifs.ko sends the legacy IRD/ORD negotiation + * event if iWarp MPA v2 was used. + * + * Here we check that the values match and only + * mark the client as legacy if they don't match. + */ + if ((u32)event->param.conn.initiator_depth != ird32 || + (u32)event->param.conn.responder_resources != ord32) { + /* + * There are broken clients (old cifs.ko) + * using little endian and also + * struct rdma_conn_param only uses u8 + * for initiator_depth and responder_resources, + * so we truncate the value to U8_MAX. + * + * smb_direct_accept_client() will then + * do the real negotiation in order to + * select the minimum between client and + * server. + */ + ird32 = min_t(u32, ird32, U8_MAX); + ord32 = min_t(u32, ord32, U8_MAX); + + t->legacy_iwarp = true; + peer_initiator_depth = (u8)ird32; + peer_responder_resources = (u8)ord32; + } + } + + /* + * First set what the we as server are able to support + */ + t->initiator_depth = min_t(u8, t->initiator_depth, + new_cm_id->device->attrs.max_qp_rd_atom); + + /* + * negotiate the value by using the minimum + * between client and server if the client provided + * non 0 values. + */ + if (peer_initiator_depth != 0) + t->initiator_depth = min_t(u8, t->initiator_depth, + peer_initiator_depth); + if (peer_responder_resources != 0) + t->responder_resources = min_t(u8, t->responder_resources, + peer_responder_resources); + ret = smb_direct_connect(t); if (ret) goto out_err; @@ -2122,7 +2193,7 @@ static int smb_direct_listen_handler(struct rdma_cm_id *cm_id, { switch (event->event) { case RDMA_CM_EVENT_CONNECT_REQUEST: { - int ret = smb_direct_handle_connect_request(cm_id); + int ret = smb_direct_handle_connect_request(cm_id, event); if (ret) { pr_err("Can't create transport: %d\n", ret); From 575c1af4dc64434a42c4b00e5b7fd298e8c68c3c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 16 Aug 2025 10:24:30 +0900 Subject: [PATCH 088/159] smb: server: make use of common smbdirect_pdu.h Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: Namjae Jeon Cc: Hyunchul Lee Cc: Meetakshi Setiya Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 47 +++++++++++++++++----------------- fs/smb/server/transport_rdma.h | 41 ----------------------------- 2 files changed, 24 insertions(+), 64 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index e1f659d3b4cf..9401ba09310a 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -23,12 +23,13 @@ #include "connection.h" #include "smb_common.h" #include "../common/smb2status.h" +#include "../common/smbdirect/smbdirect_pdu.h" #include "transport_rdma.h" #define SMB_DIRECT_PORT_IWARP 5445 #define SMB_DIRECT_PORT_INFINIBAND 445 -#define SMB_DIRECT_VERSION_LE cpu_to_le16(0x0100) +#define SMB_DIRECT_VERSION_LE cpu_to_le16(SMBDIRECT_V1) /* SMB_DIRECT negotiation timeout in seconds */ #define SMB_DIRECT_NEGOTIATE_TIMEOUT 120 @@ -479,8 +480,8 @@ static int smb_direct_check_recvmsg(struct smb_direct_recvmsg *recvmsg) { switch (recvmsg->type) { case SMB_DIRECT_MSG_DATA_TRANSFER: { - struct smb_direct_data_transfer *req = - (struct smb_direct_data_transfer *)recvmsg->packet; + struct smbdirect_data_transfer *req = + (struct smbdirect_data_transfer *)recvmsg->packet; struct smb2_hdr *hdr = (struct smb2_hdr *)(recvmsg->packet + le32_to_cpu(req->data_offset)); ksmbd_debug(RDMA, @@ -492,8 +493,8 @@ static int smb_direct_check_recvmsg(struct smb_direct_recvmsg *recvmsg) break; } case SMB_DIRECT_MSG_NEGOTIATE_REQ: { - struct smb_direct_negotiate_req *req = - (struct smb_direct_negotiate_req *)recvmsg->packet; + struct smbdirect_negotiate_req *req = + (struct smbdirect_negotiate_req *)recvmsg->packet; ksmbd_debug(RDMA, "MinVersion: %u, MaxVersion: %u, CreditRequested: %u, MaxSendSize: %u, MaxRecvSize: %u, MaxFragmentedSize: %u\n", le16_to_cpu(req->min_version), @@ -547,7 +548,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) switch (recvmsg->type) { case SMB_DIRECT_MSG_NEGOTIATE_REQ: - if (wc->byte_len < sizeof(struct smb_direct_negotiate_req)) { + if (wc->byte_len < sizeof(struct smbdirect_negotiate_req)) { put_recvmsg(t, recvmsg); smb_direct_disconnect_rdma_connection(t); return; @@ -559,13 +560,13 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) wake_up_interruptible(&t->wait_status); return; case SMB_DIRECT_MSG_DATA_TRANSFER: { - struct smb_direct_data_transfer *data_transfer = - (struct smb_direct_data_transfer *)recvmsg->packet; + struct smbdirect_data_transfer *data_transfer = + (struct smbdirect_data_transfer *)recvmsg->packet; u32 remaining_data_length, data_offset, data_length; int avail_recvmsg_count, receive_credits; if (wc->byte_len < - offsetof(struct smb_direct_data_transfer, padding)) { + offsetof(struct smbdirect_data_transfer, padding)) { put_recvmsg(t, recvmsg); smb_direct_disconnect_rdma_connection(t); return; @@ -615,7 +616,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) &t->send_credits); if (le16_to_cpu(data_transfer->flags) & - SMB_DIRECT_RESPONSE_REQUESTED) + SMBDIRECT_FLAG_RESPONSE_REQUESTED) queue_work(smb_direct_wq, &t->send_immediate_work); if (atomic_read(&t->send_credits) > 0) @@ -680,7 +681,7 @@ static int smb_direct_read(struct ksmbd_transport *t, char *buf, unsigned int size, int unused) { struct smb_direct_recvmsg *recvmsg; - struct smb_direct_data_transfer *data_transfer; + struct smbdirect_data_transfer *data_transfer; int to_copy, to_read, data_read, offset; u32 data_length, remaining_data_length, data_offset; int rc; @@ -1016,7 +1017,7 @@ static int smb_direct_create_header(struct smb_direct_transport *t, struct smb_direct_sendmsg **sendmsg_out) { struct smb_direct_sendmsg *sendmsg; - struct smb_direct_data_transfer *packet; + struct smbdirect_data_transfer *packet; int header_length; int ret; @@ -1025,7 +1026,7 @@ static int smb_direct_create_header(struct smb_direct_transport *t, return PTR_ERR(sendmsg); /* Fill in the packet header */ - packet = (struct smb_direct_data_transfer *)sendmsg->packet; + packet = (struct smbdirect_data_transfer *)sendmsg->packet; packet->credits_requested = cpu_to_le16(t->send_credit_target); packet->credits_granted = cpu_to_le16(manage_credits_prior_sending(t)); @@ -1048,11 +1049,11 @@ static int smb_direct_create_header(struct smb_direct_transport *t, le32_to_cpu(packet->remaining_data_length)); /* Map the packet to DMA */ - header_length = sizeof(struct smb_direct_data_transfer); + header_length = sizeof(struct smbdirect_data_transfer); /* If this is a packet without payload, don't send padding */ if (!size) header_length = - offsetof(struct smb_direct_data_transfer, padding); + offsetof(struct smbdirect_data_transfer, padding); sendmsg->sge[0].addr = ib_dma_map_single(t->cm_id->device, (void *)packet, @@ -1228,7 +1229,7 @@ static int smb_direct_writev(struct ksmbd_transport *t, size_t iov_idx; size_t iov_ofs; size_t max_iov_size = st->max_send_size - - sizeof(struct smb_direct_data_transfer); + sizeof(struct smbdirect_data_transfer); int ret; struct smb_direct_send_ctx send_ctx; int error = 0; @@ -1627,18 +1628,18 @@ static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, int failed) { struct smb_direct_sendmsg *sendmsg; - struct smb_direct_negotiate_resp *resp; + struct smbdirect_negotiate_resp *resp; int ret; sendmsg = smb_direct_alloc_sendmsg(t); if (IS_ERR(sendmsg)) return -ENOMEM; - resp = (struct smb_direct_negotiate_resp *)sendmsg->packet; + resp = (struct smbdirect_negotiate_resp *)sendmsg->packet; if (failed) { memset(resp, 0, sizeof(*resp)); - resp->min_version = cpu_to_le16(0x0100); - resp->max_version = cpu_to_le16(0x0100); + resp->min_version = SMB_DIRECT_VERSION_LE; + resp->max_version = SMB_DIRECT_VERSION_LE; resp->status = STATUS_NOT_SUPPORTED; } else { resp->status = STATUS_SUCCESS; @@ -1875,7 +1876,7 @@ static int smb_direct_create_pools(struct smb_direct_transport *t) snprintf(name, sizeof(name), "smb_direct_rqst_pool_%p", t); t->sendmsg_cache = kmem_cache_create(name, sizeof(struct smb_direct_sendmsg) + - sizeof(struct smb_direct_negotiate_resp), + sizeof(struct smbdirect_negotiate_resp), 0, SLAB_HWCACHE_ALIGN, NULL); if (!t->sendmsg_cache) return -ENOMEM; @@ -2008,7 +2009,7 @@ static int smb_direct_prepare(struct ksmbd_transport *t) { struct smb_direct_transport *st = smb_trans_direct_transfort(t); struct smb_direct_recvmsg *recvmsg; - struct smb_direct_negotiate_req *req; + struct smbdirect_negotiate_req *req; int ret; ksmbd_debug(RDMA, "Waiting for SMB_DIRECT negotiate request\n"); @@ -2027,7 +2028,7 @@ static int smb_direct_prepare(struct ksmbd_transport *t) if (ret == -ECONNABORTED) goto out; - req = (struct smb_direct_negotiate_req *)recvmsg->packet; + req = (struct smbdirect_negotiate_req *)recvmsg->packet; st->max_recv_size = min_t(int, st->max_recv_size, le32_to_cpu(req->preferred_send_size)); st->max_send_size = min_t(int, st->max_send_size, diff --git a/fs/smb/server/transport_rdma.h b/fs/smb/server/transport_rdma.h index a2291b77488a..63eab9f8f13d 100644 --- a/fs/smb/server/transport_rdma.h +++ b/fs/smb/server/transport_rdma.h @@ -11,47 +11,6 @@ #define SMBD_MIN_IOSIZE (512 * 1024) #define SMBD_MAX_IOSIZE (16 * 1024 * 1024) -/* SMB DIRECT negotiation request packet [MS-SMBD] 2.2.1 */ -struct smb_direct_negotiate_req { - __le16 min_version; - __le16 max_version; - __le16 reserved; - __le16 credits_requested; - __le32 preferred_send_size; - __le32 max_receive_size; - __le32 max_fragmented_size; -} __packed; - -/* SMB DIRECT negotiation response packet [MS-SMBD] 2.2.2 */ -struct smb_direct_negotiate_resp { - __le16 min_version; - __le16 max_version; - __le16 negotiated_version; - __le16 reserved; - __le16 credits_requested; - __le16 credits_granted; - __le32 status; - __le32 max_readwrite_size; - __le32 preferred_send_size; - __le32 max_receive_size; - __le32 max_fragmented_size; -} __packed; - -#define SMB_DIRECT_RESPONSE_REQUESTED 0x0001 - -/* SMB DIRECT data transfer packet with payload [MS-SMBD] 2.2.3 */ -struct smb_direct_data_transfer { - __le16 credits_requested; - __le16 credits_granted; - __le16 flags; - __le16 reserved; - __le32 remaining_data_length; - __le32 data_offset; - __le32 data_length; - __le32 padding; - __u8 buffer[]; -} __packed; - #ifdef CONFIG_SMB_SERVER_SMBDIRECT int ksmbd_rdma_init(void); void ksmbd_rdma_stop_listening(void); From e7de2c4521ce86eb23de133cdf48cb460cff5a91 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 6 Aug 2025 19:35:55 +0200 Subject: [PATCH 089/159] smb: server: make use of common smbdirect.h Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: Namjae Jeon Cc: Hyunchul Lee Cc: Meetakshi Setiya Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/connection.c | 4 ++-- fs/smb/server/connection.h | 10 ++++++---- fs/smb/server/smb2pdu.c | 11 ++++++----- fs/smb/server/smb2pdu.h | 6 ------ fs/smb/server/transport_rdma.c | 7 ++++--- 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c index 67c4f73398df..91a934411134 100644 --- a/fs/smb/server/connection.c +++ b/fs/smb/server/connection.c @@ -243,7 +243,7 @@ int ksmbd_conn_write(struct ksmbd_work *work) int ksmbd_conn_rdma_read(struct ksmbd_conn *conn, void *buf, unsigned int buflen, - struct smb2_buffer_desc_v1 *desc, + struct smbdirect_buffer_descriptor_v1 *desc, unsigned int desc_len) { int ret = -EINVAL; @@ -257,7 +257,7 @@ int ksmbd_conn_rdma_read(struct ksmbd_conn *conn, int ksmbd_conn_rdma_write(struct ksmbd_conn *conn, void *buf, unsigned int buflen, - struct smb2_buffer_desc_v1 *desc, + struct smbdirect_buffer_descriptor_v1 *desc, unsigned int desc_len) { int ret = -EINVAL; diff --git a/fs/smb/server/connection.h b/fs/smb/server/connection.h index 2aa8084bb593..07b43634262a 100644 --- a/fs/smb/server/connection.h +++ b/fs/smb/server/connection.h @@ -19,6 +19,8 @@ #include "smb_common.h" #include "ksmbd_work.h" +struct smbdirect_buffer_descriptor_v1; + #define KSMBD_SOCKET_BACKLOG 16 enum { @@ -133,11 +135,11 @@ struct ksmbd_transport_ops { unsigned int remote_key); int (*rdma_read)(struct ksmbd_transport *t, void *buf, unsigned int len, - struct smb2_buffer_desc_v1 *desc, + struct smbdirect_buffer_descriptor_v1 *desc, unsigned int desc_len); int (*rdma_write)(struct ksmbd_transport *t, void *buf, unsigned int len, - struct smb2_buffer_desc_v1 *desc, + struct smbdirect_buffer_descriptor_v1 *desc, unsigned int desc_len); void (*free_transport)(struct ksmbd_transport *kt); }; @@ -163,11 +165,11 @@ bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c); int ksmbd_conn_write(struct ksmbd_work *work); int ksmbd_conn_rdma_read(struct ksmbd_conn *conn, void *buf, unsigned int buflen, - struct smb2_buffer_desc_v1 *desc, + struct smbdirect_buffer_descriptor_v1 *desc, unsigned int desc_len); int ksmbd_conn_rdma_write(struct ksmbd_conn *conn, void *buf, unsigned int buflen, - struct smb2_buffer_desc_v1 *desc, + struct smbdirect_buffer_descriptor_v1 *desc, unsigned int desc_len); void ksmbd_conn_enqueue_request(struct ksmbd_work *work); void ksmbd_conn_try_dequeue_request(struct ksmbd_work *work); diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index a565fc36cee6..00e644935f28 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -23,6 +23,7 @@ #include "asn1.h" #include "connection.h" #include "transport_ipc.h" +#include "../common/smbdirect/smbdirect.h" #include "transport_rdma.h" #include "vfs.h" #include "vfs_cache.h" @@ -6665,7 +6666,7 @@ static noinline int smb2_read_pipe(struct ksmbd_work *work) } static int smb2_set_remote_key_for_rdma(struct ksmbd_work *work, - struct smb2_buffer_desc_v1 *desc, + struct smbdirect_buffer_descriptor_v1 *desc, __le32 Channel, __le16 ChannelInfoLength) { @@ -6701,7 +6702,7 @@ static ssize_t smb2_read_rdma_channel(struct ksmbd_work *work, int err; err = ksmbd_conn_rdma_write(work->conn, data_buf, length, - (struct smb2_buffer_desc_v1 *) + (struct smbdirect_buffer_descriptor_v1 *) ((char *)req + le16_to_cpu(req->ReadChannelInfoOffset)), le16_to_cpu(req->ReadChannelInfoLength)); if (err) @@ -6772,7 +6773,7 @@ int smb2_read(struct ksmbd_work *work) goto out; } err = smb2_set_remote_key_for_rdma(work, - (struct smb2_buffer_desc_v1 *) + (struct smbdirect_buffer_descriptor_v1 *) ((char *)req + ch_offset), req->Channel, req->ReadChannelInfoLength); @@ -6967,7 +6968,7 @@ static ssize_t smb2_write_rdma_channel(struct ksmbd_work *work, return -ENOMEM; ret = ksmbd_conn_rdma_read(work->conn, data_buf, length, - (struct smb2_buffer_desc_v1 *) + (struct smbdirect_buffer_descriptor_v1 *) ((char *)req + le16_to_cpu(req->WriteChannelInfoOffset)), le16_to_cpu(req->WriteChannelInfoLength)); if (ret < 0) { @@ -7032,7 +7033,7 @@ int smb2_write(struct ksmbd_work *work) goto out; } err = smb2_set_remote_key_for_rdma(work, - (struct smb2_buffer_desc_v1 *) + (struct smbdirect_buffer_descriptor_v1 *) ((char *)req + ch_offset), req->Channel, req->WriteChannelInfoLength); diff --git a/fs/smb/server/smb2pdu.h b/fs/smb/server/smb2pdu.h index 16ae8a10490b..5163d5241b90 100644 --- a/fs/smb/server/smb2pdu.h +++ b/fs/smb/server/smb2pdu.h @@ -136,12 +136,6 @@ struct create_posix_rsp { u8 SidBuffer[44]; } __packed; -struct smb2_buffer_desc_v1 { - __le64 offset; - __le32 token; - __le32 length; -} __packed; - #define SMB2_0_IOCTL_IS_FSCTL 0x00000001 struct smb_sockaddr_in { diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 9401ba09310a..72ae3c9714a6 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -23,6 +23,7 @@ #include "connection.h" #include "smb_common.h" #include "../common/smb2status.h" +#include "../common/smbdirect/smbdirect.h" #include "../common/smbdirect/smbdirect_pdu.h" #include "transport_rdma.h" @@ -1402,7 +1403,7 @@ static void write_done(struct ib_cq *cq, struct ib_wc *wc) static int smb_direct_rdma_xmit(struct smb_direct_transport *t, void *buf, int buf_len, - struct smb2_buffer_desc_v1 *desc, + struct smbdirect_buffer_descriptor_v1 *desc, unsigned int desc_len, bool is_read) { @@ -1532,7 +1533,7 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, static int smb_direct_rdma_write(struct ksmbd_transport *t, void *buf, unsigned int buflen, - struct smb2_buffer_desc_v1 *desc, + struct smbdirect_buffer_descriptor_v1 *desc, unsigned int desc_len) { return smb_direct_rdma_xmit(smb_trans_direct_transfort(t), buf, buflen, @@ -1541,7 +1542,7 @@ static int smb_direct_rdma_write(struct ksmbd_transport *t, static int smb_direct_rdma_read(struct ksmbd_transport *t, void *buf, unsigned int buflen, - struct smb2_buffer_desc_v1 *desc, + struct smbdirect_buffer_descriptor_v1 *desc, unsigned int desc_len) { return smb_direct_rdma_xmit(smb_trans_direct_transfort(t), buf, buflen, From 4c564f03e23b1ea55b77679192a4cb07f5b3e7f3 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 6 Aug 2025 19:35:56 +0200 Subject: [PATCH 090/159] smb: server: make use of common smbdirect_socket This is the next step in the direction of a common smbdirect layer. Currently only structures are shared, but that will change over time until everything is shared. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: Namjae Jeon Cc: Hyunchul Lee Cc: Meetakshi Setiya Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 241 ++++++++++++++++++--------------- 1 file changed, 133 insertions(+), 108 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 72ae3c9714a6..e2d8ac087344 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -25,6 +25,7 @@ #include "../common/smb2status.h" #include "../common/smbdirect/smbdirect.h" #include "../common/smbdirect/smbdirect_pdu.h" +#include "../common/smbdirect/smbdirect_socket.h" #include "transport_rdma.h" #define SMB_DIRECT_PORT_IWARP 5445 @@ -89,26 +90,14 @@ static struct smb_direct_listener { static struct workqueue_struct *smb_direct_wq; -enum smb_direct_status { - SMB_DIRECT_CS_NEW = 0, - SMB_DIRECT_CS_CONNECTED, - SMB_DIRECT_CS_DISCONNECTING, - SMB_DIRECT_CS_DISCONNECTED, -}; - struct smb_direct_transport { struct ksmbd_transport transport; - enum smb_direct_status status; + struct smbdirect_socket socket; + bool full_packet_received; wait_queue_head_t wait_status; - struct rdma_cm_id *cm_id; - struct ib_cq *send_cq; - struct ib_cq *recv_cq; - struct ib_pd *pd; - struct ib_qp *qp; - int max_send_size; int max_recv_size; int max_fragmented_send_size; @@ -271,8 +260,10 @@ smb_direct_recvmsg *get_free_recvmsg(struct smb_direct_transport *t) static void put_recvmsg(struct smb_direct_transport *t, struct smb_direct_recvmsg *recvmsg) { + struct smbdirect_socket *sc = &t->socket; + if (likely(recvmsg->sge.length != 0)) { - ib_dma_unmap_single(t->cm_id->device, + ib_dma_unmap_single(sc->ib.dev, recvmsg->sge.addr, recvmsg->sge.length, DMA_FROM_DEVICE); @@ -316,17 +307,20 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work) struct smb_direct_transport *t = container_of(work, struct smb_direct_transport, disconnect_work); + struct smbdirect_socket *sc = &t->socket; - if (t->status == SMB_DIRECT_CS_CONNECTED) { - t->status = SMB_DIRECT_CS_DISCONNECTING; - rdma_disconnect(t->cm_id); + if (sc->status == SMBDIRECT_SOCKET_CONNECTED) { + sc->status = SMBDIRECT_SOCKET_DISCONNECTING; + rdma_disconnect(sc->rdma.cm_id); } } static void smb_direct_disconnect_rdma_connection(struct smb_direct_transport *t) { - if (t->status == SMB_DIRECT_CS_CONNECTED) + struct smbdirect_socket *sc = &t->socket; + + if (sc->status == SMBDIRECT_SOCKET_CONNECTED) queue_work(smb_direct_wq, &t->disconnect_work); } @@ -334,8 +328,9 @@ static void smb_direct_send_immediate_work(struct work_struct *work) { struct smb_direct_transport *t = container_of(work, struct smb_direct_transport, send_immediate_work); + struct smbdirect_socket *sc = &t->socket; - if (t->status != SMB_DIRECT_CS_CONNECTED) + if (sc->status != SMBDIRECT_SOCKET_CONNECTED) return; smb_direct_post_send_data(t, NULL, NULL, 0, 0); @@ -344,19 +339,23 @@ static void smb_direct_send_immediate_work(struct work_struct *work) static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) { struct smb_direct_transport *t; + struct smbdirect_socket *sc; struct ksmbd_conn *conn; t = kzalloc(sizeof(*t), KSMBD_DEFAULT_GFP); if (!t) return NULL; + sc = &t->socket; - t->cm_id = cm_id; + sc->rdma.cm_id = cm_id; cm_id->context = t; t->initiator_depth = SMB_DIRECT_CM_INITIATOR_DEPTH; t->responder_resources = 1; - t->status = SMB_DIRECT_CS_NEW; + sc->ib.dev = sc->rdma.cm_id->device; + + sc->status = SMBDIRECT_SOCKET_CREATED; init_waitqueue_head(&t->wait_status); spin_lock_init(&t->reassembly_queue_lock); @@ -400,6 +399,7 @@ static void smb_direct_free_transport(struct ksmbd_transport *kt) static void free_transport(struct smb_direct_transport *t) { + struct smbdirect_socket *sc = &t->socket; struct smb_direct_recvmsg *recvmsg; wake_up_interruptible(&t->wait_send_credits); @@ -412,11 +412,11 @@ static void free_transport(struct smb_direct_transport *t) disable_work_sync(&t->post_recv_credits_work); disable_work_sync(&t->send_immediate_work); - if (t->qp) { - ib_drain_qp(t->qp); - ib_mr_pool_destroy(t->qp, &t->qp->rdma_mrs); - t->qp = NULL; - rdma_destroy_qp(t->cm_id); + if (sc->ib.qp) { + ib_drain_qp(sc->ib.qp); + ib_mr_pool_destroy(sc->ib.qp, &sc->ib.qp->rdma_mrs); + sc->ib.qp = NULL; + rdma_destroy_qp(sc->rdma.cm_id); } ksmbd_debug(RDMA, "drain the reassembly queue\n"); @@ -433,14 +433,14 @@ static void free_transport(struct smb_direct_transport *t) } while (recvmsg); t->reassembly_data_length = 0; - if (t->send_cq) - ib_free_cq(t->send_cq); - if (t->recv_cq) - ib_free_cq(t->recv_cq); - if (t->pd) - ib_dealloc_pd(t->pd); - if (t->cm_id) - rdma_destroy_id(t->cm_id); + if (sc->ib.send_cq) + ib_free_cq(sc->ib.send_cq); + if (sc->ib.recv_cq) + ib_free_cq(sc->ib.recv_cq); + if (sc->ib.pd) + ib_dealloc_pd(sc->ib.pd); + if (sc->rdma.cm_id) + rdma_destroy_id(sc->rdma.cm_id); smb_direct_destroy_pools(t); ksmbd_conn_free(KSMBD_TRANS(t)->conn); @@ -463,14 +463,15 @@ static struct smb_direct_sendmsg static void smb_direct_free_sendmsg(struct smb_direct_transport *t, struct smb_direct_sendmsg *msg) { + struct smbdirect_socket *sc = &t->socket; int i; if (msg->num_sge > 0) { - ib_dma_unmap_single(t->cm_id->device, + ib_dma_unmap_single(sc->ib.dev, msg->sge[0].addr, msg->sge[0].length, DMA_TO_DEVICE); for (i = 1; i < msg->num_sge; i++) - ib_dma_unmap_page(t->cm_id->device, + ib_dma_unmap_page(sc->ib.dev, msg->sge[i].addr, msg->sge[i].length, DMA_TO_DEVICE); } @@ -525,9 +526,11 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) { struct smb_direct_recvmsg *recvmsg; struct smb_direct_transport *t; + struct smbdirect_socket *sc; recvmsg = container_of(wc->wr_cqe, struct smb_direct_recvmsg, cqe); t = recvmsg->transport; + sc = &t->socket; if (wc->status != IB_WC_SUCCESS || wc->opcode != IB_WC_RECV) { put_recvmsg(t, recvmsg); @@ -556,7 +559,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) } t->negotiation_requested = true; t->full_packet_received = true; - t->status = SMB_DIRECT_CS_CONNECTED; + sc->status = SMBDIRECT_SOCKET_CONNECTED; enqueue_reassembly(t, recvmsg, 0); wake_up_interruptible(&t->wait_status); return; @@ -647,17 +650,18 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) static int smb_direct_post_recv(struct smb_direct_transport *t, struct smb_direct_recvmsg *recvmsg) { + struct smbdirect_socket *sc = &t->socket; struct ib_recv_wr wr; int ret; - recvmsg->sge.addr = ib_dma_map_single(t->cm_id->device, + recvmsg->sge.addr = ib_dma_map_single(sc->ib.dev, recvmsg->packet, t->max_recv_size, DMA_FROM_DEVICE); - ret = ib_dma_mapping_error(t->cm_id->device, recvmsg->sge.addr); + ret = ib_dma_mapping_error(sc->ib.dev, recvmsg->sge.addr); if (ret) return ret; recvmsg->sge.length = t->max_recv_size; - recvmsg->sge.lkey = t->pd->local_dma_lkey; + recvmsg->sge.lkey = sc->ib.pd->local_dma_lkey; recvmsg->cqe.done = recv_done; wr.wr_cqe = &recvmsg->cqe; @@ -665,10 +669,10 @@ static int smb_direct_post_recv(struct smb_direct_transport *t, wr.sg_list = &recvmsg->sge; wr.num_sge = 1; - ret = ib_post_recv(t->qp, &wr, NULL); + ret = ib_post_recv(sc->ib.qp, &wr, NULL); if (ret) { pr_err("Can't post recv: %d\n", ret); - ib_dma_unmap_single(t->cm_id->device, + ib_dma_unmap_single(sc->ib.dev, recvmsg->sge.addr, recvmsg->sge.length, DMA_FROM_DEVICE); recvmsg->sge.length = 0; @@ -687,9 +691,10 @@ static int smb_direct_read(struct ksmbd_transport *t, char *buf, u32 data_length, remaining_data_length, data_offset; int rc; struct smb_direct_transport *st = smb_trans_direct_transfort(t); + struct smbdirect_socket *sc = &st->socket; again: - if (st->status != SMB_DIRECT_CS_CONNECTED) { + if (sc->status != SMBDIRECT_SOCKET_CONNECTED) { pr_err("disconnected\n"); return -ENOTCONN; } @@ -798,7 +803,7 @@ static int smb_direct_read(struct ksmbd_transport *t, char *buf, ksmbd_debug(RDMA, "wait_event on more data\n"); rc = wait_event_interruptible(st->wait_reassembly_queue, st->reassembly_data_length >= size || - st->status != SMB_DIRECT_CS_CONNECTED); + sc->status != SMBDIRECT_SOCKET_CONNECTED); if (rc) return -EINTR; @@ -900,10 +905,11 @@ static int manage_credits_prior_sending(struct smb_direct_transport *t) static int smb_direct_post_send(struct smb_direct_transport *t, struct ib_send_wr *wr) { + struct smbdirect_socket *sc = &t->socket; int ret; atomic_inc(&t->send_pending); - ret = ib_post_send(t->qp, wr, NULL); + ret = ib_post_send(sc->ib.qp, wr, NULL); if (ret) { pr_err("failed to post send: %d\n", ret); if (atomic_dec_and_test(&t->send_pending)) @@ -968,6 +974,7 @@ static int wait_for_credits(struct smb_direct_transport *t, wait_queue_head_t *waitq, atomic_t *total_credits, int needed) { + struct smbdirect_socket *sc = &t->socket; int ret; do { @@ -977,9 +984,9 @@ static int wait_for_credits(struct smb_direct_transport *t, atomic_add(needed, total_credits); ret = wait_event_interruptible(*waitq, atomic_read(total_credits) >= needed || - t->status != SMB_DIRECT_CS_CONNECTED); + sc->status != SMBDIRECT_SOCKET_CONNECTED); - if (t->status != SMB_DIRECT_CS_CONNECTED) + if (sc->status != SMBDIRECT_SOCKET_CONNECTED) return -ENOTCONN; else if (ret < 0) return ret; @@ -1017,6 +1024,7 @@ static int smb_direct_create_header(struct smb_direct_transport *t, int size, int remaining_data_length, struct smb_direct_sendmsg **sendmsg_out) { + struct smbdirect_socket *sc = &t->socket; struct smb_direct_sendmsg *sendmsg; struct smbdirect_data_transfer *packet; int header_length; @@ -1056,11 +1064,11 @@ static int smb_direct_create_header(struct smb_direct_transport *t, header_length = offsetof(struct smbdirect_data_transfer, padding); - sendmsg->sge[0].addr = ib_dma_map_single(t->cm_id->device, + sendmsg->sge[0].addr = ib_dma_map_single(sc->ib.dev, (void *)packet, header_length, DMA_TO_DEVICE); - ret = ib_dma_mapping_error(t->cm_id->device, sendmsg->sge[0].addr); + ret = ib_dma_mapping_error(sc->ib.dev, sendmsg->sge[0].addr); if (ret) { smb_direct_free_sendmsg(t, sendmsg); return ret; @@ -1068,7 +1076,7 @@ static int smb_direct_create_header(struct smb_direct_transport *t, sendmsg->num_sge = 1; sendmsg->sge[0].length = header_length; - sendmsg->sge[0].lkey = t->pd->local_dma_lkey; + sendmsg->sge[0].lkey = sc->ib.pd->local_dma_lkey; *sendmsg_out = sendmsg; return 0; @@ -1122,10 +1130,11 @@ static int post_sendmsg(struct smb_direct_transport *t, struct smb_direct_send_ctx *send_ctx, struct smb_direct_sendmsg *msg) { + struct smbdirect_socket *sc = &t->socket; int i; for (i = 0; i < msg->num_sge; i++) - ib_dma_sync_single_for_device(t->cm_id->device, + ib_dma_sync_single_for_device(sc->ib.dev, msg->sge[i].addr, msg->sge[i].length, DMA_TO_DEVICE); @@ -1161,6 +1170,7 @@ static int smb_direct_post_send_data(struct smb_direct_transport *t, struct kvec *iov, int niov, int remaining_data_length) { + struct smbdirect_socket *sc = &t->socket; int i, j, ret; struct smb_direct_sendmsg *msg; int data_length; @@ -1186,7 +1196,7 @@ static int smb_direct_post_send_data(struct smb_direct_transport *t, int sg_cnt; sg_init_table(sg, SMB_DIRECT_MAX_SEND_SGES - 1); - sg_cnt = get_mapped_sg_list(t->cm_id->device, + sg_cnt = get_mapped_sg_list(sc->ib.dev, iov[i].iov_base, iov[i].iov_len, sg, SMB_DIRECT_MAX_SEND_SGES - 1, DMA_TO_DEVICE); @@ -1197,7 +1207,7 @@ static int smb_direct_post_send_data(struct smb_direct_transport *t, } else if (sg_cnt + msg->num_sge > SMB_DIRECT_MAX_SEND_SGES) { pr_err("buffer not fitted into sges\n"); ret = -E2BIG; - ib_dma_unmap_sg(t->cm_id->device, sg, sg_cnt, + ib_dma_unmap_sg(sc->ib.dev, sg, sg_cnt, DMA_TO_DEVICE); goto err; } @@ -1206,7 +1216,7 @@ static int smb_direct_post_send_data(struct smb_direct_transport *t, sge = &msg->sge[msg->num_sge]; sge->addr = sg_dma_address(&sg[j]); sge->length = sg_dma_len(&sg[j]); - sge->lkey = t->pd->local_dma_lkey; + sge->lkey = sc->ib.pd->local_dma_lkey; msg->num_sge++; } } @@ -1226,6 +1236,7 @@ static int smb_direct_writev(struct ksmbd_transport *t, bool need_invalidate, unsigned int remote_key) { struct smb_direct_transport *st = smb_trans_direct_transfort(t); + struct smbdirect_socket *sc = &st->socket; size_t remaining_data_length; size_t iov_idx; size_t iov_ofs; @@ -1235,7 +1246,7 @@ static int smb_direct_writev(struct ksmbd_transport *t, struct smb_direct_send_ctx send_ctx; int error = 0; - if (st->status != SMB_DIRECT_CS_CONNECTED) + if (sc->status != SMBDIRECT_SOCKET_CONNECTED) return -ENOTCONN; //FIXME: skip RFC1002 header.. @@ -1367,7 +1378,9 @@ static void smb_direct_free_rdma_rw_msg(struct smb_direct_transport *t, struct smb_direct_rdma_rw_msg *msg, enum dma_data_direction dir) { - rdma_rw_ctx_destroy(&msg->rw_ctx, t->qp, t->qp->port, + struct smbdirect_socket *sc = &t->socket; + + rdma_rw_ctx_destroy(&msg->rw_ctx, sc->ib.qp, sc->ib.qp->port, msg->sgt.sgl, msg->sgt.nents, dir); sg_free_table_chained(&msg->sgt, SG_CHUNK_SIZE); kfree(msg); @@ -1407,6 +1420,7 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, unsigned int desc_len, bool is_read) { + struct smbdirect_socket *sc = &t->socket; struct smb_direct_rdma_rw_msg *msg, *next_msg; int i, ret; DECLARE_COMPLETION_ONSTACK(completion); @@ -1416,7 +1430,7 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, int credits_needed; unsigned int desc_buf_len, desc_num = 0; - if (t->status != SMB_DIRECT_CS_CONNECTED) + if (sc->status != SMBDIRECT_SOCKET_CONNECTED) return -ENOTCONN; if (buf_len > t->max_rdma_rw_size) @@ -1486,7 +1500,7 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, goto out; } - ret = rdma_rw_ctx_init(&msg->rw_ctx, t->qp, t->qp->port, + ret = rdma_rw_ctx_init(&msg->rw_ctx, sc->ib.qp, sc->ib.qp->port, msg->sgt.sgl, get_buf_page_count(desc_buf, desc_buf_len), 0, @@ -1507,11 +1521,11 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, /* concatenate work requests of rdma_rw_ctxs */ first_wr = NULL; list_for_each_entry_reverse(msg, &msg_list, list) { - first_wr = rdma_rw_ctx_wrs(&msg->rw_ctx, t->qp, t->qp->port, + first_wr = rdma_rw_ctx_wrs(&msg->rw_ctx, sc->ib.qp, sc->ib.qp->port, &msg->cqe, first_wr); } - ret = ib_post_send(t->qp, first_wr, NULL); + ret = ib_post_send(sc->ib.qp, first_wr, NULL); if (ret) { pr_err("failed to post send wr for RDMA R/W: %d\n", ret); goto out; @@ -1552,20 +1566,22 @@ static int smb_direct_rdma_read(struct ksmbd_transport *t, static void smb_direct_disconnect(struct ksmbd_transport *t) { struct smb_direct_transport *st = smb_trans_direct_transfort(t); + struct smbdirect_socket *sc = &st->socket; - ksmbd_debug(RDMA, "Disconnecting cm_id=%p\n", st->cm_id); + ksmbd_debug(RDMA, "Disconnecting cm_id=%p\n", sc->rdma.cm_id); smb_direct_disconnect_rdma_work(&st->disconnect_work); wait_event_interruptible(st->wait_status, - st->status == SMB_DIRECT_CS_DISCONNECTED); + sc->status == SMBDIRECT_SOCKET_DISCONNECTED); free_transport(st); } static void smb_direct_shutdown(struct ksmbd_transport *t) { struct smb_direct_transport *st = smb_trans_direct_transfort(t); + struct smbdirect_socket *sc = &st->socket; - ksmbd_debug(RDMA, "smb-direct shutdown cm_id=%p\n", st->cm_id); + ksmbd_debug(RDMA, "smb-direct shutdown cm_id=%p\n", sc->rdma.cm_id); smb_direct_disconnect_rdma_work(&st->disconnect_work); } @@ -1574,28 +1590,29 @@ static int smb_direct_cm_handler(struct rdma_cm_id *cm_id, struct rdma_cm_event *event) { struct smb_direct_transport *t = cm_id->context; + struct smbdirect_socket *sc = &t->socket; ksmbd_debug(RDMA, "RDMA CM event. cm_id=%p event=%s (%d)\n", cm_id, rdma_event_msg(event->event), event->event); switch (event->event) { case RDMA_CM_EVENT_ESTABLISHED: { - t->status = SMB_DIRECT_CS_CONNECTED; + sc->status = SMBDIRECT_SOCKET_CONNECTED; wake_up_interruptible(&t->wait_status); break; } case RDMA_CM_EVENT_DEVICE_REMOVAL: case RDMA_CM_EVENT_DISCONNECTED: { - ib_drain_qp(t->qp); + ib_drain_qp(sc->ib.qp); - t->status = SMB_DIRECT_CS_DISCONNECTED; + sc->status = SMBDIRECT_SOCKET_DISCONNECTED; wake_up_interruptible(&t->wait_status); wake_up_interruptible(&t->wait_reassembly_queue); wake_up(&t->wait_send_credits); break; } case RDMA_CM_EVENT_CONNECT_ERROR: { - t->status = SMB_DIRECT_CS_DISCONNECTED; + sc->status = SMBDIRECT_SOCKET_DISCONNECTED; wake_up_interruptible(&t->wait_status); break; } @@ -1611,9 +1628,10 @@ static int smb_direct_cm_handler(struct rdma_cm_id *cm_id, static void smb_direct_qpair_handler(struct ib_event *event, void *context) { struct smb_direct_transport *t = context; + struct smbdirect_socket *sc = &t->socket; ksmbd_debug(RDMA, "Received QP event. cm_id=%p, event=%s (%d)\n", - t->cm_id, ib_event_msg(event->event), event->event); + sc->rdma.cm_id, ib_event_msg(event->event), event->event); switch (event->event) { case IB_EVENT_CQ_ERR: @@ -1628,6 +1646,7 @@ static void smb_direct_qpair_handler(struct ib_event *event, void *context) static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, int failed) { + struct smbdirect_socket *sc = &t->socket; struct smb_direct_sendmsg *sendmsg; struct smbdirect_negotiate_resp *resp; int ret; @@ -1658,10 +1677,10 @@ static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, cpu_to_le32(t->max_fragmented_recv_size); } - sendmsg->sge[0].addr = ib_dma_map_single(t->cm_id->device, + sendmsg->sge[0].addr = ib_dma_map_single(sc->ib.dev, (void *)resp, sizeof(*resp), DMA_TO_DEVICE); - ret = ib_dma_mapping_error(t->cm_id->device, sendmsg->sge[0].addr); + ret = ib_dma_mapping_error(sc->ib.dev, sendmsg->sge[0].addr); if (ret) { smb_direct_free_sendmsg(t, sendmsg); return ret; @@ -1669,7 +1688,7 @@ static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, sendmsg->num_sge = 1; sendmsg->sge[0].length = sizeof(*resp); - sendmsg->sge[0].lkey = t->pd->local_dma_lkey; + sendmsg->sge[0].lkey = sc->ib.pd->local_dma_lkey; ret = post_sendmsg(t, NULL, sendmsg); if (ret) { @@ -1684,6 +1703,7 @@ static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, static int smb_direct_accept_client(struct smb_direct_transport *t) { + struct smbdirect_socket *sc = &t->socket; struct rdma_conn_param conn_param; __be32 ird_ord_hdr[2]; int ret; @@ -1710,7 +1730,7 @@ static int smb_direct_accept_client(struct smb_direct_transport *t) conn_param.rnr_retry_count = SMB_DIRECT_CM_RNR_RETRY; conn_param.flow_control = 0; - ret = rdma_accept(t->cm_id, &conn_param); + ret = rdma_accept(sc->rdma.cm_id, &conn_param); if (ret) { pr_err("error at rdma_accept: %d\n", ret); return ret; @@ -1750,15 +1770,18 @@ static int smb_direct_prepare_negotiation(struct smb_direct_transport *t) static unsigned int smb_direct_get_max_fr_pages(struct smb_direct_transport *t) { + struct smbdirect_socket *sc = &t->socket; + return min_t(unsigned int, - t->cm_id->device->attrs.max_fast_reg_page_list_len, + sc->ib.dev->attrs.max_fast_reg_page_list_len, 256); } static int smb_direct_init_params(struct smb_direct_transport *t, struct ib_qp_cap *cap) { - struct ib_device *device = t->cm_id->device; + struct smbdirect_socket *sc = &t->socket; + struct ib_device *device = sc->ib.dev; int max_send_sges, max_rw_wrs, max_send_wrs; unsigned int max_sge_per_wr, wrs_per_credit; @@ -1923,34 +1946,35 @@ static int smb_direct_create_pools(struct smb_direct_transport *t) static int smb_direct_create_qpair(struct smb_direct_transport *t, struct ib_qp_cap *cap) { + struct smbdirect_socket *sc = &t->socket; int ret; struct ib_qp_init_attr qp_attr; int pages_per_rw; - t->pd = ib_alloc_pd(t->cm_id->device, 0); - if (IS_ERR(t->pd)) { + sc->ib.pd = ib_alloc_pd(sc->ib.dev, 0); + if (IS_ERR(sc->ib.pd)) { pr_err("Can't create RDMA PD\n"); - ret = PTR_ERR(t->pd); - t->pd = NULL; + ret = PTR_ERR(sc->ib.pd); + sc->ib.pd = NULL; return ret; } - t->send_cq = ib_alloc_cq(t->cm_id->device, t, + sc->ib.send_cq = ib_alloc_cq(sc->ib.dev, t, smb_direct_send_credit_target + cap->max_rdma_ctxs, 0, IB_POLL_WORKQUEUE); - if (IS_ERR(t->send_cq)) { + if (IS_ERR(sc->ib.send_cq)) { pr_err("Can't create RDMA send CQ\n"); - ret = PTR_ERR(t->send_cq); - t->send_cq = NULL; + ret = PTR_ERR(sc->ib.send_cq); + sc->ib.send_cq = NULL; goto err; } - t->recv_cq = ib_alloc_cq(t->cm_id->device, t, + sc->ib.recv_cq = ib_alloc_cq(sc->ib.dev, t, t->recv_credit_max, 0, IB_POLL_WORKQUEUE); - if (IS_ERR(t->recv_cq)) { + if (IS_ERR(sc->ib.recv_cq)) { pr_err("Can't create RDMA recv CQ\n"); - ret = PTR_ERR(t->recv_cq); - t->recv_cq = NULL; + ret = PTR_ERR(sc->ib.recv_cq); + sc->ib.recv_cq = NULL; goto err; } @@ -1960,22 +1984,22 @@ static int smb_direct_create_qpair(struct smb_direct_transport *t, qp_attr.cap = *cap; qp_attr.sq_sig_type = IB_SIGNAL_REQ_WR; qp_attr.qp_type = IB_QPT_RC; - qp_attr.send_cq = t->send_cq; - qp_attr.recv_cq = t->recv_cq; + qp_attr.send_cq = sc->ib.send_cq; + qp_attr.recv_cq = sc->ib.recv_cq; qp_attr.port_num = ~0; - ret = rdma_create_qp(t->cm_id, t->pd, &qp_attr); + ret = rdma_create_qp(sc->rdma.cm_id, sc->ib.pd, &qp_attr); if (ret) { pr_err("Can't create RDMA QP: %d\n", ret); goto err; } - t->qp = t->cm_id->qp; - t->cm_id->event_handler = smb_direct_cm_handler; + sc->ib.qp = sc->rdma.cm_id->qp; + sc->rdma.cm_id->event_handler = smb_direct_cm_handler; pages_per_rw = DIV_ROUND_UP(t->max_rdma_rw_size, PAGE_SIZE) + 1; - if (pages_per_rw > t->cm_id->device->attrs.max_sgl_rd) { - ret = ib_mr_pool_init(t->qp, &t->qp->rdma_mrs, + if (pages_per_rw > sc->ib.dev->attrs.max_sgl_rd) { + ret = ib_mr_pool_init(sc->ib.qp, &sc->ib.qp->rdma_mrs, t->max_rw_credits, IB_MR_TYPE_MEM_REG, t->pages_per_rw_credit, 0); if (ret) { @@ -1987,21 +2011,21 @@ static int smb_direct_create_qpair(struct smb_direct_transport *t, return 0; err: - if (t->qp) { - t->qp = NULL; - rdma_destroy_qp(t->cm_id); + if (sc->ib.qp) { + sc->ib.qp = NULL; + rdma_destroy_qp(sc->rdma.cm_id); } - if (t->recv_cq) { - ib_destroy_cq(t->recv_cq); - t->recv_cq = NULL; + if (sc->ib.recv_cq) { + ib_destroy_cq(sc->ib.recv_cq); + sc->ib.recv_cq = NULL; } - if (t->send_cq) { - ib_destroy_cq(t->send_cq); - t->send_cq = NULL; + if (sc->ib.send_cq) { + ib_destroy_cq(sc->ib.send_cq); + sc->ib.send_cq = NULL; } - if (t->pd) { - ib_dealloc_pd(t->pd); - t->pd = NULL; + if (sc->ib.pd) { + ib_dealloc_pd(sc->ib.pd); + sc->ib.pd = NULL; } return ret; } @@ -2009,6 +2033,7 @@ static int smb_direct_create_qpair(struct smb_direct_transport *t, static int smb_direct_prepare(struct ksmbd_transport *t) { struct smb_direct_transport *st = smb_trans_direct_transfort(t); + struct smbdirect_socket *sc = &st->socket; struct smb_direct_recvmsg *recvmsg; struct smbdirect_negotiate_req *req; int ret; @@ -2016,9 +2041,9 @@ static int smb_direct_prepare(struct ksmbd_transport *t) ksmbd_debug(RDMA, "Waiting for SMB_DIRECT negotiate request\n"); ret = wait_event_interruptible_timeout(st->wait_status, st->negotiation_requested || - st->status == SMB_DIRECT_CS_DISCONNECTED, + sc->status == SMBDIRECT_SOCKET_DISCONNECTED, SMB_DIRECT_NEGOTIATE_TIMEOUT * HZ); - if (ret <= 0 || st->status == SMB_DIRECT_CS_DISCONNECTED) + if (ret <= 0 || sc->status == SMBDIRECT_SOCKET_DISCONNECTED) return ret < 0 ? ret : -ETIMEDOUT; recvmsg = get_first_reassembly(st); From 177368b9924314bde7d2ea6dc93de0d9ba728b61 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 6 Aug 2025 19:35:57 +0200 Subject: [PATCH 091/159] smb: server: make use of common smbdirect_socket_parameters Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: Namjae Jeon Cc: Hyunchul Lee Cc: Meetakshi Setiya Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 93 ++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 44 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index e2d8ac087344..499bb2c0bd79 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -98,12 +98,6 @@ struct smb_direct_transport { bool full_packet_received; wait_queue_head_t wait_status; - int max_send_size; - int max_recv_size; - int max_fragmented_send_size; - int max_fragmented_recv_size; - int max_rdma_rw_size; - spinlock_t reassembly_queue_lock; struct list_head reassembly_queue; int reassembly_data_length; @@ -114,13 +108,11 @@ struct smb_direct_transport { spinlock_t receive_credit_lock; int recv_credits; int count_avail_recvmsg; - int recv_credit_max; int recv_credit_target; spinlock_t recvmsg_queue_lock; struct list_head recvmsg_queue; - int send_credit_target; atomic_t send_credits; spinlock_t lock_new_recv_credits; int new_recv_credits; @@ -527,10 +519,12 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) struct smb_direct_recvmsg *recvmsg; struct smb_direct_transport *t; struct smbdirect_socket *sc; + struct smbdirect_socket_parameters *sp; recvmsg = container_of(wc->wr_cqe, struct smb_direct_recvmsg, cqe); t = recvmsg->transport; sc = &t->socket; + sp = &sc->parameters; if (wc->status != IB_WC_SUCCESS || wc->opcode != IB_WC_RECV) { put_recvmsg(t, recvmsg); @@ -585,10 +579,10 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) smb_direct_disconnect_rdma_connection(t); return; } - if (remaining_data_length > t->max_fragmented_recv_size || - data_length > t->max_fragmented_recv_size || + if (remaining_data_length > sp->max_fragmented_recv_size || + data_length > sp->max_fragmented_recv_size || (u64)remaining_data_length + (u64)data_length > - (u64)t->max_fragmented_recv_size) { + (u64)sp->max_fragmented_recv_size) { put_recvmsg(t, recvmsg); smb_direct_disconnect_rdma_connection(t); return; @@ -651,16 +645,18 @@ static int smb_direct_post_recv(struct smb_direct_transport *t, struct smb_direct_recvmsg *recvmsg) { struct smbdirect_socket *sc = &t->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; struct ib_recv_wr wr; int ret; recvmsg->sge.addr = ib_dma_map_single(sc->ib.dev, - recvmsg->packet, t->max_recv_size, + recvmsg->packet, + sp->max_recv_size, DMA_FROM_DEVICE); ret = ib_dma_mapping_error(sc->ib.dev, recvmsg->sge.addr); if (ret) return ret; - recvmsg->sge.length = t->max_recv_size; + recvmsg->sge.length = sp->max_recv_size; recvmsg->sge.lkey = sc->ib.pd->local_dma_lkey; recvmsg->cqe.done = recv_done; @@ -1025,6 +1021,7 @@ static int smb_direct_create_header(struct smb_direct_transport *t, struct smb_direct_sendmsg **sendmsg_out) { struct smbdirect_socket *sc = &t->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; struct smb_direct_sendmsg *sendmsg; struct smbdirect_data_transfer *packet; int header_length; @@ -1036,7 +1033,7 @@ static int smb_direct_create_header(struct smb_direct_transport *t, /* Fill in the packet header */ packet = (struct smbdirect_data_transfer *)sendmsg->packet; - packet->credits_requested = cpu_to_le16(t->send_credit_target); + packet->credits_requested = cpu_to_le16(sp->send_credit_target); packet->credits_granted = cpu_to_le16(manage_credits_prior_sending(t)); packet->flags = 0; @@ -1237,10 +1234,11 @@ static int smb_direct_writev(struct ksmbd_transport *t, { struct smb_direct_transport *st = smb_trans_direct_transfort(t); struct smbdirect_socket *sc = &st->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; size_t remaining_data_length; size_t iov_idx; size_t iov_ofs; - size_t max_iov_size = st->max_send_size - + size_t max_iov_size = sp->max_send_size - sizeof(struct smbdirect_data_transfer); int ret; struct smb_direct_send_ctx send_ctx; @@ -1421,6 +1419,7 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, bool is_read) { struct smbdirect_socket *sc = &t->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; struct smb_direct_rdma_rw_msg *msg, *next_msg; int i, ret; DECLARE_COMPLETION_ONSTACK(completion); @@ -1433,7 +1432,7 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, if (sc->status != SMBDIRECT_SOCKET_CONNECTED) return -ENOTCONN; - if (buf_len > t->max_rdma_rw_size) + if (buf_len > sp->max_read_write_size) return -EINVAL; /* calculate needed credits */ @@ -1647,6 +1646,7 @@ static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, int failed) { struct smbdirect_socket *sc = &t->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; struct smb_direct_sendmsg *sendmsg; struct smbdirect_negotiate_resp *resp; int ret; @@ -1668,13 +1668,13 @@ static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, resp->negotiated_version = SMB_DIRECT_VERSION_LE; resp->reserved = 0; resp->credits_requested = - cpu_to_le16(t->send_credit_target); + cpu_to_le16(sp->send_credit_target); resp->credits_granted = cpu_to_le16(manage_credits_prior_sending(t)); - resp->max_readwrite_size = cpu_to_le32(t->max_rdma_rw_size); - resp->preferred_send_size = cpu_to_le32(t->max_send_size); - resp->max_receive_size = cpu_to_le32(t->max_recv_size); + resp->max_readwrite_size = cpu_to_le32(sp->max_read_write_size); + resp->preferred_send_size = cpu_to_le32(sp->max_send_size); + resp->max_receive_size = cpu_to_le32(sp->max_recv_size); resp->max_fragmented_size = - cpu_to_le32(t->max_fragmented_recv_size); + cpu_to_le32(sp->max_fragmented_recv_size); } sendmsg->sge[0].addr = ib_dma_map_single(sc->ib.dev, @@ -1781,6 +1781,7 @@ static int smb_direct_init_params(struct smb_direct_transport *t, struct ib_qp_cap *cap) { struct smbdirect_socket *sc = &t->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; struct ib_device *device = sc->ib.dev; int max_send_sges, max_rw_wrs, max_send_wrs; unsigned int max_sge_per_wr, wrs_per_credit; @@ -1788,10 +1789,10 @@ static int smb_direct_init_params(struct smb_direct_transport *t, /* need 3 more sge. because a SMB_DIRECT header, SMB2 header, * SMB2 response could be mapped. */ - t->max_send_size = smb_direct_max_send_size; - max_send_sges = DIV_ROUND_UP(t->max_send_size, PAGE_SIZE) + 3; + sp->max_send_size = smb_direct_max_send_size; + max_send_sges = DIV_ROUND_UP(sp->max_send_size, PAGE_SIZE) + 3; if (max_send_sges > SMB_DIRECT_MAX_SEND_SGES) { - pr_err("max_send_size %d is too large\n", t->max_send_size); + pr_err("max_send_size %d is too large\n", sp->max_send_size); return -EINVAL; } @@ -1802,9 +1803,9 @@ static int smb_direct_init_params(struct smb_direct_transport *t, * are needed for MR registration, RDMA R/W, local & remote * MR invalidation. */ - t->max_rdma_rw_size = smb_direct_max_read_write_size; + sp->max_read_write_size = smb_direct_max_read_write_size; t->pages_per_rw_credit = smb_direct_get_max_fr_pages(t); - t->max_rw_credits = DIV_ROUND_UP(t->max_rdma_rw_size, + t->max_rw_credits = DIV_ROUND_UP(sp->max_read_write_size, (t->pages_per_rw_credit - 1) * PAGE_SIZE); @@ -1850,20 +1851,20 @@ static int smb_direct_init_params(struct smb_direct_transport *t, t->recv_credits = 0; t->count_avail_recvmsg = 0; - t->recv_credit_max = smb_direct_receive_credit_max; + sp->recv_credit_max = smb_direct_receive_credit_max; t->recv_credit_target = 10; t->new_recv_credits = 0; - t->send_credit_target = smb_direct_send_credit_target; + sp->send_credit_target = smb_direct_send_credit_target; atomic_set(&t->send_credits, 0); atomic_set(&t->rw_credits, t->max_rw_credits); - t->max_send_size = smb_direct_max_send_size; - t->max_recv_size = smb_direct_max_receive_size; - t->max_fragmented_recv_size = smb_direct_max_fragmented_recv_size; + sp->max_send_size = smb_direct_max_send_size; + sp->max_recv_size = smb_direct_max_receive_size; + sp->max_fragmented_recv_size = smb_direct_max_fragmented_recv_size; cap->max_send_wr = max_send_wrs; - cap->max_recv_wr = t->recv_credit_max; + cap->max_recv_wr = sp->recv_credit_max; cap->max_send_sge = SMB_DIRECT_MAX_SEND_SGES; cap->max_recv_sge = SMB_DIRECT_MAX_RECV_SGES; cap->max_inline_data = 0; @@ -1893,6 +1894,8 @@ static void smb_direct_destroy_pools(struct smb_direct_transport *t) static int smb_direct_create_pools(struct smb_direct_transport *t) { + struct smbdirect_socket *sc = &t->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; char name[80]; int i; struct smb_direct_recvmsg *recvmsg; @@ -1905,7 +1908,7 @@ static int smb_direct_create_pools(struct smb_direct_transport *t) if (!t->sendmsg_cache) return -ENOMEM; - t->sendmsg_mempool = mempool_create(t->send_credit_target, + t->sendmsg_mempool = mempool_create(sp->send_credit_target, mempool_alloc_slab, mempool_free_slab, t->sendmsg_cache); if (!t->sendmsg_mempool) @@ -1914,20 +1917,20 @@ static int smb_direct_create_pools(struct smb_direct_transport *t) snprintf(name, sizeof(name), "smb_direct_resp_%p", t); t->recvmsg_cache = kmem_cache_create(name, sizeof(struct smb_direct_recvmsg) + - t->max_recv_size, + sp->max_recv_size, 0, SLAB_HWCACHE_ALIGN, NULL); if (!t->recvmsg_cache) goto err; t->recvmsg_mempool = - mempool_create(t->recv_credit_max, mempool_alloc_slab, + mempool_create(sp->recv_credit_max, mempool_alloc_slab, mempool_free_slab, t->recvmsg_cache); if (!t->recvmsg_mempool) goto err; INIT_LIST_HEAD(&t->recvmsg_queue); - for (i = 0; i < t->recv_credit_max; i++) { + for (i = 0; i < sp->recv_credit_max; i++) { recvmsg = mempool_alloc(t->recvmsg_mempool, KSMBD_DEFAULT_GFP); if (!recvmsg) goto err; @@ -1935,7 +1938,7 @@ static int smb_direct_create_pools(struct smb_direct_transport *t) recvmsg->sge.length = 0; list_add(&recvmsg->list, &t->recvmsg_queue); } - t->count_avail_recvmsg = t->recv_credit_max; + t->count_avail_recvmsg = sp->recv_credit_max; return 0; err: @@ -1947,6 +1950,7 @@ static int smb_direct_create_qpair(struct smb_direct_transport *t, struct ib_qp_cap *cap) { struct smbdirect_socket *sc = &t->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; int ret; struct ib_qp_init_attr qp_attr; int pages_per_rw; @@ -1970,7 +1974,7 @@ static int smb_direct_create_qpair(struct smb_direct_transport *t, } sc->ib.recv_cq = ib_alloc_cq(sc->ib.dev, t, - t->recv_credit_max, 0, IB_POLL_WORKQUEUE); + sp->recv_credit_max, 0, IB_POLL_WORKQUEUE); if (IS_ERR(sc->ib.recv_cq)) { pr_err("Can't create RDMA recv CQ\n"); ret = PTR_ERR(sc->ib.recv_cq); @@ -1997,7 +2001,7 @@ static int smb_direct_create_qpair(struct smb_direct_transport *t, sc->ib.qp = sc->rdma.cm_id->qp; sc->rdma.cm_id->event_handler = smb_direct_cm_handler; - pages_per_rw = DIV_ROUND_UP(t->max_rdma_rw_size, PAGE_SIZE) + 1; + pages_per_rw = DIV_ROUND_UP(sp->max_read_write_size, PAGE_SIZE) + 1; if (pages_per_rw > sc->ib.dev->attrs.max_sgl_rd) { ret = ib_mr_pool_init(sc->ib.qp, &sc->ib.qp->rdma_mrs, t->max_rw_credits, IB_MR_TYPE_MEM_REG, @@ -2034,6 +2038,7 @@ static int smb_direct_prepare(struct ksmbd_transport *t) { struct smb_direct_transport *st = smb_trans_direct_transfort(t); struct smbdirect_socket *sc = &st->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; struct smb_direct_recvmsg *recvmsg; struct smbdirect_negotiate_req *req; int ret; @@ -2055,14 +2060,14 @@ static int smb_direct_prepare(struct ksmbd_transport *t) goto out; req = (struct smbdirect_negotiate_req *)recvmsg->packet; - st->max_recv_size = min_t(int, st->max_recv_size, + sp->max_recv_size = min_t(int, sp->max_recv_size, le32_to_cpu(req->preferred_send_size)); - st->max_send_size = min_t(int, st->max_send_size, + sp->max_send_size = min_t(int, sp->max_send_size, le32_to_cpu(req->max_receive_size)); - st->max_fragmented_send_size = + sp->max_fragmented_send_size = le32_to_cpu(req->max_fragmented_size); - st->max_fragmented_recv_size = - (st->recv_credit_max * st->max_recv_size) / 2; + sp->max_fragmented_recv_size = + (sp->recv_credit_max * sp->max_recv_size) / 2; ret = smb_direct_send_negotiate_response(st, ret); out: From 3e691b1d16dbd30186d71ca707efeb3a98cc542c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 6 Aug 2025 19:35:58 +0200 Subject: [PATCH 092/159] smb: server: make use of smbdirect_socket->recv_io.expected The expected incoming message type can be per connection. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 44 +++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 499bb2c0bd79..7892dd634c82 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -145,10 +145,6 @@ struct smb_direct_transport { #define KSMBD_TRANS(t) ((struct ksmbd_transport *)&((t)->transport)) #define SMBD_TRANS(t) ((struct smb_direct_transport *)container_of(t, \ struct smb_direct_transport, transport)) -enum { - SMB_DIRECT_MSG_NEGOTIATE_REQ = 0, - SMB_DIRECT_MSG_DATA_TRANSFER -}; static const struct ksmbd_transport_ops ksmbd_smb_direct_transport_ops; @@ -172,7 +168,6 @@ struct smb_direct_sendmsg { struct smb_direct_recvmsg { struct smb_direct_transport *transport; struct list_head list; - int type; struct ib_sge sge; struct ib_cqe cqe; bool first_segment; @@ -472,8 +467,10 @@ static void smb_direct_free_sendmsg(struct smb_direct_transport *t, static int smb_direct_check_recvmsg(struct smb_direct_recvmsg *recvmsg) { - switch (recvmsg->type) { - case SMB_DIRECT_MSG_DATA_TRANSFER: { + struct smbdirect_socket *sc = &recvmsg->transport->socket; + + switch (sc->recv_io.expected) { + case SMBDIRECT_EXPECT_DATA_TRANSFER: { struct smbdirect_data_transfer *req = (struct smbdirect_data_transfer *)recvmsg->packet; struct smb2_hdr *hdr = (struct smb2_hdr *)(recvmsg->packet @@ -484,9 +481,9 @@ static int smb_direct_check_recvmsg(struct smb_direct_recvmsg *recvmsg) le16_to_cpu(req->credits_requested), req->data_length, req->remaining_data_length, hdr->ProtocolId, hdr->Command); - break; + return 0; } - case SMB_DIRECT_MSG_NEGOTIATE_REQ: { + case SMBDIRECT_EXPECT_NEGOTIATE_REQ: { struct smbdirect_negotiate_req *req = (struct smbdirect_negotiate_req *)recvmsg->packet; ksmbd_debug(RDMA, @@ -506,12 +503,15 @@ static int smb_direct_check_recvmsg(struct smb_direct_recvmsg *recvmsg) 128 * 1024) return -ECONNABORTED; + return 0; + } + case SMBDIRECT_EXPECT_NEGOTIATE_REP: + /* client only */ break; } - default: - return -EINVAL; - } - return 0; + + /* This is an internal error */ + return -EINVAL; } static void recv_done(struct ib_cq *cq, struct ib_wc *wc) @@ -544,8 +544,8 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) ib_dma_sync_single_for_cpu(wc->qp->device, recvmsg->sge.addr, recvmsg->sge.length, DMA_FROM_DEVICE); - switch (recvmsg->type) { - case SMB_DIRECT_MSG_NEGOTIATE_REQ: + switch (sc->recv_io.expected) { + case SMBDIRECT_EXPECT_NEGOTIATE_REQ: if (wc->byte_len < sizeof(struct smbdirect_negotiate_req)) { put_recvmsg(t, recvmsg); smb_direct_disconnect_rdma_connection(t); @@ -557,7 +557,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) enqueue_reassembly(t, recvmsg, 0); wake_up_interruptible(&t->wait_status); return; - case SMB_DIRECT_MSG_DATA_TRANSFER: { + case SMBDIRECT_EXPECT_DATA_TRANSFER: { struct smbdirect_data_transfer *data_transfer = (struct smbdirect_data_transfer *)recvmsg->packet; u32 remaining_data_length, data_offset, data_length; @@ -631,12 +631,15 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) return; } + case SMBDIRECT_EXPECT_NEGOTIATE_REP: + /* client only */ + break; } /* * This is an internal error! */ - WARN_ON_ONCE(recvmsg->type != SMB_DIRECT_MSG_DATA_TRANSFER); + WARN_ON_ONCE(sc->recv_io.expected != SMBDIRECT_EXPECT_DATA_TRANSFER); put_recvmsg(t, recvmsg); smb_direct_disconnect_rdma_connection(t); } @@ -824,7 +827,6 @@ static void smb_direct_post_recv_credits(struct work_struct *work) if (!recvmsg) break; - recvmsg->type = SMB_DIRECT_MSG_DATA_TRANSFER; recvmsg->first_segment = false; ret = smb_direct_post_recv(t, recvmsg); @@ -1675,6 +1677,8 @@ static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, resp->max_receive_size = cpu_to_le32(sp->max_recv_size); resp->max_fragmented_size = cpu_to_le32(sp->max_fragmented_recv_size); + + sc->recv_io.expected = SMBDIRECT_EXPECT_DATA_TRANSFER; } sendmsg->sge[0].addr = ib_dma_map_single(sc->ib.dev, @@ -1740,13 +1744,15 @@ static int smb_direct_accept_client(struct smb_direct_transport *t) static int smb_direct_prepare_negotiation(struct smb_direct_transport *t) { + struct smbdirect_socket *sc = &t->socket; int ret; struct smb_direct_recvmsg *recvmsg; + sc->recv_io.expected = SMBDIRECT_EXPECT_NEGOTIATE_REQ; + recvmsg = get_free_recvmsg(t); if (!recvmsg) return -ENOMEM; - recvmsg->type = SMB_DIRECT_MSG_NEGOTIATE_REQ; ret = smb_direct_post_recv(t, recvmsg); if (ret) { From 9883a142f1bba5bdc3a3091608aef8b1600cdd11 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 6 Aug 2025 19:35:59 +0200 Subject: [PATCH 093/159] smb: server: make use of struct smbdirect_recv_io This will allow us to move helper functions into common code soon as the client already uses smbdirect_recv_io. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 61 +++++++++++++++------------------- 1 file changed, 26 insertions(+), 35 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 7892dd634c82..c4e786f2e7e7 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -165,15 +165,6 @@ struct smb_direct_sendmsg { u8 packet[]; }; -struct smb_direct_recvmsg { - struct smb_direct_transport *transport; - struct list_head list; - struct ib_sge sge; - struct ib_cqe cqe; - bool first_segment; - u8 packet[]; -}; - struct smb_direct_rdma_rw_msg { struct smb_direct_transport *t; struct ib_cqe cqe; @@ -216,7 +207,7 @@ smb_trans_direct_transfort(struct ksmbd_transport *t) } static inline void -*smb_direct_recvmsg_payload(struct smb_direct_recvmsg *recvmsg) +*smbdirect_recv_io_payload(struct smbdirect_recv_io *recvmsg) { return (void *)recvmsg->packet; } @@ -229,14 +220,14 @@ static inline bool is_receive_credit_post_required(int receive_credits, } static struct -smb_direct_recvmsg *get_free_recvmsg(struct smb_direct_transport *t) +smbdirect_recv_io *get_free_recvmsg(struct smb_direct_transport *t) { - struct smb_direct_recvmsg *recvmsg = NULL; + struct smbdirect_recv_io *recvmsg = NULL; spin_lock(&t->recvmsg_queue_lock); if (!list_empty(&t->recvmsg_queue)) { recvmsg = list_first_entry(&t->recvmsg_queue, - struct smb_direct_recvmsg, + struct smbdirect_recv_io, list); list_del(&recvmsg->list); } @@ -245,7 +236,7 @@ smb_direct_recvmsg *get_free_recvmsg(struct smb_direct_transport *t) } static void put_recvmsg(struct smb_direct_transport *t, - struct smb_direct_recvmsg *recvmsg) + struct smbdirect_recv_io *recvmsg) { struct smbdirect_socket *sc = &t->socket; @@ -263,7 +254,7 @@ static void put_recvmsg(struct smb_direct_transport *t, } static void enqueue_reassembly(struct smb_direct_transport *t, - struct smb_direct_recvmsg *recvmsg, + struct smbdirect_recv_io *recvmsg, int data_length) { spin_lock(&t->reassembly_queue_lock); @@ -280,11 +271,11 @@ static void enqueue_reassembly(struct smb_direct_transport *t, spin_unlock(&t->reassembly_queue_lock); } -static struct smb_direct_recvmsg *get_first_reassembly(struct smb_direct_transport *t) +static struct smbdirect_recv_io *get_first_reassembly(struct smb_direct_transport *t) { if (!list_empty(&t->reassembly_queue)) return list_first_entry(&t->reassembly_queue, - struct smb_direct_recvmsg, list); + struct smbdirect_recv_io, list); else return NULL; } @@ -387,7 +378,7 @@ static void smb_direct_free_transport(struct ksmbd_transport *kt) static void free_transport(struct smb_direct_transport *t) { struct smbdirect_socket *sc = &t->socket; - struct smb_direct_recvmsg *recvmsg; + struct smbdirect_recv_io *recvmsg; wake_up_interruptible(&t->wait_send_credits); @@ -465,9 +456,9 @@ static void smb_direct_free_sendmsg(struct smb_direct_transport *t, mempool_free(msg, t->sendmsg_mempool); } -static int smb_direct_check_recvmsg(struct smb_direct_recvmsg *recvmsg) +static int smb_direct_check_recvmsg(struct smbdirect_recv_io *recvmsg) { - struct smbdirect_socket *sc = &recvmsg->transport->socket; + struct smbdirect_socket *sc = recvmsg->socket; switch (sc->recv_io.expected) { case SMBDIRECT_EXPECT_DATA_TRANSFER: { @@ -516,15 +507,15 @@ static int smb_direct_check_recvmsg(struct smb_direct_recvmsg *recvmsg) static void recv_done(struct ib_cq *cq, struct ib_wc *wc) { - struct smb_direct_recvmsg *recvmsg; + struct smbdirect_recv_io *recvmsg; struct smb_direct_transport *t; struct smbdirect_socket *sc; struct smbdirect_socket_parameters *sp; - recvmsg = container_of(wc->wr_cqe, struct smb_direct_recvmsg, cqe); - t = recvmsg->transport; - sc = &t->socket; + recvmsg = container_of(wc->wr_cqe, struct smbdirect_recv_io, cqe); + sc = recvmsg->socket; sp = &sc->parameters; + t = container_of(sc, struct smb_direct_transport, socket); if (wc->status != IB_WC_SUCCESS || wc->opcode != IB_WC_RECV) { put_recvmsg(t, recvmsg); @@ -645,7 +636,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) } static int smb_direct_post_recv(struct smb_direct_transport *t, - struct smb_direct_recvmsg *recvmsg) + struct smbdirect_recv_io *recvmsg) { struct smbdirect_socket *sc = &t->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; @@ -684,7 +675,7 @@ static int smb_direct_post_recv(struct smb_direct_transport *t, static int smb_direct_read(struct ksmbd_transport *t, char *buf, unsigned int size, int unused) { - struct smb_direct_recvmsg *recvmsg; + struct smbdirect_recv_io *recvmsg; struct smbdirect_data_transfer *data_transfer; int to_copy, to_read, data_read, offset; u32 data_length, remaining_data_length, data_offset; @@ -721,7 +712,7 @@ static int smb_direct_read(struct ksmbd_transport *t, char *buf, offset = st->first_entry_offset; while (data_read < size) { recvmsg = get_first_reassembly(st); - data_transfer = smb_direct_recvmsg_payload(recvmsg); + data_transfer = smbdirect_recv_io_payload(recvmsg); data_length = le32_to_cpu(data_transfer->data_length); remaining_data_length = le32_to_cpu(data_transfer->remaining_data_length); @@ -813,7 +804,7 @@ static void smb_direct_post_recv_credits(struct work_struct *work) { struct smb_direct_transport *t = container_of(work, struct smb_direct_transport, post_recv_credits_work); - struct smb_direct_recvmsg *recvmsg; + struct smbdirect_recv_io *recvmsg; int receive_credits, credits = 0; int ret; @@ -1746,7 +1737,7 @@ static int smb_direct_prepare_negotiation(struct smb_direct_transport *t) { struct smbdirect_socket *sc = &t->socket; int ret; - struct smb_direct_recvmsg *recvmsg; + struct smbdirect_recv_io *recvmsg; sc->recv_io.expected = SMBDIRECT_EXPECT_NEGOTIATE_REQ; @@ -1880,7 +1871,7 @@ static int smb_direct_init_params(struct smb_direct_transport *t, static void smb_direct_destroy_pools(struct smb_direct_transport *t) { - struct smb_direct_recvmsg *recvmsg; + struct smbdirect_recv_io *recvmsg; while ((recvmsg = get_free_recvmsg(t))) mempool_free(recvmsg, t->recvmsg_mempool); @@ -1904,7 +1895,7 @@ static int smb_direct_create_pools(struct smb_direct_transport *t) struct smbdirect_socket_parameters *sp = &sc->parameters; char name[80]; int i; - struct smb_direct_recvmsg *recvmsg; + struct smbdirect_recv_io *recvmsg; snprintf(name, sizeof(name), "smb_direct_rqst_pool_%p", t); t->sendmsg_cache = kmem_cache_create(name, @@ -1920,9 +1911,9 @@ static int smb_direct_create_pools(struct smb_direct_transport *t) if (!t->sendmsg_mempool) goto err; - snprintf(name, sizeof(name), "smb_direct_resp_%p", t); + snprintf(name, sizeof(name), "smbdirect_recv_io_pool_%p", t); t->recvmsg_cache = kmem_cache_create(name, - sizeof(struct smb_direct_recvmsg) + + sizeof(struct smbdirect_recv_io) + sp->max_recv_size, 0, SLAB_HWCACHE_ALIGN, NULL); if (!t->recvmsg_cache) @@ -1940,7 +1931,7 @@ static int smb_direct_create_pools(struct smb_direct_transport *t) recvmsg = mempool_alloc(t->recvmsg_mempool, KSMBD_DEFAULT_GFP); if (!recvmsg) goto err; - recvmsg->transport = t; + recvmsg->socket = sc; recvmsg->sge.length = 0; list_add(&recvmsg->list, &t->recvmsg_queue); } @@ -2045,7 +2036,7 @@ static int smb_direct_prepare(struct ksmbd_transport *t) struct smb_direct_transport *st = smb_trans_direct_transfort(t); struct smbdirect_socket *sc = &st->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; - struct smb_direct_recvmsg *recvmsg; + struct smbdirect_recv_io *recvmsg; struct smbdirect_negotiate_req *req; int ret; From d9989207b78c2fa3008285c8b1e53e8618544de7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 6 Aug 2025 19:36:00 +0200 Subject: [PATCH 094/159] smb: server: make use of smbdirect_socket.recv_io.free.{list,lock} This is already used by the client and will allow us to add common helper functions soon. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index c4e786f2e7e7..8eec651e2f9e 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -110,9 +110,6 @@ struct smb_direct_transport { int count_avail_recvmsg; int recv_credit_target; - spinlock_t recvmsg_queue_lock; - struct list_head recvmsg_queue; - atomic_t send_credits; spinlock_t lock_new_recv_credits; int new_recv_credits; @@ -222,16 +219,17 @@ static inline bool is_receive_credit_post_required(int receive_credits, static struct smbdirect_recv_io *get_free_recvmsg(struct smb_direct_transport *t) { + struct smbdirect_socket *sc = &t->socket; struct smbdirect_recv_io *recvmsg = NULL; - spin_lock(&t->recvmsg_queue_lock); - if (!list_empty(&t->recvmsg_queue)) { - recvmsg = list_first_entry(&t->recvmsg_queue, + spin_lock(&sc->recv_io.free.lock); + if (!list_empty(&sc->recv_io.free.list)) { + recvmsg = list_first_entry(&sc->recv_io.free.list, struct smbdirect_recv_io, list); list_del(&recvmsg->list); } - spin_unlock(&t->recvmsg_queue_lock); + spin_unlock(&sc->recv_io.free.lock); return recvmsg; } @@ -248,9 +246,9 @@ static void put_recvmsg(struct smb_direct_transport *t, recvmsg->sge.length = 0; } - spin_lock(&t->recvmsg_queue_lock); - list_add(&recvmsg->list, &t->recvmsg_queue); - spin_unlock(&t->recvmsg_queue_lock); + spin_lock(&sc->recv_io.free.lock); + list_add(&recvmsg->list, &sc->recv_io.free.list); + spin_unlock(&sc->recv_io.free.lock); } static void enqueue_reassembly(struct smb_direct_transport *t, @@ -333,6 +331,9 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) sc->ib.dev = sc->rdma.cm_id->device; + INIT_LIST_HEAD(&sc->recv_io.free.list); + spin_lock_init(&sc->recv_io.free.lock); + sc->status = SMBDIRECT_SOCKET_CREATED; init_waitqueue_head(&t->wait_status); @@ -345,8 +346,6 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) init_waitqueue_head(&t->wait_rw_credits); spin_lock_init(&t->receive_credit_lock); - spin_lock_init(&t->recvmsg_queue_lock); - INIT_LIST_HEAD(&t->recvmsg_queue); init_waitqueue_head(&t->wait_send_pending); atomic_set(&t->send_pending, 0); @@ -1925,15 +1924,13 @@ static int smb_direct_create_pools(struct smb_direct_transport *t) if (!t->recvmsg_mempool) goto err; - INIT_LIST_HEAD(&t->recvmsg_queue); - for (i = 0; i < sp->recv_credit_max; i++) { recvmsg = mempool_alloc(t->recvmsg_mempool, KSMBD_DEFAULT_GFP); if (!recvmsg) goto err; recvmsg->socket = sc; recvmsg->sge.length = 0; - list_add(&recvmsg->list, &t->recvmsg_queue); + list_add(&recvmsg->list, &sc->recv_io.free.list); } t->count_avail_recvmsg = sp->recv_credit_max; From bdb0f1596ae537535a0cebc2911b07ff264c3099 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 6 Aug 2025 19:36:01 +0200 Subject: [PATCH 095/159] smb: server: make use of smbdirect_socket.recv_io.reassembly.* This is also used by the client and will allow us to introduce common helper functions soon. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 90 ++++++++++++++++------------------ 1 file changed, 43 insertions(+), 47 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 8eec651e2f9e..7853b3b4d8da 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -95,16 +95,8 @@ struct smb_direct_transport { struct smbdirect_socket socket; - bool full_packet_received; wait_queue_head_t wait_status; - spinlock_t reassembly_queue_lock; - struct list_head reassembly_queue; - int reassembly_data_length; - int reassembly_queue_length; - int first_entry_offset; - wait_queue_head_t wait_reassembly_queue; - spinlock_t receive_credit_lock; int recv_credits; int count_avail_recvmsg; @@ -255,9 +247,11 @@ static void enqueue_reassembly(struct smb_direct_transport *t, struct smbdirect_recv_io *recvmsg, int data_length) { - spin_lock(&t->reassembly_queue_lock); - list_add_tail(&recvmsg->list, &t->reassembly_queue); - t->reassembly_queue_length++; + struct smbdirect_socket *sc = &t->socket; + + spin_lock(&sc->recv_io.reassembly.lock); + list_add_tail(&recvmsg->list, &sc->recv_io.reassembly.list); + sc->recv_io.reassembly.queue_length++; /* * Make sure reassembly_data_length is updated after list and * reassembly_queue_length are updated. On the dequeue side @@ -265,14 +259,16 @@ static void enqueue_reassembly(struct smb_direct_transport *t, * if reassembly_queue_length and list is up to date */ virt_wmb(); - t->reassembly_data_length += data_length; - spin_unlock(&t->reassembly_queue_lock); + sc->recv_io.reassembly.data_length += data_length; + spin_unlock(&sc->recv_io.reassembly.lock); } static struct smbdirect_recv_io *get_first_reassembly(struct smb_direct_transport *t) { - if (!list_empty(&t->reassembly_queue)) - return list_first_entry(&t->reassembly_queue, + struct smbdirect_socket *sc = &t->socket; + + if (!list_empty(&sc->recv_io.reassembly.list)) + return list_first_entry(&sc->recv_io.reassembly.list, struct smbdirect_recv_io, list); else return NULL; @@ -337,11 +333,11 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) sc->status = SMBDIRECT_SOCKET_CREATED; init_waitqueue_head(&t->wait_status); - spin_lock_init(&t->reassembly_queue_lock); - INIT_LIST_HEAD(&t->reassembly_queue); - t->reassembly_data_length = 0; - t->reassembly_queue_length = 0; - init_waitqueue_head(&t->wait_reassembly_queue); + spin_lock_init(&sc->recv_io.reassembly.lock); + INIT_LIST_HEAD(&sc->recv_io.reassembly.list); + sc->recv_io.reassembly.data_length = 0; + sc->recv_io.reassembly.queue_length = 0; + init_waitqueue_head(&sc->recv_io.reassembly.wait_queue); init_waitqueue_head(&t->wait_send_credits); init_waitqueue_head(&t->wait_rw_credits); @@ -398,17 +394,17 @@ static void free_transport(struct smb_direct_transport *t) ksmbd_debug(RDMA, "drain the reassembly queue\n"); do { - spin_lock(&t->reassembly_queue_lock); + spin_lock(&sc->recv_io.reassembly.lock); recvmsg = get_first_reassembly(t); if (recvmsg) { list_del(&recvmsg->list); - spin_unlock(&t->reassembly_queue_lock); + spin_unlock(&sc->recv_io.reassembly.lock); put_recvmsg(t, recvmsg); } else { - spin_unlock(&t->reassembly_queue_lock); + spin_unlock(&sc->recv_io.reassembly.lock); } } while (recvmsg); - t->reassembly_data_length = 0; + sc->recv_io.reassembly.data_length = 0; if (sc->ib.send_cq) ib_free_cq(sc->ib.send_cq); @@ -542,7 +538,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) return; } t->negotiation_requested = true; - t->full_packet_received = true; + sc->recv_io.reassembly.full_packet_received = true; sc->status = SMBDIRECT_SOCKET_CONNECTED; enqueue_reassembly(t, recvmsg, 0); wake_up_interruptible(&t->wait_status); @@ -579,13 +575,13 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) } if (data_length) { - if (t->full_packet_received) + if (sc->recv_io.reassembly.full_packet_received) recvmsg->first_segment = true; if (le32_to_cpu(data_transfer->remaining_data_length)) - t->full_packet_received = false; + sc->recv_io.reassembly.full_packet_received = false; else - t->full_packet_received = true; + sc->recv_io.reassembly.full_packet_received = true; spin_lock(&t->receive_credit_lock); receive_credits = --(t->recv_credits); @@ -615,7 +611,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) if (data_length) { enqueue_reassembly(t, recvmsg, (int)data_length); - wake_up_interruptible(&t->wait_reassembly_queue); + wake_up_interruptible(&sc->recv_io.reassembly.wait_queue); } else put_recvmsg(t, recvmsg); @@ -693,7 +689,7 @@ static int smb_direct_read(struct ksmbd_transport *t, char *buf, * the only one reading from the front of the queue. The transport * may add more entries to the back of the queue at the same time */ - if (st->reassembly_data_length >= size) { + if (sc->recv_io.reassembly.data_length >= size) { int queue_length; int queue_removed = 0; @@ -705,10 +701,10 @@ static int smb_direct_read(struct ksmbd_transport *t, char *buf, * updated in SOFTIRQ as more data is received */ virt_rmb(); - queue_length = st->reassembly_queue_length; + queue_length = sc->recv_io.reassembly.queue_length; data_read = 0; to_read = size; - offset = st->first_entry_offset; + offset = sc->recv_io.reassembly.first_entry_offset; while (data_read < size) { recvmsg = get_first_reassembly(st); data_transfer = smbdirect_recv_io_payload(recvmsg); @@ -751,9 +747,9 @@ static int smb_direct_read(struct ksmbd_transport *t, char *buf, if (queue_length) { list_del(&recvmsg->list); } else { - spin_lock_irq(&st->reassembly_queue_lock); + spin_lock_irq(&sc->recv_io.reassembly.lock); list_del(&recvmsg->list); - spin_unlock_irq(&st->reassembly_queue_lock); + spin_unlock_irq(&sc->recv_io.reassembly.lock); } queue_removed++; put_recvmsg(st, recvmsg); @@ -766,10 +762,10 @@ static int smb_direct_read(struct ksmbd_transport *t, char *buf, data_read += to_copy; } - spin_lock_irq(&st->reassembly_queue_lock); - st->reassembly_data_length -= data_read; - st->reassembly_queue_length -= queue_removed; - spin_unlock_irq(&st->reassembly_queue_lock); + spin_lock_irq(&sc->recv_io.reassembly.lock); + sc->recv_io.reassembly.data_length -= data_read; + sc->recv_io.reassembly.queue_length -= queue_removed; + spin_unlock_irq(&sc->recv_io.reassembly.lock); spin_lock(&st->receive_credit_lock); st->count_avail_recvmsg += queue_removed; @@ -780,18 +776,18 @@ static int smb_direct_read(struct ksmbd_transport *t, char *buf, spin_unlock(&st->receive_credit_lock); } - st->first_entry_offset = offset; + sc->recv_io.reassembly.first_entry_offset = offset; ksmbd_debug(RDMA, "returning to thread data_read=%d reassembly_data_length=%d first_entry_offset=%d\n", - data_read, st->reassembly_data_length, - st->first_entry_offset); + data_read, sc->recv_io.reassembly.data_length, + sc->recv_io.reassembly.first_entry_offset); read_rfc1002_done: return data_read; } ksmbd_debug(RDMA, "wait_event on more data\n"); - rc = wait_event_interruptible(st->wait_reassembly_queue, - st->reassembly_data_length >= size || + rc = wait_event_interruptible(sc->recv_io.reassembly.wait_queue, + sc->recv_io.reassembly.data_length >= size || sc->status != SMBDIRECT_SOCKET_CONNECTED); if (rc) return -EINTR; @@ -1598,7 +1594,7 @@ static int smb_direct_cm_handler(struct rdma_cm_id *cm_id, sc->status = SMBDIRECT_SOCKET_DISCONNECTED; wake_up_interruptible(&t->wait_status); - wake_up_interruptible(&t->wait_reassembly_queue); + wake_up_interruptible(&sc->recv_io.reassembly.wait_queue); wake_up(&t->wait_send_credits); break; } @@ -2065,10 +2061,10 @@ static int smb_direct_prepare(struct ksmbd_transport *t) ret = smb_direct_send_negotiate_response(st, ret); out: - spin_lock_irq(&st->reassembly_queue_lock); - st->reassembly_queue_length--; + spin_lock_irq(&sc->recv_io.reassembly.lock); + sc->recv_io.reassembly.queue_length--; list_del(&recvmsg->list); - spin_unlock_irq(&st->reassembly_queue_lock); + spin_unlock_irq(&sc->recv_io.reassembly.lock); put_recvmsg(st, recvmsg); return ret; From ea20d02842c8f38ed36045b46d8e95bcfa0514f2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 6 Aug 2025 19:36:02 +0200 Subject: [PATCH 096/159] smb: server: make use of SMBDIRECT_RECV_IO_MAX_SGE Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 7853b3b4d8da..b027382c554e 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -37,7 +37,6 @@ #define SMB_DIRECT_NEGOTIATE_TIMEOUT 120 #define SMB_DIRECT_MAX_SEND_SGES 6 -#define SMB_DIRECT_MAX_RECV_SGES 1 /* * Default maximum number of RDMA read/write outstanding on this connection @@ -1834,7 +1833,7 @@ static int smb_direct_init_params(struct smb_direct_transport *t, device->attrs.max_send_sge); return -EINVAL; } - if (device->attrs.max_recv_sge < SMB_DIRECT_MAX_RECV_SGES) { + if (device->attrs.max_recv_sge < SMBDIRECT_RECV_IO_MAX_SGE) { pr_err("warning: device max_recv_sge = %d too small\n", device->attrs.max_recv_sge); return -EINVAL; @@ -1858,7 +1857,7 @@ static int smb_direct_init_params(struct smb_direct_transport *t, cap->max_send_wr = max_send_wrs; cap->max_recv_wr = sp->recv_credit_max; cap->max_send_sge = SMB_DIRECT_MAX_SEND_SGES; - cap->max_recv_sge = SMB_DIRECT_MAX_RECV_SGES; + cap->max_recv_sge = SMBDIRECT_RECV_IO_MAX_SGE; cap->max_inline_data = 0; cap->max_rdma_ctxs = t->max_rw_credits; return 0; From 442959002fcce509069025aab2aaab0344709e6f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 6 Aug 2025 19:36:03 +0200 Subject: [PATCH 097/159] smb: server: make use of struct smbdirect_send_io This is already used by the client and will allow us to use common helper functions soon. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 87 +++++++++++++++------------------- 1 file changed, 39 insertions(+), 48 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index b027382c554e..b4951ecf5c88 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -36,8 +36,6 @@ /* SMB_DIRECT negotiation timeout in seconds */ #define SMB_DIRECT_NEGOTIATE_TIMEOUT 120 -#define SMB_DIRECT_MAX_SEND_SGES 6 - /* * Default maximum number of RDMA read/write outstanding on this connection * This value is possibly decreased during QP creation on hardware limit @@ -143,16 +141,6 @@ struct smb_direct_send_ctx { unsigned int remote_key; }; -struct smb_direct_sendmsg { - struct smb_direct_transport *transport; - struct ib_send_wr wr; - struct list_head list; - int num_sge; - struct ib_sge sge[SMB_DIRECT_MAX_SEND_SGES]; - struct ib_cqe cqe; - u8 packet[]; -}; - struct smb_direct_rdma_rw_msg { struct smb_direct_transport *t; struct ib_cqe cqe; @@ -418,22 +406,23 @@ static void free_transport(struct smb_direct_transport *t) ksmbd_conn_free(KSMBD_TRANS(t)->conn); } -static struct smb_direct_sendmsg +static struct smbdirect_send_io *smb_direct_alloc_sendmsg(struct smb_direct_transport *t) { - struct smb_direct_sendmsg *msg; + struct smbdirect_socket *sc = &t->socket; + struct smbdirect_send_io *msg; msg = mempool_alloc(t->sendmsg_mempool, KSMBD_DEFAULT_GFP); if (!msg) return ERR_PTR(-ENOMEM); - msg->transport = t; - INIT_LIST_HEAD(&msg->list); + msg->socket = sc; + INIT_LIST_HEAD(&msg->sibling_list); msg->num_sge = 0; return msg; } static void smb_direct_free_sendmsg(struct smb_direct_transport *t, - struct smb_direct_sendmsg *msg) + struct smbdirect_send_io *msg) { struct smbdirect_socket *sc = &t->socket; int i; @@ -839,12 +828,14 @@ static void smb_direct_post_recv_credits(struct work_struct *work) static void send_done(struct ib_cq *cq, struct ib_wc *wc) { - struct smb_direct_sendmsg *sendmsg, *sibling; + struct smbdirect_send_io *sendmsg, *sibling; struct smb_direct_transport *t; + struct smbdirect_socket *sc; struct list_head *pos, *prev, *end; - sendmsg = container_of(wc->wr_cqe, struct smb_direct_sendmsg, cqe); - t = sendmsg->transport; + sendmsg = container_of(wc->wr_cqe, struct smbdirect_send_io, cqe); + sc = sendmsg->socket; + t = container_of(sc, struct smb_direct_transport, socket); ksmbd_debug(RDMA, "Send completed. status='%s (%d)', opcode=%d\n", ib_wc_status_msg(wc->status), wc->status, @@ -863,13 +854,13 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc) /* iterate and free the list of messages in reverse. the list's head * is invalid. */ - for (pos = &sendmsg->list, prev = pos->prev, end = sendmsg->list.next; + for (pos = &sendmsg->sibling_list, prev = pos->prev, end = sendmsg->sibling_list.next; prev != end; pos = prev, prev = prev->prev) { - sibling = container_of(pos, struct smb_direct_sendmsg, list); + sibling = container_of(pos, struct smbdirect_send_io, sibling_list); smb_direct_free_sendmsg(t, sibling); } - sibling = container_of(pos, struct smb_direct_sendmsg, list); + sibling = container_of(pos, struct smbdirect_send_io, sibling_list); smb_direct_free_sendmsg(t, sibling); } @@ -917,18 +908,18 @@ static int smb_direct_flush_send_list(struct smb_direct_transport *t, struct smb_direct_send_ctx *send_ctx, bool is_last) { - struct smb_direct_sendmsg *first, *last; + struct smbdirect_send_io *first, *last; int ret; if (list_empty(&send_ctx->msg_list)) return 0; first = list_first_entry(&send_ctx->msg_list, - struct smb_direct_sendmsg, - list); + struct smbdirect_send_io, + sibling_list); last = list_last_entry(&send_ctx->msg_list, - struct smb_direct_sendmsg, - list); + struct smbdirect_send_io, + sibling_list); last->wr.send_flags = IB_SEND_SIGNALED; last->wr.wr_cqe = &last->cqe; @@ -946,7 +937,7 @@ static int smb_direct_flush_send_list(struct smb_direct_transport *t, atomic_add(send_ctx->wr_cnt, &t->send_credits); wake_up(&t->wait_send_credits); list_for_each_entry_safe(first, last, &send_ctx->msg_list, - list) { + sibling_list) { smb_direct_free_sendmsg(t, first); } } @@ -1005,11 +996,11 @@ static int calc_rw_credits(struct smb_direct_transport *t, static int smb_direct_create_header(struct smb_direct_transport *t, int size, int remaining_data_length, - struct smb_direct_sendmsg **sendmsg_out) + struct smbdirect_send_io **sendmsg_out) { struct smbdirect_socket *sc = &t->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; - struct smb_direct_sendmsg *sendmsg; + struct smbdirect_send_io *sendmsg; struct smbdirect_data_transfer *packet; int header_length; int ret; @@ -1112,7 +1103,7 @@ static int get_mapped_sg_list(struct ib_device *device, void *buf, int size, static int post_sendmsg(struct smb_direct_transport *t, struct smb_direct_send_ctx *send_ctx, - struct smb_direct_sendmsg *msg) + struct smbdirect_send_io *msg) { struct smbdirect_socket *sc = &t->socket; int i; @@ -1132,14 +1123,14 @@ static int post_sendmsg(struct smb_direct_transport *t, msg->wr.wr_cqe = NULL; msg->wr.send_flags = 0; if (!list_empty(&send_ctx->msg_list)) { - struct smb_direct_sendmsg *last; + struct smbdirect_send_io *last; last = list_last_entry(&send_ctx->msg_list, - struct smb_direct_sendmsg, - list); + struct smbdirect_send_io, + sibling_list); last->wr.next = &msg->wr; } - list_add_tail(&msg->list, &send_ctx->msg_list); + list_add_tail(&msg->sibling_list, &send_ctx->msg_list); send_ctx->wr_cnt++; return 0; } @@ -1156,9 +1147,9 @@ static int smb_direct_post_send_data(struct smb_direct_transport *t, { struct smbdirect_socket *sc = &t->socket; int i, j, ret; - struct smb_direct_sendmsg *msg; + struct smbdirect_send_io *msg; int data_length; - struct scatterlist sg[SMB_DIRECT_MAX_SEND_SGES - 1]; + struct scatterlist sg[SMBDIRECT_SEND_IO_MAX_SGE - 1]; ret = wait_for_send_credits(t, send_ctx); if (ret) @@ -1179,16 +1170,16 @@ static int smb_direct_post_send_data(struct smb_direct_transport *t, struct ib_sge *sge; int sg_cnt; - sg_init_table(sg, SMB_DIRECT_MAX_SEND_SGES - 1); + sg_init_table(sg, SMBDIRECT_SEND_IO_MAX_SGE - 1); sg_cnt = get_mapped_sg_list(sc->ib.dev, iov[i].iov_base, iov[i].iov_len, - sg, SMB_DIRECT_MAX_SEND_SGES - 1, + sg, SMBDIRECT_SEND_IO_MAX_SGE - 1, DMA_TO_DEVICE); if (sg_cnt <= 0) { pr_err("failed to map buffer\n"); ret = -ENOMEM; goto err; - } else if (sg_cnt + msg->num_sge > SMB_DIRECT_MAX_SEND_SGES) { + } else if (sg_cnt + msg->num_sge > SMBDIRECT_SEND_IO_MAX_SGE) { pr_err("buffer not fitted into sges\n"); ret = -E2BIG; ib_dma_unmap_sg(sc->ib.dev, sg, sg_cnt, @@ -1246,7 +1237,7 @@ static int smb_direct_writev(struct ksmbd_transport *t, smb_direct_send_ctx_init(st, &send_ctx, need_invalidate, remote_key); while (remaining_data_length) { - struct kvec vecs[SMB_DIRECT_MAX_SEND_SGES - 1]; /* minus smbdirect hdr */ + struct kvec vecs[SMBDIRECT_SEND_IO_MAX_SGE - 1]; /* minus smbdirect hdr */ size_t possible_bytes = max_iov_size; size_t possible_vecs; size_t bytes = 0; @@ -1634,7 +1625,7 @@ static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, { struct smbdirect_socket *sc = &t->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; - struct smb_direct_sendmsg *sendmsg; + struct smbdirect_send_io *sendmsg; struct smbdirect_negotiate_resp *resp; int ret; @@ -1782,7 +1773,7 @@ static int smb_direct_init_params(struct smb_direct_transport *t, */ sp->max_send_size = smb_direct_max_send_size; max_send_sges = DIV_ROUND_UP(sp->max_send_size, PAGE_SIZE) + 3; - if (max_send_sges > SMB_DIRECT_MAX_SEND_SGES) { + if (max_send_sges > SMBDIRECT_SEND_IO_MAX_SGE) { pr_err("max_send_size %d is too large\n", sp->max_send_size); return -EINVAL; } @@ -1828,7 +1819,7 @@ static int smb_direct_init_params(struct smb_direct_transport *t, return -EINVAL; } - if (device->attrs.max_send_sge < SMB_DIRECT_MAX_SEND_SGES) { + if (device->attrs.max_send_sge < SMBDIRECT_SEND_IO_MAX_SGE) { pr_err("warning: device max_send_sge = %d too small\n", device->attrs.max_send_sge); return -EINVAL; @@ -1856,7 +1847,7 @@ static int smb_direct_init_params(struct smb_direct_transport *t, cap->max_send_wr = max_send_wrs; cap->max_recv_wr = sp->recv_credit_max; - cap->max_send_sge = SMB_DIRECT_MAX_SEND_SGES; + cap->max_send_sge = SMBDIRECT_SEND_IO_MAX_SGE; cap->max_recv_sge = SMBDIRECT_RECV_IO_MAX_SGE; cap->max_inline_data = 0; cap->max_rdma_ctxs = t->max_rw_credits; @@ -1891,9 +1882,9 @@ static int smb_direct_create_pools(struct smb_direct_transport *t) int i; struct smbdirect_recv_io *recvmsg; - snprintf(name, sizeof(name), "smb_direct_rqst_pool_%p", t); + snprintf(name, sizeof(name), "smbdirect_send_io_pool_%p", t); t->sendmsg_cache = kmem_cache_create(name, - sizeof(struct smb_direct_sendmsg) + + sizeof(struct smbdirect_send_io) + sizeof(struct smbdirect_negotiate_resp), 0, SLAB_HWCACHE_ALIGN, NULL); if (!t->sendmsg_cache) From 98dc77b310644b6716ed2da829697c128b2e5d51 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 6 Aug 2025 19:36:04 +0200 Subject: [PATCH 098/159] smb: server: make use of smbdirect_socket.{send,recv}_io.mem.{cache,pool} This will allow common helper functions to be created later. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 50 ++++++++++++++++------------------ 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index b4951ecf5c88..c400833a8c16 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -109,11 +109,6 @@ struct smb_direct_transport { wait_queue_head_t wait_send_credits; wait_queue_head_t wait_rw_credits; - mempool_t *sendmsg_mempool; - struct kmem_cache *sendmsg_cache; - mempool_t *recvmsg_mempool; - struct kmem_cache *recvmsg_cache; - wait_queue_head_t wait_send_pending; atomic_t send_pending; @@ -412,7 +407,7 @@ static struct smbdirect_send_io struct smbdirect_socket *sc = &t->socket; struct smbdirect_send_io *msg; - msg = mempool_alloc(t->sendmsg_mempool, KSMBD_DEFAULT_GFP); + msg = mempool_alloc(sc->send_io.mem.pool, KSMBD_DEFAULT_GFP); if (!msg) return ERR_PTR(-ENOMEM); msg->socket = sc; @@ -436,7 +431,7 @@ static void smb_direct_free_sendmsg(struct smb_direct_transport *t, msg->sge[i].addr, msg->sge[i].length, DMA_TO_DEVICE); } - mempool_free(msg, t->sendmsg_mempool); + mempool_free(msg, sc->send_io.mem.pool); } static int smb_direct_check_recvmsg(struct smbdirect_recv_io *recvmsg) @@ -1856,22 +1851,23 @@ static int smb_direct_init_params(struct smb_direct_transport *t, static void smb_direct_destroy_pools(struct smb_direct_transport *t) { + struct smbdirect_socket *sc = &t->socket; struct smbdirect_recv_io *recvmsg; while ((recvmsg = get_free_recvmsg(t))) - mempool_free(recvmsg, t->recvmsg_mempool); + mempool_free(recvmsg, sc->recv_io.mem.pool); - mempool_destroy(t->recvmsg_mempool); - t->recvmsg_mempool = NULL; + mempool_destroy(sc->recv_io.mem.pool); + sc->recv_io.mem.pool = NULL; - kmem_cache_destroy(t->recvmsg_cache); - t->recvmsg_cache = NULL; + kmem_cache_destroy(sc->recv_io.mem.cache); + sc->recv_io.mem.cache = NULL; - mempool_destroy(t->sendmsg_mempool); - t->sendmsg_mempool = NULL; + mempool_destroy(sc->send_io.mem.pool); + sc->send_io.mem.pool = NULL; - kmem_cache_destroy(t->sendmsg_cache); - t->sendmsg_cache = NULL; + kmem_cache_destroy(sc->send_io.mem.cache); + sc->send_io.mem.cache = NULL; } static int smb_direct_create_pools(struct smb_direct_transport *t) @@ -1883,35 +1879,35 @@ static int smb_direct_create_pools(struct smb_direct_transport *t) struct smbdirect_recv_io *recvmsg; snprintf(name, sizeof(name), "smbdirect_send_io_pool_%p", t); - t->sendmsg_cache = kmem_cache_create(name, + sc->send_io.mem.cache = kmem_cache_create(name, sizeof(struct smbdirect_send_io) + sizeof(struct smbdirect_negotiate_resp), 0, SLAB_HWCACHE_ALIGN, NULL); - if (!t->sendmsg_cache) + if (!sc->send_io.mem.cache) return -ENOMEM; - t->sendmsg_mempool = mempool_create(sp->send_credit_target, + sc->send_io.mem.pool = mempool_create(sp->send_credit_target, mempool_alloc_slab, mempool_free_slab, - t->sendmsg_cache); - if (!t->sendmsg_mempool) + sc->send_io.mem.cache); + if (!sc->send_io.mem.pool) goto err; snprintf(name, sizeof(name), "smbdirect_recv_io_pool_%p", t); - t->recvmsg_cache = kmem_cache_create(name, + sc->recv_io.mem.cache = kmem_cache_create(name, sizeof(struct smbdirect_recv_io) + sp->max_recv_size, 0, SLAB_HWCACHE_ALIGN, NULL); - if (!t->recvmsg_cache) + if (!sc->recv_io.mem.cache) goto err; - t->recvmsg_mempool = + sc->recv_io.mem.pool = mempool_create(sp->recv_credit_max, mempool_alloc_slab, - mempool_free_slab, t->recvmsg_cache); - if (!t->recvmsg_mempool) + mempool_free_slab, sc->recv_io.mem.cache); + if (!sc->recv_io.mem.pool) goto err; for (i = 0; i < sp->recv_credit_max; i++) { - recvmsg = mempool_alloc(t->recvmsg_mempool, KSMBD_DEFAULT_GFP); + recvmsg = mempool_alloc(sc->recv_io.mem.pool, KSMBD_DEFAULT_GFP); if (!recvmsg) goto err; recvmsg->socket = sc; From 27bc4c57f094917c450f1a2d3097bfea728fc1a5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 14 Aug 2025 10:06:50 +0200 Subject: [PATCH 099/159] smb: server: make only use of wake_up[_all]() in transport_rdma.c wake_up_interruptible(() doesn't wake up tasks waiting with wait_event(). So we better wake_up[_all]() in order to wake up all tasks in order to simplify the logic. As we currently don't use any wait_event_*_exclusive() it doesn't really matter if we use wake_up() or wake_up_all(). But in this patch I try to use wake_up() for expected situations and wake_up_all() for situations of a broken connection. So don't need to adjust things in future when we may use wait_event_*_exclusive() in order to wake up only one process that should make progress. Changing the wait_event_*() code in order to keep wait_event(), wait_event_interruptible() and wait_event_interruptible_timeout() or changing them to wait_event_killable(), wait_event_killable_timeout(), wait_event_killable_exclusive() is something to think about in a future patch. The goal here is to avoid that some tasks are not woken and freeze forever. Also note that this patch only changes the existing wake_up*() calls. Adding more wake_up*() calls for other wait queues is also deferred to a future patch. Link: https://lore.kernel.org/linux-cifs/13851363-0dc9-465c-9ced-3ede4904eef0@samba.org/T/#t Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index c400833a8c16..67a0a2974dcb 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -357,7 +357,7 @@ static void free_transport(struct smb_direct_transport *t) struct smbdirect_socket *sc = &t->socket; struct smbdirect_recv_io *recvmsg; - wake_up_interruptible(&t->wait_send_credits); + wake_up_all(&t->wait_send_credits); ksmbd_debug(RDMA, "wait for all send posted to IB to finish\n"); wait_event(t->wait_send_pending, @@ -524,7 +524,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) sc->recv_io.reassembly.full_packet_received = true; sc->status = SMBDIRECT_SOCKET_CONNECTED; enqueue_reassembly(t, recvmsg, 0); - wake_up_interruptible(&t->wait_status); + wake_up(&t->wait_status); return; case SMBDIRECT_EXPECT_DATA_TRANSFER: { struct smbdirect_data_transfer *data_transfer = @@ -587,14 +587,14 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) queue_work(smb_direct_wq, &t->send_immediate_work); if (atomic_read(&t->send_credits) > 0) - wake_up_interruptible(&t->wait_send_credits); + wake_up(&t->wait_send_credits); if (is_receive_credit_post_required(receive_credits, avail_recvmsg_count)) queue_work(smb_direct_wq, &t->post_recv_credits_work); if (data_length) { enqueue_reassembly(t, recvmsg, (int)data_length); - wake_up_interruptible(&sc->recv_io.reassembly.wait_queue); + wake_up(&sc->recv_io.reassembly.wait_queue); } else put_recvmsg(t, recvmsg); @@ -1570,7 +1570,7 @@ static int smb_direct_cm_handler(struct rdma_cm_id *cm_id, switch (event->event) { case RDMA_CM_EVENT_ESTABLISHED: { sc->status = SMBDIRECT_SOCKET_CONNECTED; - wake_up_interruptible(&t->wait_status); + wake_up(&t->wait_status); break; } case RDMA_CM_EVENT_DEVICE_REMOVAL: @@ -1578,14 +1578,14 @@ static int smb_direct_cm_handler(struct rdma_cm_id *cm_id, ib_drain_qp(sc->ib.qp); sc->status = SMBDIRECT_SOCKET_DISCONNECTED; - wake_up_interruptible(&t->wait_status); - wake_up_interruptible(&sc->recv_io.reassembly.wait_queue); - wake_up(&t->wait_send_credits); + wake_up_all(&t->wait_status); + wake_up_all(&sc->recv_io.reassembly.wait_queue); + wake_up_all(&t->wait_send_credits); break; } case RDMA_CM_EVENT_CONNECT_ERROR: { sc->status = SMBDIRECT_SOCKET_DISCONNECTED; - wake_up_interruptible(&t->wait_status); + wake_up_all(&t->wait_status); break; } default: From d4b86b49093cbe98b68461a1b1af958f1a0ee16d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Aug 2025 18:23:59 +0200 Subject: [PATCH 100/159] smb: server: add a pr_info() when the server starts running We already have a message like: ksmbd: kill command received when the server stops running. This makes it easier for debugging in order to match any possible warnings/errors in dmesg with restarted server. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/server.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c index 8c9c49c3a0a4..40420544cc25 100644 --- a/fs/smb/server/server.c +++ b/fs/smb/server/server.c @@ -365,6 +365,7 @@ static void server_ctrl_handle_init(struct server_ctrl_struct *ctrl) return; } + pr_info("running\n"); WRITE_ONCE(server_conf.state, SERVER_STATE_RUNNING); } From a7eef6144c97bd7031d40ebc6e8fdd038ea3f46f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 11 Aug 2025 18:23:03 +0200 Subject: [PATCH 101/159] smb: server: queue post_recv_credits_work in put_recvmsg() and avoid count_avail_recvmsg This is basically what the client is doing in put_receive_buffer(). It means we don't need complicated work to maintain count_avail_recvmsg. But we keep the logic to queue post_recv_credits_work if the peer raises the requested credit_target and put_receive_buffer() is not called. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 45 +++++++++------------------------- 1 file changed, 11 insertions(+), 34 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 67a0a2974dcb..6c34a271ae84 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -96,7 +96,6 @@ struct smb_direct_transport { spinlock_t receive_credit_lock; int recv_credits; - int count_avail_recvmsg; int recv_credit_target; atomic_t send_credits; @@ -183,13 +182,6 @@ static inline void return (void *)recvmsg->packet; } -static inline bool is_receive_credit_post_required(int receive_credits, - int avail_recvmsg_count) -{ - return receive_credits <= (smb_direct_receive_credit_max >> 3) && - avail_recvmsg_count >= (receive_credits >> 2); -} - static struct smbdirect_recv_io *get_free_recvmsg(struct smb_direct_transport *t) { @@ -223,6 +215,8 @@ static void put_recvmsg(struct smb_direct_transport *t, spin_lock(&sc->recv_io.free.lock); list_add(&recvmsg->list, &sc->recv_io.free.list); spin_unlock(&sc->recv_io.free.lock); + + queue_work(smb_direct_wq, &t->post_recv_credits_work); } static void enqueue_reassembly(struct smb_direct_transport *t, @@ -530,7 +524,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) struct smbdirect_data_transfer *data_transfer = (struct smbdirect_data_transfer *)recvmsg->packet; u32 remaining_data_length, data_offset, data_length; - int avail_recvmsg_count, receive_credits; + int old_recv_credit_target; if (wc->byte_len < offsetof(struct smbdirect_data_transfer, padding)) { @@ -565,18 +559,13 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) sc->recv_io.reassembly.full_packet_received = false; else sc->recv_io.reassembly.full_packet_received = true; - - spin_lock(&t->receive_credit_lock); - receive_credits = --(t->recv_credits); - avail_recvmsg_count = t->count_avail_recvmsg; - spin_unlock(&t->receive_credit_lock); - } else { - spin_lock(&t->receive_credit_lock); - receive_credits = --(t->recv_credits); - avail_recvmsg_count = ++(t->count_avail_recvmsg); - spin_unlock(&t->receive_credit_lock); } + spin_lock(&t->receive_credit_lock); + t->recv_credits -= 1; + spin_unlock(&t->receive_credit_lock); + + old_recv_credit_target = t->recv_credit_target; t->recv_credit_target = le16_to_cpu(data_transfer->credits_requested); atomic_add(le16_to_cpu(data_transfer->credits_granted), @@ -589,10 +578,10 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) if (atomic_read(&t->send_credits) > 0) wake_up(&t->wait_send_credits); - if (is_receive_credit_post_required(receive_credits, avail_recvmsg_count)) - queue_work(smb_direct_wq, &t->post_recv_credits_work); - if (data_length) { + if (t->recv_credit_target > old_recv_credit_target) + queue_work(smb_direct_wq, &t->post_recv_credits_work); + enqueue_reassembly(t, recvmsg, (int)data_length); wake_up(&sc->recv_io.reassembly.wait_queue); } else @@ -750,15 +739,6 @@ static int smb_direct_read(struct ksmbd_transport *t, char *buf, sc->recv_io.reassembly.queue_length -= queue_removed; spin_unlock_irq(&sc->recv_io.reassembly.lock); - spin_lock(&st->receive_credit_lock); - st->count_avail_recvmsg += queue_removed; - if (is_receive_credit_post_required(st->recv_credits, st->count_avail_recvmsg)) { - spin_unlock(&st->receive_credit_lock); - queue_work(smb_direct_wq, &st->post_recv_credits_work); - } else { - spin_unlock(&st->receive_credit_lock); - } - sc->recv_io.reassembly.first_entry_offset = offset; ksmbd_debug(RDMA, "returning to thread data_read=%d reassembly_data_length=%d first_entry_offset=%d\n", @@ -810,7 +790,6 @@ static void smb_direct_post_recv_credits(struct work_struct *work) spin_lock(&t->receive_credit_lock); t->recv_credits += credits; - t->count_avail_recvmsg -= credits; spin_unlock(&t->receive_credit_lock); spin_lock(&t->lock_new_recv_credits); @@ -1826,7 +1805,6 @@ static int smb_direct_init_params(struct smb_direct_transport *t, } t->recv_credits = 0; - t->count_avail_recvmsg = 0; sp->recv_credit_max = smb_direct_receive_credit_max; t->recv_credit_target = 10; @@ -1914,7 +1892,6 @@ static int smb_direct_create_pools(struct smb_direct_transport *t) recvmsg->sge.length = 0; list_add(&recvmsg->list, &sc->recv_io.free.list); } - t->count_avail_recvmsg = sp->recv_credit_max; return 0; err: From c82a53211a378e70866aac8ec49f4df64905ccc2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 7 Aug 2025 11:20:55 +0200 Subject: [PATCH 102/159] smb: server: make use of smbdirect_socket.status_wait This will allow us to have common helper functions soon. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 6c34a271ae84..a338f9496dea 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -92,8 +92,6 @@ struct smb_direct_transport { struct smbdirect_socket socket; - wait_queue_head_t wait_status; - spinlock_t receive_credit_lock; int recv_credits; int recv_credit_target; @@ -307,7 +305,7 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) spin_lock_init(&sc->recv_io.free.lock); sc->status = SMBDIRECT_SOCKET_CREATED; - init_waitqueue_head(&t->wait_status); + init_waitqueue_head(&sc->status_wait); spin_lock_init(&sc->recv_io.reassembly.lock); INIT_LIST_HEAD(&sc->recv_io.reassembly.list); @@ -518,7 +516,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) sc->recv_io.reassembly.full_packet_received = true; sc->status = SMBDIRECT_SOCKET_CONNECTED; enqueue_reassembly(t, recvmsg, 0); - wake_up(&t->wait_status); + wake_up(&sc->status_wait); return; case SMBDIRECT_EXPECT_DATA_TRANSFER: { struct smbdirect_data_transfer *data_transfer = @@ -1522,7 +1520,7 @@ static void smb_direct_disconnect(struct ksmbd_transport *t) ksmbd_debug(RDMA, "Disconnecting cm_id=%p\n", sc->rdma.cm_id); smb_direct_disconnect_rdma_work(&st->disconnect_work); - wait_event_interruptible(st->wait_status, + wait_event_interruptible(sc->status_wait, sc->status == SMBDIRECT_SOCKET_DISCONNECTED); free_transport(st); } @@ -1549,7 +1547,7 @@ static int smb_direct_cm_handler(struct rdma_cm_id *cm_id, switch (event->event) { case RDMA_CM_EVENT_ESTABLISHED: { sc->status = SMBDIRECT_SOCKET_CONNECTED; - wake_up(&t->wait_status); + wake_up(&sc->status_wait); break; } case RDMA_CM_EVENT_DEVICE_REMOVAL: @@ -1557,14 +1555,14 @@ static int smb_direct_cm_handler(struct rdma_cm_id *cm_id, ib_drain_qp(sc->ib.qp); sc->status = SMBDIRECT_SOCKET_DISCONNECTED; - wake_up_all(&t->wait_status); + wake_up_all(&sc->status_wait); wake_up_all(&sc->recv_io.reassembly.wait_queue); wake_up_all(&t->wait_send_credits); break; } case RDMA_CM_EVENT_CONNECT_ERROR: { sc->status = SMBDIRECT_SOCKET_DISCONNECTED; - wake_up_all(&t->wait_status); + wake_up_all(&sc->status_wait); break; } default: @@ -1997,7 +1995,7 @@ static int smb_direct_prepare(struct ksmbd_transport *t) int ret; ksmbd_debug(RDMA, "Waiting for SMB_DIRECT negotiate request\n"); - ret = wait_event_interruptible_timeout(st->wait_status, + ret = wait_event_interruptible_timeout(sc->status_wait, st->negotiation_requested || sc->status == SMBDIRECT_SOCKET_DISCONNECTED, SMB_DIRECT_NEGOTIATE_TIMEOUT * HZ); From e2d5e516c66383bed098b60be4925f9cbe9e3530 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Aug 2025 12:46:25 +0200 Subject: [PATCH 103/159] smb: server: only turn into SMBDIRECT_SOCKET_CONNECTED when negotiation is done From SMBDIRECT_SOCKET_CREATED we now go via the following stages: 1. SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED This indicated rdma_accept needs to be called 2. SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING This waits for RDMA_CM_EVENT_ESTABLISHED to arrive 3. SMBDIRECT_SOCKET_NEGOTIATE_NEEDED This waits for the negotiate request to arrive 4. SMBDIRECT_SOCKET_NEGOTIATE_RUNNING This indicates the negotiate request arrived and needs to be processed 5. SMBDIRECT_SOCKET_CONNECTED The connection is ready to use This avoids the extra 'bool negotiation_requested' and makes the steps more clear. In future we may want to add trace points when changing the states, which would be useful for debugging. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 84 ++++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 15 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index a338f9496dea..c5850dcf2e19 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -113,8 +113,6 @@ struct smb_direct_transport { struct work_struct send_immediate_work; struct work_struct disconnect_work; - bool negotiation_requested; - bool legacy_iwarp; u8 initiator_depth; u8 responder_resources; @@ -255,19 +253,53 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work) disconnect_work); struct smbdirect_socket *sc = &t->socket; - if (sc->status == SMBDIRECT_SOCKET_CONNECTED) { + /* + * make sure this and other work is not queued again + * but here we don't block and avoid + * disable[_delayed]_work_sync() + */ + disable_work(&t->disconnect_work); + disable_work(&t->post_recv_credits_work); + disable_work(&t->send_immediate_work); + + switch (sc->status) { + case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: + case SMBDIRECT_SOCKET_NEGOTIATE_RUNNING: + case SMBDIRECT_SOCKET_NEGOTIATE_FAILED: + case SMBDIRECT_SOCKET_CONNECTED: + case SMBDIRECT_SOCKET_ERROR: sc->status = SMBDIRECT_SOCKET_DISCONNECTING; rdma_disconnect(sc->rdma.cm_id); + break; + + case SMBDIRECT_SOCKET_CREATED: + case SMBDIRECT_SOCKET_RESOLVE_ADDR_NEEDED: + case SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING: + case SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED: + case SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED: + case SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING: + case SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED: + case SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED: + case SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING: + case SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED: + /* + * rdma_accept() never reached + * RDMA_CM_EVENT_ESTABLISHED + */ + sc->status = SMBDIRECT_SOCKET_DISCONNECTED; + break; + + case SMBDIRECT_SOCKET_DISCONNECTING: + case SMBDIRECT_SOCKET_DISCONNECTED: + case SMBDIRECT_SOCKET_DESTROYED: + break; } } static void smb_direct_disconnect_rdma_connection(struct smb_direct_transport *t) { - struct smbdirect_socket *sc = &t->socket; - - if (sc->status == SMBDIRECT_SOCKET_CONNECTED) - queue_work(smb_direct_wq, &t->disconnect_work); + queue_work(smb_direct_wq, &t->disconnect_work); } static void smb_direct_send_immediate_work(struct work_struct *work) @@ -512,9 +544,9 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) smb_direct_disconnect_rdma_connection(t); return; } - t->negotiation_requested = true; sc->recv_io.reassembly.full_packet_received = true; - sc->status = SMBDIRECT_SOCKET_CONNECTED; + WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_NEGOTIATE_NEEDED); + sc->status = SMBDIRECT_SOCKET_NEGOTIATE_RUNNING; enqueue_reassembly(t, recvmsg, 0); wake_up(&sc->status_wait); return; @@ -1546,7 +1578,8 @@ static int smb_direct_cm_handler(struct rdma_cm_id *cm_id, switch (event->event) { case RDMA_CM_EVENT_ESTABLISHED: { - sc->status = SMBDIRECT_SOCKET_CONNECTED; + WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING); + sc->status = SMBDIRECT_SOCKET_NEGOTIATE_NEEDED; wake_up(&sc->status_wait); break; } @@ -1555,6 +1588,7 @@ static int smb_direct_cm_handler(struct rdma_cm_id *cm_id, ib_drain_qp(sc->ib.qp); sc->status = SMBDIRECT_SOCKET_DISCONNECTED; + smb_direct_disconnect_rdma_work(&sc->disconnect_work); wake_up_all(&sc->status_wait); wake_up_all(&sc->recv_io.reassembly.wait_queue); wake_up_all(&t->wait_send_credits); @@ -1611,6 +1645,8 @@ static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, resp->min_version = SMB_DIRECT_VERSION_LE; resp->max_version = SMB_DIRECT_VERSION_LE; resp->status = STATUS_NOT_SUPPORTED; + + sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED; } else { resp->status = STATUS_SUCCESS; resp->min_version = SMB_DIRECT_VERSION_LE; @@ -1627,6 +1663,7 @@ static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, cpu_to_le32(sp->max_fragmented_recv_size); sc->recv_io.expected = SMBDIRECT_EXPECT_DATA_TRANSFER; + sc->status = SMBDIRECT_SOCKET_CONNECTED; } sendmsg->sge[0].addr = ib_dma_map_single(sc->ib.dev, @@ -1682,6 +1719,8 @@ static int smb_direct_accept_client(struct smb_direct_transport *t) conn_param.rnr_retry_count = SMB_DIRECT_CM_RNR_RETRY; conn_param.flow_control = 0; + WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED); + sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING; ret = rdma_accept(sc->rdma.cm_id, &conn_param); if (ret) { pr_err("error at rdma_accept: %d\n", ret); @@ -1696,6 +1735,9 @@ static int smb_direct_prepare_negotiation(struct smb_direct_transport *t) int ret; struct smbdirect_recv_io *recvmsg; + WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_CREATED); + sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED; + sc->recv_io.expected = SMBDIRECT_EXPECT_NEGOTIATE_REQ; recvmsg = get_free_recvmsg(t); @@ -1708,7 +1750,6 @@ static int smb_direct_prepare_negotiation(struct smb_direct_transport *t) goto out_err; } - t->negotiation_requested = false; ret = smb_direct_accept_client(t); if (ret) { pr_err("Can't accept client\n"); @@ -1994,12 +2035,25 @@ static int smb_direct_prepare(struct ksmbd_transport *t) struct smbdirect_negotiate_req *req; int ret; + /* + * We are waiting to pass the following states: + * + * SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED + * SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING + * SMBDIRECT_SOCKET_NEGOTIATE_NEEDED + * + * To finally get to SMBDIRECT_SOCKET_NEGOTIATE_RUNNING + * in order to continue below. + * + * Everything else is unexpected and an error. + */ ksmbd_debug(RDMA, "Waiting for SMB_DIRECT negotiate request\n"); ret = wait_event_interruptible_timeout(sc->status_wait, - st->negotiation_requested || - sc->status == SMBDIRECT_SOCKET_DISCONNECTED, - SMB_DIRECT_NEGOTIATE_TIMEOUT * HZ); - if (ret <= 0 || sc->status == SMBDIRECT_SOCKET_DISCONNECTED) + sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED && + sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING && + sc->status != SMBDIRECT_SOCKET_NEGOTIATE_NEEDED, + SMB_DIRECT_NEGOTIATE_TIMEOUT * HZ); + if (ret <= 0 || sc->status != SMBDIRECT_SOCKET_NEGOTIATE_RUNNING) return ret < 0 ? ret : -ETIMEDOUT; recvmsg = get_first_reassembly(st); From b31606097de8393c8adac4161a4d3a6098af10e0 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 12 Aug 2025 10:55:31 +0200 Subject: [PATCH 104/159] smb: server: move smb_direct_disconnect_rdma_work() into free_transport() The logic is also needed when smb_direct_handle_connect_request() calls free_transport(), because rdma_accept() and RDMA_CM_EVENT_ESTABLISHED could already be reached. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index c5850dcf2e19..298c7e060db6 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -381,13 +381,19 @@ static void free_transport(struct smb_direct_transport *t) struct smbdirect_socket *sc = &t->socket; struct smbdirect_recv_io *recvmsg; + disable_work_sync(&t->disconnect_work); + if (sc->status < SMBDIRECT_SOCKET_DISCONNECTING) { + smb_direct_disconnect_rdma_work(&t->disconnect_work); + wait_event_interruptible(sc->status_wait, + sc->status == SMBDIRECT_SOCKET_DISCONNECTED); + } + wake_up_all(&t->wait_send_credits); ksmbd_debug(RDMA, "wait for all send posted to IB to finish\n"); wait_event(t->wait_send_pending, atomic_read(&t->send_pending) == 0); - disable_work_sync(&t->disconnect_work); disable_work_sync(&t->post_recv_credits_work); disable_work_sync(&t->send_immediate_work); @@ -1551,9 +1557,6 @@ static void smb_direct_disconnect(struct ksmbd_transport *t) ksmbd_debug(RDMA, "Disconnecting cm_id=%p\n", sc->rdma.cm_id); - smb_direct_disconnect_rdma_work(&st->disconnect_work); - wait_event_interruptible(sc->status_wait, - sc->status == SMBDIRECT_SOCKET_DISCONNECTED); free_transport(st); } From b4d56ced9e9dc353484dcb6355c1fd7074609124 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 13 Aug 2025 11:39:19 +0200 Subject: [PATCH 105/159] smb: server: don't wait for info->send_pending == 0 on error Instead we just wake up the waiters and let them return -ENOTCONN. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 298c7e060db6..4199a4f96635 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -389,10 +389,7 @@ static void free_transport(struct smb_direct_transport *t) } wake_up_all(&t->wait_send_credits); - - ksmbd_debug(RDMA, "wait for all send posted to IB to finish\n"); - wait_event(t->wait_send_pending, - atomic_read(&t->send_pending) == 0); + wake_up_all(&t->wait_send_pending); disable_work_sync(&t->post_recv_credits_work); disable_work_sync(&t->send_immediate_work); @@ -1356,7 +1353,11 @@ static int smb_direct_writev(struct ksmbd_transport *t, */ wait_event(st->wait_send_pending, - atomic_read(&st->send_pending) == 0); + atomic_read(&st->send_pending) == 0 || + sc->status != SMBDIRECT_SOCKET_CONNECTED); + if (sc->status != SMBDIRECT_SOCKET_CONNECTED && ret == 0) + ret = -ENOTCONN; + return ret; } @@ -1689,7 +1690,11 @@ static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, } wait_event(t->wait_send_pending, - atomic_read(&t->send_pending) == 0); + atomic_read(&t->send_pending) == 0 || + sc->status != SMBDIRECT_SOCKET_CONNECTED); + if (sc->status != SMBDIRECT_SOCKET_CONNECTED) + return -ENOTCONN; + return 0; } From 16ba90e52bc7c367b62386fa4f61e4dc318c3583 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Aug 2025 15:10:52 +0200 Subject: [PATCH 106/159] smb: server: make use of smbdirect_socket_init() Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 4199a4f96635..297345c50f95 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -324,6 +324,7 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) if (!t) return NULL; sc = &t->socket; + smbdirect_socket_init(sc); sc->rdma.cm_id = cm_id; cm_id->context = t; @@ -333,17 +334,6 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) sc->ib.dev = sc->rdma.cm_id->device; - INIT_LIST_HEAD(&sc->recv_io.free.list); - spin_lock_init(&sc->recv_io.free.lock); - - sc->status = SMBDIRECT_SOCKET_CREATED; - init_waitqueue_head(&sc->status_wait); - - spin_lock_init(&sc->recv_io.reassembly.lock); - INIT_LIST_HEAD(&sc->recv_io.reassembly.list); - sc->recv_io.reassembly.data_length = 0; - sc->recv_io.reassembly.queue_length = 0; - init_waitqueue_head(&sc->recv_io.reassembly.wait_queue); init_waitqueue_head(&t->wait_send_credits); init_waitqueue_head(&t->wait_rw_credits); From bb12617ecb3af1e1c8ba36ef2c3496f95521a605 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Aug 2025 19:07:37 +0200 Subject: [PATCH 107/159] smb: server: make use of smbdirect_socket.disconnect_work Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 297345c50f95..1e14b038a77f 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -111,7 +111,6 @@ struct smb_direct_transport { struct work_struct post_recv_credits_work; struct work_struct send_immediate_work; - struct work_struct disconnect_work; bool legacy_iwarp; u8 initiator_depth; @@ -248,17 +247,17 @@ static struct smbdirect_recv_io *get_first_reassembly(struct smb_direct_transpor static void smb_direct_disconnect_rdma_work(struct work_struct *work) { + struct smbdirect_socket *sc = + container_of(work, struct smbdirect_socket, disconnect_work); struct smb_direct_transport *t = - container_of(work, struct smb_direct_transport, - disconnect_work); - struct smbdirect_socket *sc = &t->socket; + container_of(sc, struct smb_direct_transport, socket); /* * make sure this and other work is not queued again * but here we don't block and avoid * disable[_delayed]_work_sync() */ - disable_work(&t->disconnect_work); + disable_work(&sc->disconnect_work); disable_work(&t->post_recv_credits_work); disable_work(&t->send_immediate_work); @@ -299,7 +298,9 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work) static void smb_direct_disconnect_rdma_connection(struct smb_direct_transport *t) { - queue_work(smb_direct_wq, &t->disconnect_work); + struct smbdirect_socket *sc = &t->socket; + + queue_work(smb_direct_wq, &sc->disconnect_work); } static void smb_direct_send_immediate_work(struct work_struct *work) @@ -326,6 +327,8 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) sc = &t->socket; smbdirect_socket_init(sc); + INIT_WORK(&sc->disconnect_work, smb_direct_disconnect_rdma_work); + sc->rdma.cm_id = cm_id; cm_id->context = t; @@ -347,7 +350,6 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) INIT_WORK(&t->post_recv_credits_work, smb_direct_post_recv_credits); INIT_WORK(&t->send_immediate_work, smb_direct_send_immediate_work); - INIT_WORK(&t->disconnect_work, smb_direct_disconnect_rdma_work); conn = ksmbd_conn_alloc(); if (!conn) @@ -371,9 +373,9 @@ static void free_transport(struct smb_direct_transport *t) struct smbdirect_socket *sc = &t->socket; struct smbdirect_recv_io *recvmsg; - disable_work_sync(&t->disconnect_work); + disable_work_sync(&sc->disconnect_work); if (sc->status < SMBDIRECT_SOCKET_DISCONNECTING) { - smb_direct_disconnect_rdma_work(&t->disconnect_work); + smb_direct_disconnect_rdma_work(&sc->disconnect_work); wait_event_interruptible(sc->status_wait, sc->status == SMBDIRECT_SOCKET_DISCONNECTED); } @@ -1558,7 +1560,7 @@ static void smb_direct_shutdown(struct ksmbd_transport *t) ksmbd_debug(RDMA, "smb-direct shutdown cm_id=%p\n", sc->rdma.cm_id); - smb_direct_disconnect_rdma_work(&st->disconnect_work); + smb_direct_disconnect_rdma_work(&sc->disconnect_work); } static int smb_direct_cm_handler(struct rdma_cm_id *cm_id, From fd0ad9c521db6acf20fb24699830138481c07f8a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 11 Aug 2025 15:19:51 +0200 Subject: [PATCH 108/159] smb: server: make use of smbdirect_socket.send_io.pending.{count,zero_wait_queue} This will is used by the client already and will allow to create common helper functions. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 1e14b038a77f..d8f0f252e401 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -106,9 +106,6 @@ struct smb_direct_transport { wait_queue_head_t wait_send_credits; wait_queue_head_t wait_rw_credits; - wait_queue_head_t wait_send_pending; - atomic_t send_pending; - struct work_struct post_recv_credits_work; struct work_struct send_immediate_work; @@ -342,9 +339,6 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) spin_lock_init(&t->receive_credit_lock); - init_waitqueue_head(&t->wait_send_pending); - atomic_set(&t->send_pending, 0); - spin_lock_init(&t->lock_new_recv_credits); INIT_WORK(&t->post_recv_credits_work, @@ -381,7 +375,7 @@ static void free_transport(struct smb_direct_transport *t) } wake_up_all(&t->wait_send_credits); - wake_up_all(&t->wait_send_pending); + wake_up_all(&sc->send_io.pending.zero_wait_queue); disable_work_sync(&t->post_recv_credits_work); disable_work_sync(&t->send_immediate_work); @@ -847,8 +841,8 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc) smb_direct_disconnect_rdma_connection(t); } - if (atomic_dec_and_test(&t->send_pending)) - wake_up(&t->wait_send_pending); + if (atomic_dec_and_test(&sc->send_io.pending.count)) + wake_up(&sc->send_io.pending.zero_wait_queue); /* iterate and free the list of messages in reverse. the list's head * is invalid. @@ -881,12 +875,12 @@ static int smb_direct_post_send(struct smb_direct_transport *t, struct smbdirect_socket *sc = &t->socket; int ret; - atomic_inc(&t->send_pending); + atomic_inc(&sc->send_io.pending.count); ret = ib_post_send(sc->ib.qp, wr, NULL); if (ret) { pr_err("failed to post send: %d\n", ret); - if (atomic_dec_and_test(&t->send_pending)) - wake_up(&t->wait_send_pending); + if (atomic_dec_and_test(&sc->send_io.pending.count)) + wake_up(&sc->send_io.pending.zero_wait_queue); smb_direct_disconnect_rdma_connection(t); } return ret; @@ -1344,8 +1338,8 @@ static int smb_direct_writev(struct ksmbd_transport *t, * that means all the I/Os have been out and we are good to return */ - wait_event(st->wait_send_pending, - atomic_read(&st->send_pending) == 0 || + wait_event(sc->send_io.pending.zero_wait_queue, + atomic_read(&sc->send_io.pending.count) == 0 || sc->status != SMBDIRECT_SOCKET_CONNECTED); if (sc->status != SMBDIRECT_SOCKET_CONNECTED && ret == 0) ret = -ENOTCONN; @@ -1681,8 +1675,8 @@ static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, return ret; } - wait_event(t->wait_send_pending, - atomic_read(&t->send_pending) == 0 || + wait_event(sc->send_io.pending.zero_wait_queue, + atomic_read(&sc->send_io.pending.count) == 0 || sc->status != SMBDIRECT_SOCKET_CONNECTED); if (sc->status != SMBDIRECT_SOCKET_CONNECTED) return -ENOTCONN; From 2def28338a19f03a15a99d7df46930e6be6944e8 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 11 Aug 2025 17:12:58 +0200 Subject: [PATCH 109/159] smb: server: make use of smbdirect_socket.send_io.credits.{count,wait_queue} This will is used by the client already and will allow to create common helper functions. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index d8f0f252e401..256970c72586 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -96,14 +96,12 @@ struct smb_direct_transport { int recv_credits; int recv_credit_target; - atomic_t send_credits; spinlock_t lock_new_recv_credits; int new_recv_credits; int max_rw_credits; int pages_per_rw_credit; atomic_t rw_credits; - wait_queue_head_t wait_send_credits; wait_queue_head_t wait_rw_credits; struct work_struct post_recv_credits_work; @@ -334,7 +332,6 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) sc->ib.dev = sc->rdma.cm_id->device; - init_waitqueue_head(&t->wait_send_credits); init_waitqueue_head(&t->wait_rw_credits); spin_lock_init(&t->receive_credit_lock); @@ -374,7 +371,7 @@ static void free_transport(struct smb_direct_transport *t) sc->status == SMBDIRECT_SOCKET_DISCONNECTED); } - wake_up_all(&t->wait_send_credits); + wake_up_all(&sc->send_io.credits.wait_queue); wake_up_all(&sc->send_io.pending.zero_wait_queue); disable_work_sync(&t->post_recv_credits_work); @@ -588,14 +585,14 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) t->recv_credit_target = le16_to_cpu(data_transfer->credits_requested); atomic_add(le16_to_cpu(data_transfer->credits_granted), - &t->send_credits); + &sc->send_io.credits.count); if (le16_to_cpu(data_transfer->flags) & SMBDIRECT_FLAG_RESPONSE_REQUESTED) queue_work(smb_direct_wq, &t->send_immediate_work); - if (atomic_read(&t->send_credits) > 0) - wake_up(&t->wait_send_credits); + if (atomic_read(&sc->send_io.credits.count) > 0) + wake_up(&sc->send_io.credits.wait_queue); if (data_length) { if (t->recv_credit_target > old_recv_credit_target) @@ -901,6 +898,7 @@ static int smb_direct_flush_send_list(struct smb_direct_transport *t, struct smb_direct_send_ctx *send_ctx, bool is_last) { + struct smbdirect_socket *sc = &t->socket; struct smbdirect_send_io *first, *last; int ret; @@ -927,8 +925,8 @@ static int smb_direct_flush_send_list(struct smb_direct_transport *t, send_ctx->need_invalidate_rkey, send_ctx->remote_key); } else { - atomic_add(send_ctx->wr_cnt, &t->send_credits); - wake_up(&t->wait_send_credits); + atomic_add(send_ctx->wr_cnt, &sc->send_io.credits.count); + wake_up(&sc->send_io.credits.wait_queue); list_for_each_entry_safe(first, last, &send_ctx->msg_list, sibling_list) { smb_direct_free_sendmsg(t, first); @@ -963,16 +961,17 @@ static int wait_for_credits(struct smb_direct_transport *t, static int wait_for_send_credits(struct smb_direct_transport *t, struct smb_direct_send_ctx *send_ctx) { + struct smbdirect_socket *sc = &t->socket; int ret; if (send_ctx && - (send_ctx->wr_cnt >= 16 || atomic_read(&t->send_credits) <= 1)) { + (send_ctx->wr_cnt >= 16 || atomic_read(&sc->send_io.credits.count) <= 1)) { ret = smb_direct_flush_send_list(t, send_ctx, false); if (ret) return ret; } - return wait_for_credits(t, &t->wait_send_credits, &t->send_credits, 1); + return wait_for_credits(t, &sc->send_io.credits.wait_queue, &sc->send_io.credits.count, 1); } static int wait_for_rw_credits(struct smb_direct_transport *t, int credits) @@ -1155,7 +1154,7 @@ static int smb_direct_post_send_data(struct smb_direct_transport *t, ret = smb_direct_create_header(t, data_length, remaining_data_length, &msg); if (ret) { - atomic_inc(&t->send_credits); + atomic_inc(&sc->send_io.credits.count); return ret; } @@ -1195,7 +1194,7 @@ static int smb_direct_post_send_data(struct smb_direct_transport *t, return 0; err: smb_direct_free_sendmsg(t, msg); - atomic_inc(&t->send_credits); + atomic_inc(&sc->send_io.credits.count); return ret; } @@ -1581,7 +1580,7 @@ static int smb_direct_cm_handler(struct rdma_cm_id *cm_id, smb_direct_disconnect_rdma_work(&sc->disconnect_work); wake_up_all(&sc->status_wait); wake_up_all(&sc->recv_io.reassembly.wait_queue); - wake_up_all(&t->wait_send_credits); + wake_up_all(&sc->send_io.credits.wait_queue); break; } case RDMA_CM_EVENT_CONNECT_ERROR: { @@ -1844,7 +1843,6 @@ static int smb_direct_init_params(struct smb_direct_transport *t, t->new_recv_credits = 0; sp->send_credit_target = smb_direct_send_credit_target; - atomic_set(&t->send_credits, 0); atomic_set(&t->rw_credits, t->max_rw_credits); sp->max_send_size = smb_direct_max_send_size; From 73430a64469c86c027518014e63ca637d9a53b9a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 18 Aug 2025 21:16:48 +0200 Subject: [PATCH 110/159] smb: server: make use of struct smbdirect_send_batch This makes it easier to move functions to the common smbdirect code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 256970c72586..4f6e8e552bcd 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -118,13 +118,6 @@ struct smb_direct_transport { static const struct ksmbd_transport_ops ksmbd_smb_direct_transport_ops; -struct smb_direct_send_ctx { - struct list_head msg_list; - int wr_cnt; - bool need_invalidate_rkey; - unsigned int remote_key; -}; - struct smb_direct_rdma_rw_msg { struct smb_direct_transport *t; struct ib_cqe cqe; @@ -156,7 +149,7 @@ static inline int get_buf_page_count(void *buf, int size) static void smb_direct_destroy_pools(struct smb_direct_transport *transport); static void smb_direct_post_recv_credits(struct work_struct *work); static int smb_direct_post_send_data(struct smb_direct_transport *t, - struct smb_direct_send_ctx *send_ctx, + struct smbdirect_send_batch *send_ctx, struct kvec *iov, int niov, int remaining_data_length); @@ -884,7 +877,7 @@ static int smb_direct_post_send(struct smb_direct_transport *t, } static void smb_direct_send_ctx_init(struct smb_direct_transport *t, - struct smb_direct_send_ctx *send_ctx, + struct smbdirect_send_batch *send_ctx, bool need_invalidate_rkey, unsigned int remote_key) { @@ -895,7 +888,7 @@ static void smb_direct_send_ctx_init(struct smb_direct_transport *t, } static int smb_direct_flush_send_list(struct smb_direct_transport *t, - struct smb_direct_send_ctx *send_ctx, + struct smbdirect_send_batch *send_ctx, bool is_last) { struct smbdirect_socket *sc = &t->socket; @@ -959,7 +952,7 @@ static int wait_for_credits(struct smb_direct_transport *t, } static int wait_for_send_credits(struct smb_direct_transport *t, - struct smb_direct_send_ctx *send_ctx) + struct smbdirect_send_batch *send_ctx) { struct smbdirect_socket *sc = &t->socket; int ret; @@ -1094,7 +1087,7 @@ static int get_mapped_sg_list(struct ib_device *device, void *buf, int size, } static int post_sendmsg(struct smb_direct_transport *t, - struct smb_direct_send_ctx *send_ctx, + struct smbdirect_send_batch *send_ctx, struct smbdirect_send_io *msg) { struct smbdirect_socket *sc = &t->socket; @@ -1133,7 +1126,7 @@ static int post_sendmsg(struct smb_direct_transport *t, } static int smb_direct_post_send_data(struct smb_direct_transport *t, - struct smb_direct_send_ctx *send_ctx, + struct smbdirect_send_batch *send_ctx, struct kvec *iov, int niov, int remaining_data_length) { @@ -1211,7 +1204,7 @@ static int smb_direct_writev(struct ksmbd_transport *t, size_t max_iov_size = sp->max_send_size - sizeof(struct smbdirect_data_transfer); int ret; - struct smb_direct_send_ctx send_ctx; + struct smbdirect_send_batch send_ctx; int error = 0; if (sc->status != SMBDIRECT_SOCKET_CONNECTED) From 95475d8886bd7e60860f7aa8657683a089f21db5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 14 Aug 2025 12:01:50 +0200 Subject: [PATCH 111/159] smb: server: make use smbdirect_socket.rw_io.credits This will allow to us to have functions moved into common code in future (even if it's only used by the server). Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 44 +++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 4f6e8e552bcd..87fb66304ee5 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -98,11 +98,6 @@ struct smb_direct_transport { spinlock_t lock_new_recv_credits; int new_recv_credits; - int max_rw_credits; - int pages_per_rw_credit; - atomic_t rw_credits; - - wait_queue_head_t wait_rw_credits; struct work_struct post_recv_credits_work; struct work_struct send_immediate_work; @@ -325,8 +320,6 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) sc->ib.dev = sc->rdma.cm_id->device; - init_waitqueue_head(&t->wait_rw_credits); - spin_lock_init(&t->receive_credit_lock); spin_lock_init(&t->lock_new_recv_credits); @@ -969,14 +962,21 @@ static int wait_for_send_credits(struct smb_direct_transport *t, static int wait_for_rw_credits(struct smb_direct_transport *t, int credits) { - return wait_for_credits(t, &t->wait_rw_credits, &t->rw_credits, credits); + struct smbdirect_socket *sc = &t->socket; + + return wait_for_credits(t, + &sc->rw_io.credits.wait_queue, + &sc->rw_io.credits.count, + credits); } static int calc_rw_credits(struct smb_direct_transport *t, char *buf, unsigned int len) { + struct smbdirect_socket *sc = &t->socket; + return DIV_ROUND_UP(get_buf_page_count(buf, len), - t->pages_per_rw_credit); + sc->rw_io.credits.num_pages); } static int smb_direct_create_header(struct smb_direct_transport *t, @@ -1506,8 +1506,8 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, smb_direct_free_rdma_rw_msg(t, msg, is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } - atomic_add(credits_needed, &t->rw_credits); - wake_up(&t->wait_rw_credits); + atomic_add(credits_needed, &sc->rw_io.credits.count); + wake_up(&sc->rw_io.credits.wait_queue); return ret; } @@ -1785,9 +1785,9 @@ static int smb_direct_init_params(struct smb_direct_transport *t, * MR invalidation. */ sp->max_read_write_size = smb_direct_max_read_write_size; - t->pages_per_rw_credit = smb_direct_get_max_fr_pages(t); - t->max_rw_credits = DIV_ROUND_UP(sp->max_read_write_size, - (t->pages_per_rw_credit - 1) * + sc->rw_io.credits.num_pages = smb_direct_get_max_fr_pages(t); + sc->rw_io.credits.max = DIV_ROUND_UP(sp->max_read_write_size, + (sc->rw_io.credits.num_pages - 1) * PAGE_SIZE); max_sge_per_wr = min_t(unsigned int, device->attrs.max_send_sge, @@ -1795,9 +1795,9 @@ static int smb_direct_init_params(struct smb_direct_transport *t, max_sge_per_wr = max_t(unsigned int, max_sge_per_wr, max_send_sges); wrs_per_credit = max_t(unsigned int, 4, - DIV_ROUND_UP(t->pages_per_rw_credit, + DIV_ROUND_UP(sc->rw_io.credits.num_pages, max_sge_per_wr) + 1); - max_rw_wrs = t->max_rw_credits * wrs_per_credit; + max_rw_wrs = sc->rw_io.credits.max * wrs_per_credit; max_send_wrs = smb_direct_send_credit_target + max_rw_wrs; if (max_send_wrs > device->attrs.max_cqe || @@ -1836,7 +1836,7 @@ static int smb_direct_init_params(struct smb_direct_transport *t, t->new_recv_credits = 0; sp->send_credit_target = smb_direct_send_credit_target; - atomic_set(&t->rw_credits, t->max_rw_credits); + atomic_set(&sc->rw_io.credits.count, sc->rw_io.credits.max); sp->max_send_size = smb_direct_max_send_size; sp->max_recv_size = smb_direct_max_receive_size; @@ -1847,7 +1847,7 @@ static int smb_direct_init_params(struct smb_direct_transport *t, cap->max_send_sge = SMBDIRECT_SEND_IO_MAX_SGE; cap->max_recv_sge = SMBDIRECT_RECV_IO_MAX_SGE; cap->max_inline_data = 0; - cap->max_rdma_ctxs = t->max_rw_credits; + cap->max_rdma_ctxs = sc->rw_io.credits.max; return 0; } @@ -1981,11 +1981,11 @@ static int smb_direct_create_qpair(struct smb_direct_transport *t, pages_per_rw = DIV_ROUND_UP(sp->max_read_write_size, PAGE_SIZE) + 1; if (pages_per_rw > sc->ib.dev->attrs.max_sgl_rd) { ret = ib_mr_pool_init(sc->ib.qp, &sc->ib.qp->rdma_mrs, - t->max_rw_credits, IB_MR_TYPE_MEM_REG, - t->pages_per_rw_credit, 0); + sc->rw_io.credits.max, IB_MR_TYPE_MEM_REG, + sc->rw_io.credits.num_pages, 0); if (ret) { - pr_err("failed to init mr pool count %d pages %d\n", - t->max_rw_credits, t->pages_per_rw_credit); + pr_err("failed to init mr pool count %zu pages %zu\n", + sc->rw_io.credits.max, sc->rw_io.credits.num_pages); goto err; } } From 780ccb0fb624600278ef4a65df30e563fd015a2a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 18 Aug 2025 21:07:06 +0200 Subject: [PATCH 112/159] smb: server: make use of struct smbdirect_rw_io This will allow us to create functions in the common smbdirect code to be used by the server in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 37 +++++++++++++--------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 87fb66304ee5..33ce90b15de5 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -113,17 +113,6 @@ struct smb_direct_transport { static const struct ksmbd_transport_ops ksmbd_smb_direct_transport_ops; -struct smb_direct_rdma_rw_msg { - struct smb_direct_transport *t; - struct ib_cqe cqe; - int status; - struct completion *completion; - struct list_head list; - struct rdma_rw_ctx rw_ctx; - struct sg_table sgt; - struct scatterlist sg_list[]; -}; - void init_smbd_max_io_size(unsigned int sz) { sz = clamp_val(sz, SMBD_MIN_IOSIZE, SMBD_MAX_IOSIZE); @@ -1340,12 +1329,12 @@ static int smb_direct_writev(struct ksmbd_transport *t, } static void smb_direct_free_rdma_rw_msg(struct smb_direct_transport *t, - struct smb_direct_rdma_rw_msg *msg, + struct smbdirect_rw_io *msg, enum dma_data_direction dir) { struct smbdirect_socket *sc = &t->socket; - rdma_rw_ctx_destroy(&msg->rw_ctx, sc->ib.qp, sc->ib.qp->port, + rdma_rw_ctx_destroy(&msg->rdma_ctx, sc->ib.qp, sc->ib.qp->port, msg->sgt.sgl, msg->sgt.nents, dir); sg_free_table_chained(&msg->sgt, SG_CHUNK_SIZE); kfree(msg); @@ -1354,12 +1343,14 @@ static void smb_direct_free_rdma_rw_msg(struct smb_direct_transport *t, static void read_write_done(struct ib_cq *cq, struct ib_wc *wc, enum dma_data_direction dir) { - struct smb_direct_rdma_rw_msg *msg = container_of(wc->wr_cqe, - struct smb_direct_rdma_rw_msg, cqe); - struct smb_direct_transport *t = msg->t; + struct smbdirect_rw_io *msg = + container_of(wc->wr_cqe, struct smbdirect_rw_io, cqe); + struct smbdirect_socket *sc = msg->socket; + struct smb_direct_transport *t = + container_of(sc, struct smb_direct_transport, socket); if (wc->status != IB_WC_SUCCESS) { - msg->status = -EIO; + msg->error = -EIO; pr_err("read/write error. opcode = %d, status = %s(%d)\n", wc->opcode, ib_wc_status_msg(wc->status), wc->status); if (wc->status != IB_WC_WR_FLUSH_ERR) @@ -1387,7 +1378,7 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, { struct smbdirect_socket *sc = &t->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; - struct smb_direct_rdma_rw_msg *msg, *next_msg; + struct smbdirect_rw_io *msg, *next_msg; int i, ret; DECLARE_COMPLETION_ONSTACK(completion); struct ib_send_wr *first_wr; @@ -1444,7 +1435,7 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, desc_buf_len = le32_to_cpu(desc[i].length); - msg->t = t; + msg->socket = sc; msg->cqe.done = is_read ? read_done : write_done; msg->completion = &completion; @@ -1466,7 +1457,7 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, goto out; } - ret = rdma_rw_ctx_init(&msg->rw_ctx, sc->ib.qp, sc->ib.qp->port, + ret = rdma_rw_ctx_init(&msg->rdma_ctx, sc->ib.qp, sc->ib.qp->port, msg->sgt.sgl, get_buf_page_count(desc_buf, desc_buf_len), 0, @@ -1487,7 +1478,7 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, /* concatenate work requests of rdma_rw_ctxs */ first_wr = NULL; list_for_each_entry_reverse(msg, &msg_list, list) { - first_wr = rdma_rw_ctx_wrs(&msg->rw_ctx, sc->ib.qp, sc->ib.qp->port, + first_wr = rdma_rw_ctx_wrs(&msg->rdma_ctx, sc->ib.qp, sc->ib.qp->port, &msg->cqe, first_wr); } @@ -1497,9 +1488,9 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, goto out; } - msg = list_last_entry(&msg_list, struct smb_direct_rdma_rw_msg, list); + msg = list_last_entry(&msg_list, struct smbdirect_rw_io, list); wait_for_completion(&completion); - ret = msg->status; + ret = msg->error; out: list_for_each_entry_safe(msg, next_msg, &msg_list, list) { list_del(&msg->list); From 113ed9d56f63d2e4eb3d74002c3d91de1e7a3485 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 14 Aug 2025 15:50:05 +0200 Subject: [PATCH 113/159] smb: server: take the recv_credit_target from the negotiate req and always limit the range The clients sends the initial recv_credit_target in the negotiate req, so we should use that. We also limit the range between 1 and our local defined sp->recv_credit_max. This will simplify further logic changes. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 33ce90b15de5..283f06cf4938 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -94,7 +94,7 @@ struct smb_direct_transport { spinlock_t receive_credit_lock; int recv_credits; - int recv_credit_target; + u16 recv_credit_target; spinlock_t lock_new_recv_credits; int new_recv_credits; @@ -515,7 +515,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) struct smbdirect_data_transfer *data_transfer = (struct smbdirect_data_transfer *)recvmsg->packet; u32 remaining_data_length, data_offset, data_length; - int old_recv_credit_target; + u16 old_recv_credit_target; if (wc->byte_len < offsetof(struct smbdirect_data_transfer, padding)) { @@ -559,6 +559,10 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) old_recv_credit_target = t->recv_credit_target; t->recv_credit_target = le16_to_cpu(data_transfer->credits_requested); + t->recv_credit_target = + min_t(u16, t->recv_credit_target, sp->recv_credit_max); + t->recv_credit_target = + max_t(u16, t->recv_credit_target, 1); atomic_add(le16_to_cpu(data_transfer->credits_granted), &sc->send_io.credits.count); @@ -1823,7 +1827,7 @@ static int smb_direct_init_params(struct smb_direct_transport *t, t->recv_credits = 0; sp->recv_credit_max = smb_direct_receive_credit_max; - t->recv_credit_target = 10; + t->recv_credit_target = 1; t->new_recv_credits = 0; sp->send_credit_target = smb_direct_send_credit_target; @@ -2049,6 +2053,9 @@ static int smb_direct_prepare(struct ksmbd_transport *t) le32_to_cpu(req->max_fragmented_size); sp->max_fragmented_recv_size = (sp->recv_credit_max * sp->max_recv_size) / 2; + st->recv_credit_target = le16_to_cpu(req->credits_requested); + st->recv_credit_target = min_t(u16, st->recv_credit_target, sp->recv_credit_max); + st->recv_credit_target = max_t(u16, st->recv_credit_target, 1); ret = smb_direct_send_negotiate_response(st, ret); out: From 89b021a72663c4d96d8a8b85272bb42d991a1c6f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 14 Aug 2025 16:05:47 +0200 Subject: [PATCH 114/159] smb: server: manage recv credits by counting posted recv_io and granted credits (At least for me) the logic maintaining the count of posted recv_io messages and the count of granted credits is much easier to understand. From there we can easily calculate the number of new_credits we'll grant to the peer in outgoing send_io messages. This will simplify the move to common logic that can be shared between client and server in the following patches. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 53 ++++++++++++++-------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 283f06cf4938..bd6d927e9656 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -92,13 +92,10 @@ struct smb_direct_transport { struct smbdirect_socket socket; - spinlock_t receive_credit_lock; - int recv_credits; + atomic_t recv_credits; u16 recv_credit_target; - spinlock_t lock_new_recv_credits; - int new_recv_credits; - + atomic_t recv_posted; struct work_struct post_recv_credits_work; struct work_struct send_immediate_work; @@ -309,9 +306,8 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) sc->ib.dev = sc->rdma.cm_id->device; - spin_lock_init(&t->receive_credit_lock); - - spin_lock_init(&t->lock_new_recv_credits); + atomic_set(&t->recv_posted, 0); + atomic_set(&t->recv_credits, 0); INIT_WORK(&t->post_recv_credits_work, smb_direct_post_recv_credits); @@ -552,9 +548,8 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) sc->recv_io.reassembly.full_packet_received = true; } - spin_lock(&t->receive_credit_lock); - t->recv_credits -= 1; - spin_unlock(&t->receive_credit_lock); + atomic_dec(&t->recv_posted); + atomic_dec(&t->recv_credits); old_recv_credit_target = t->recv_credit_target; t->recv_credit_target = @@ -758,14 +753,10 @@ static void smb_direct_post_recv_credits(struct work_struct *work) struct smb_direct_transport *t = container_of(work, struct smb_direct_transport, post_recv_credits_work); struct smbdirect_recv_io *recvmsg; - int receive_credits, credits = 0; + int credits = 0; int ret; - spin_lock(&t->receive_credit_lock); - receive_credits = t->recv_credits; - spin_unlock(&t->receive_credit_lock); - - if (receive_credits < t->recv_credit_target) { + if (atomic_read(&t->recv_credits) < t->recv_credit_target) { while (true) { recvmsg = get_free_recvmsg(t); if (!recvmsg) @@ -780,17 +771,11 @@ static void smb_direct_post_recv_credits(struct work_struct *work) break; } credits++; + + atomic_inc(&t->recv_posted); } } - spin_lock(&t->receive_credit_lock); - t->recv_credits += credits; - spin_unlock(&t->receive_credit_lock); - - spin_lock(&t->lock_new_recv_credits); - t->new_recv_credits += credits; - spin_unlock(&t->lock_new_recv_credits); - if (credits) queue_work(smb_direct_wq, &t->send_immediate_work); } @@ -837,11 +822,18 @@ static int manage_credits_prior_sending(struct smb_direct_transport *t) { int new_credits; - spin_lock(&t->lock_new_recv_credits); - new_credits = t->new_recv_credits; - t->new_recv_credits = 0; - spin_unlock(&t->lock_new_recv_credits); + if (atomic_read(&t->recv_credits) >= t->recv_credit_target) + return 0; + new_credits = atomic_read(&t->recv_posted); + if (new_credits == 0) + return 0; + + new_credits -= atomic_read(&t->recv_credits); + if (new_credits <= 0) + return 0; + + atomic_add(new_credits, &t->recv_credits); return new_credits; } @@ -1824,11 +1816,8 @@ static int smb_direct_init_params(struct smb_direct_transport *t, return -EINVAL; } - t->recv_credits = 0; - sp->recv_credit_max = smb_direct_receive_credit_max; t->recv_credit_target = 1; - t->new_recv_credits = 0; sp->send_credit_target = smb_direct_send_credit_target; atomic_set(&sc->rw_io.credits.count, sc->rw_io.credits.max); From e8bc71986cbd2d2d5991a2fc6afbac0311ff3769 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 14 Aug 2025 16:33:30 +0200 Subject: [PATCH 115/159] smb: server: make use of smbdirect_socket.recv_io.{posted,credits} This will make it possible to introduce common helper functions in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 65 ++++++++++++++++------------------ 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index bd6d927e9656..b2de5311a066 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -92,11 +92,6 @@ struct smb_direct_transport { struct smbdirect_socket socket; - atomic_t recv_credits; - u16 recv_credit_target; - - atomic_t recv_posted; - struct work_struct post_recv_credits_work; struct work_struct send_immediate_work; bool legacy_iwarp; @@ -180,7 +175,7 @@ static void put_recvmsg(struct smb_direct_transport *t, list_add(&recvmsg->list, &sc->recv_io.free.list); spin_unlock(&sc->recv_io.free.lock); - queue_work(smb_direct_wq, &t->post_recv_credits_work); + queue_work(smb_direct_wq, &sc->recv_io.posted.refill_work); } static void enqueue_reassembly(struct smb_direct_transport *t, @@ -227,7 +222,7 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work) * disable[_delayed]_work_sync() */ disable_work(&sc->disconnect_work); - disable_work(&t->post_recv_credits_work); + disable_work(&sc->recv_io.posted.refill_work); disable_work(&t->send_immediate_work); switch (sc->status) { @@ -306,10 +301,7 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) sc->ib.dev = sc->rdma.cm_id->device; - atomic_set(&t->recv_posted, 0); - atomic_set(&t->recv_credits, 0); - - INIT_WORK(&t->post_recv_credits_work, + INIT_WORK(&sc->recv_io.posted.refill_work, smb_direct_post_recv_credits); INIT_WORK(&t->send_immediate_work, smb_direct_send_immediate_work); @@ -345,7 +337,7 @@ static void free_transport(struct smb_direct_transport *t) wake_up_all(&sc->send_io.credits.wait_queue); wake_up_all(&sc->send_io.pending.zero_wait_queue); - disable_work_sync(&t->post_recv_credits_work); + disable_work_sync(&sc->recv_io.posted.refill_work); disable_work_sync(&t->send_immediate_work); if (sc->ib.qp) { @@ -548,16 +540,16 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) sc->recv_io.reassembly.full_packet_received = true; } - atomic_dec(&t->recv_posted); - atomic_dec(&t->recv_credits); + atomic_dec(&sc->recv_io.posted.count); + atomic_dec(&sc->recv_io.credits.count); - old_recv_credit_target = t->recv_credit_target; - t->recv_credit_target = + old_recv_credit_target = sc->recv_io.credits.target; + sc->recv_io.credits.target = le16_to_cpu(data_transfer->credits_requested); - t->recv_credit_target = - min_t(u16, t->recv_credit_target, sp->recv_credit_max); - t->recv_credit_target = - max_t(u16, t->recv_credit_target, 1); + sc->recv_io.credits.target = + min_t(u16, sc->recv_io.credits.target, sp->recv_credit_max); + sc->recv_io.credits.target = + max_t(u16, sc->recv_io.credits.target, 1); atomic_add(le16_to_cpu(data_transfer->credits_granted), &sc->send_io.credits.count); @@ -569,8 +561,8 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) wake_up(&sc->send_io.credits.wait_queue); if (data_length) { - if (t->recv_credit_target > old_recv_credit_target) - queue_work(smb_direct_wq, &t->post_recv_credits_work); + if (sc->recv_io.credits.target > old_recv_credit_target) + queue_work(smb_direct_wq, &sc->recv_io.posted.refill_work); enqueue_reassembly(t, recvmsg, (int)data_length); wake_up(&sc->recv_io.reassembly.wait_queue); @@ -750,13 +742,15 @@ static int smb_direct_read(struct ksmbd_transport *t, char *buf, static void smb_direct_post_recv_credits(struct work_struct *work) { - struct smb_direct_transport *t = container_of(work, - struct smb_direct_transport, post_recv_credits_work); + struct smbdirect_socket *sc = + container_of(work, struct smbdirect_socket, recv_io.posted.refill_work); + struct smb_direct_transport *t = + container_of(sc, struct smb_direct_transport, socket); struct smbdirect_recv_io *recvmsg; int credits = 0; int ret; - if (atomic_read(&t->recv_credits) < t->recv_credit_target) { + if (atomic_read(&sc->recv_io.credits.count) < sc->recv_io.credits.target) { while (true) { recvmsg = get_free_recvmsg(t); if (!recvmsg) @@ -772,7 +766,7 @@ static void smb_direct_post_recv_credits(struct work_struct *work) } credits++; - atomic_inc(&t->recv_posted); + atomic_inc(&sc->recv_io.posted.count); } } @@ -820,20 +814,21 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc) static int manage_credits_prior_sending(struct smb_direct_transport *t) { + struct smbdirect_socket *sc = &t->socket; int new_credits; - if (atomic_read(&t->recv_credits) >= t->recv_credit_target) + if (atomic_read(&sc->recv_io.credits.count) >= sc->recv_io.credits.target) return 0; - new_credits = atomic_read(&t->recv_posted); + new_credits = atomic_read(&sc->recv_io.posted.count); if (new_credits == 0) return 0; - new_credits -= atomic_read(&t->recv_credits); + new_credits -= atomic_read(&sc->recv_io.credits.count); if (new_credits <= 0) return 0; - atomic_add(new_credits, &t->recv_credits); + atomic_add(new_credits, &sc->recv_io.credits.count); return new_credits; } @@ -1729,7 +1724,7 @@ static int smb_direct_prepare_negotiation(struct smb_direct_transport *t) goto out_err; } - smb_direct_post_recv_credits(&t->post_recv_credits_work); + smb_direct_post_recv_credits(&sc->recv_io.posted.refill_work); return 0; out_err: put_recvmsg(t, recvmsg); @@ -1817,7 +1812,7 @@ static int smb_direct_init_params(struct smb_direct_transport *t, } sp->recv_credit_max = smb_direct_receive_credit_max; - t->recv_credit_target = 1; + sc->recv_io.credits.target = 1; sp->send_credit_target = smb_direct_send_credit_target; atomic_set(&sc->rw_io.credits.count, sc->rw_io.credits.max); @@ -2042,9 +2037,9 @@ static int smb_direct_prepare(struct ksmbd_transport *t) le32_to_cpu(req->max_fragmented_size); sp->max_fragmented_recv_size = (sp->recv_credit_max * sp->max_recv_size) / 2; - st->recv_credit_target = le16_to_cpu(req->credits_requested); - st->recv_credit_target = min_t(u16, st->recv_credit_target, sp->recv_credit_max); - st->recv_credit_target = max_t(u16, st->recv_credit_target, 1); + sc->recv_io.credits.target = le16_to_cpu(req->credits_requested); + sc->recv_io.credits.target = min_t(u16, sc->recv_io.credits.target, sp->recv_credit_max); + sc->recv_io.credits.target = max_t(u16, sc->recv_io.credits.target, 1); ret = smb_direct_send_negotiate_response(st, ret); out: From 4d2e333dabe74349d257ca2f02225e4bc39f23b8 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 15 Aug 2025 13:01:30 +0200 Subject: [PATCH 116/159] smb: server: replace smb_trans_direct_transfort() with SMBD_TRANS() The spelling of smb_trans_direct_transfort was wrong anyway and we don't need the logic twice. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index b2de5311a066..11fed588fcc0 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -129,12 +129,6 @@ static int smb_direct_post_send_data(struct smb_direct_transport *t, struct kvec *iov, int niov, int remaining_data_length); -static inline struct smb_direct_transport * -smb_trans_direct_transfort(struct ksmbd_transport *t) -{ - return container_of(t, struct smb_direct_transport, transport); -} - static inline void *smbdirect_recv_io_payload(struct smbdirect_recv_io *recvmsg) { @@ -629,7 +623,7 @@ static int smb_direct_read(struct ksmbd_transport *t, char *buf, int to_copy, to_read, data_read, offset; u32 data_length, remaining_data_length, data_offset; int rc; - struct smb_direct_transport *st = smb_trans_direct_transfort(t); + struct smb_direct_transport *st = SMBD_TRANS(t); struct smbdirect_socket *sc = &st->socket; again: @@ -1175,7 +1169,7 @@ static int smb_direct_writev(struct ksmbd_transport *t, struct kvec *iov, int niovs, int buflen, bool need_invalidate, unsigned int remote_key) { - struct smb_direct_transport *st = smb_trans_direct_transfort(t); + struct smb_direct_transport *st = SMBD_TRANS(t); struct smbdirect_socket *sc = &st->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; size_t remaining_data_length; @@ -1498,7 +1492,7 @@ static int smb_direct_rdma_write(struct ksmbd_transport *t, struct smbdirect_buffer_descriptor_v1 *desc, unsigned int desc_len) { - return smb_direct_rdma_xmit(smb_trans_direct_transfort(t), buf, buflen, + return smb_direct_rdma_xmit(SMBD_TRANS(t), buf, buflen, desc, desc_len, false); } @@ -1507,13 +1501,13 @@ static int smb_direct_rdma_read(struct ksmbd_transport *t, struct smbdirect_buffer_descriptor_v1 *desc, unsigned int desc_len) { - return smb_direct_rdma_xmit(smb_trans_direct_transfort(t), buf, buflen, + return smb_direct_rdma_xmit(SMBD_TRANS(t), buf, buflen, desc, desc_len, true); } static void smb_direct_disconnect(struct ksmbd_transport *t) { - struct smb_direct_transport *st = smb_trans_direct_transfort(t); + struct smb_direct_transport *st = SMBD_TRANS(t); struct smbdirect_socket *sc = &st->socket; ksmbd_debug(RDMA, "Disconnecting cm_id=%p\n", sc->rdma.cm_id); @@ -1523,7 +1517,7 @@ static void smb_direct_disconnect(struct ksmbd_transport *t) static void smb_direct_shutdown(struct ksmbd_transport *t) { - struct smb_direct_transport *st = smb_trans_direct_transfort(t); + struct smb_direct_transport *st = SMBD_TRANS(t); struct smbdirect_socket *sc = &st->socket; ksmbd_debug(RDMA, "smb-direct shutdown cm_id=%p\n", sc->rdma.cm_id); @@ -1992,7 +1986,7 @@ static int smb_direct_create_qpair(struct smb_direct_transport *t, static int smb_direct_prepare(struct ksmbd_transport *t) { - struct smb_direct_transport *st = smb_trans_direct_transfort(t); + struct smb_direct_transport *st = SMBD_TRANS(t); struct smbdirect_socket *sc = &st->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; struct smbdirect_recv_io *recvmsg; From 341b6c69b959a901b167a33b7e62e8b2ff8a1e74 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 15 Aug 2025 13:04:31 +0200 Subject: [PATCH 117/159] smb: server: remove useless casts from KSMBD_TRANS/SMBD_TRANS At best they gain nothing, at worst we procude real bugs. Note container_of() already casts to a pointer of the given type. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 11fed588fcc0..0abcf2991c3c 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -99,8 +99,8 @@ struct smb_direct_transport { u8 responder_resources; }; -#define KSMBD_TRANS(t) ((struct ksmbd_transport *)&((t)->transport)) -#define SMBD_TRANS(t) ((struct smb_direct_transport *)container_of(t, \ +#define KSMBD_TRANS(t) (&(t)->transport) +#define SMBD_TRANS(t) (container_of(t, \ struct smb_direct_transport, transport)) static const struct ksmbd_transport_ops ksmbd_smb_direct_transport_ops; From 03a38d846750f06d4fb0aac2213192bdcc2a8435 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 15 Aug 2025 12:03:40 +0200 Subject: [PATCH 118/159] smb: server: pass ksmbd_transport to get_smbd_max_read_write_size() We should use the per connection value. And for TCP return NT_STATUS_INVALID_PARAMETER if any SMB2_CHANNEL_RDMA_V1* is used. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2pdu.c | 12 ++++++++++-- fs/smb/server/transport_rdma.c | 15 +++++++++++++-- fs/smb/server/transport_rdma.h | 4 ++-- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 00e644935f28..0c069eff80b7 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -6762,7 +6762,11 @@ int smb2_read(struct ksmbd_work *work) if (req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE || req->Channel == SMB2_CHANNEL_RDMA_V1) { is_rdma_channel = true; - max_read_size = get_smbd_max_read_write_size(); + max_read_size = get_smbd_max_read_write_size(work->conn->transport); + if (max_read_size == 0) { + err = -EINVAL; + goto out; + } } if (is_rdma_channel == true) { @@ -7020,7 +7024,11 @@ int smb2_write(struct ksmbd_work *work) if (req->Channel == SMB2_CHANNEL_RDMA_V1 || req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE) { is_rdma_channel = true; - max_write_size = get_smbd_max_read_write_size(); + max_write_size = get_smbd_max_read_write_size(work->conn->transport); + if (max_write_size == 0) { + err = -EINVAL; + goto out; + } length = le32_to_cpu(req->RemainingBytes); } diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 0abcf2991c3c..d970a4956533 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -111,9 +111,20 @@ void init_smbd_max_io_size(unsigned int sz) smb_direct_max_read_write_size = sz; } -unsigned int get_smbd_max_read_write_size(void) +unsigned int get_smbd_max_read_write_size(struct ksmbd_transport *kt) { - return smb_direct_max_read_write_size; + struct smb_direct_transport *t; + struct smbdirect_socket *sc; + struct smbdirect_socket_parameters *sp; + + if (kt->ops != &ksmbd_smb_direct_transport_ops) + return 0; + + t = SMBD_TRANS(kt); + sc = &t->socket; + sp = &sc->parameters; + + return sp->max_read_write_size; } static inline int get_buf_page_count(void *buf, int size) diff --git a/fs/smb/server/transport_rdma.h b/fs/smb/server/transport_rdma.h index 63eab9f8f13d..3f93c6a9f7e4 100644 --- a/fs/smb/server/transport_rdma.h +++ b/fs/smb/server/transport_rdma.h @@ -17,14 +17,14 @@ void ksmbd_rdma_stop_listening(void); void ksmbd_rdma_destroy(void); bool ksmbd_rdma_capable_netdev(struct net_device *netdev); void init_smbd_max_io_size(unsigned int sz); -unsigned int get_smbd_max_read_write_size(void); +unsigned int get_smbd_max_read_write_size(struct ksmbd_transport *kt); #else static inline int ksmbd_rdma_init(void) { return 0; } static inline void ksmbd_rdma_stop_listening(void) { } static inline void ksmbd_rdma_destroy(void) { } static inline bool ksmbd_rdma_capable_netdev(struct net_device *netdev) { return false; } static inline void init_smbd_max_io_size(unsigned int sz) { } -static inline unsigned int get_smbd_max_read_write_size(void) { return 0; } +static inline unsigned int get_smbd_max_read_write_size(struct ksmbd_transport *kt) { return 0; } #endif #endif /* __KSMBD_TRANSPORT_RDMA_H__ */ From d70e45823961e13af10f44a6a16c5c5a357ccdfb Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 15 Aug 2025 12:22:09 +0200 Subject: [PATCH 119/159] smb: server: fill smbdirect_socket_parameters at the beginning and use the values from there This is what we should do and it also simplifies the following changes. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index d970a4956533..0367db232ea8 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -288,6 +288,7 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) { struct smb_direct_transport *t; struct smbdirect_socket *sc; + struct smbdirect_socket_parameters *sp; struct ksmbd_conn *conn; t = kzalloc(sizeof(*t), KSMBD_DEFAULT_GFP); @@ -295,9 +296,17 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) return NULL; sc = &t->socket; smbdirect_socket_init(sc); + sp = &sc->parameters; INIT_WORK(&sc->disconnect_work, smb_direct_disconnect_rdma_work); + sp->recv_credit_max = smb_direct_receive_credit_max; + sp->send_credit_target = smb_direct_send_credit_target; + sp->max_send_size = smb_direct_max_send_size; + sp->max_fragmented_recv_size = smb_direct_max_fragmented_recv_size; + sp->max_recv_size = smb_direct_max_receive_size; + sp->max_read_write_size = smb_direct_max_read_write_size; + sc->rdma.cm_id = cm_id; cm_id->context = t; @@ -1757,7 +1766,6 @@ static int smb_direct_init_params(struct smb_direct_transport *t, /* need 3 more sge. because a SMB_DIRECT header, SMB2 header, * SMB2 response could be mapped. */ - sp->max_send_size = smb_direct_max_send_size; max_send_sges = DIV_ROUND_UP(sp->max_send_size, PAGE_SIZE) + 3; if (max_send_sges > SMBDIRECT_SEND_IO_MAX_SGE) { pr_err("max_send_size %d is too large\n", sp->max_send_size); @@ -1771,7 +1779,6 @@ static int smb_direct_init_params(struct smb_direct_transport *t, * are needed for MR registration, RDMA R/W, local & remote * MR invalidation. */ - sp->max_read_write_size = smb_direct_max_read_write_size; sc->rw_io.credits.num_pages = smb_direct_get_max_fr_pages(t); sc->rw_io.credits.max = DIV_ROUND_UP(sp->max_read_write_size, (sc->rw_io.credits.num_pages - 1) * @@ -1786,20 +1793,20 @@ static int smb_direct_init_params(struct smb_direct_transport *t, max_sge_per_wr) + 1); max_rw_wrs = sc->rw_io.credits.max * wrs_per_credit; - max_send_wrs = smb_direct_send_credit_target + max_rw_wrs; + max_send_wrs = sp->send_credit_target + max_rw_wrs; if (max_send_wrs > device->attrs.max_cqe || max_send_wrs > device->attrs.max_qp_wr) { pr_err("consider lowering send_credit_target = %d\n", - smb_direct_send_credit_target); + sp->send_credit_target); pr_err("Possible CQE overrun, device reporting max_cqe %d max_qp_wr %d\n", device->attrs.max_cqe, device->attrs.max_qp_wr); return -EINVAL; } - if (smb_direct_receive_credit_max > device->attrs.max_cqe || - smb_direct_receive_credit_max > device->attrs.max_qp_wr) { + if (sp->recv_credit_max > device->attrs.max_cqe || + sp->recv_credit_max > device->attrs.max_qp_wr) { pr_err("consider lowering receive_credit_max = %d\n", - smb_direct_receive_credit_max); + sp->recv_credit_max); pr_err("Possible CQE overrun, device reporting max_cpe %d max_qp_wr %d\n", device->attrs.max_cqe, device->attrs.max_qp_wr); return -EINVAL; @@ -1816,16 +1823,10 @@ static int smb_direct_init_params(struct smb_direct_transport *t, return -EINVAL; } - sp->recv_credit_max = smb_direct_receive_credit_max; sc->recv_io.credits.target = 1; - sp->send_credit_target = smb_direct_send_credit_target; atomic_set(&sc->rw_io.credits.count, sc->rw_io.credits.max); - sp->max_send_size = smb_direct_max_send_size; - sp->max_recv_size = smb_direct_max_receive_size; - sp->max_fragmented_recv_size = smb_direct_max_fragmented_recv_size; - cap->max_send_wr = max_send_wrs; cap->max_recv_wr = sp->recv_credit_max; cap->max_send_sge = SMBDIRECT_SEND_IO_MAX_SGE; @@ -1925,7 +1926,7 @@ static int smb_direct_create_qpair(struct smb_direct_transport *t, } sc->ib.send_cq = ib_alloc_cq(sc->ib.dev, t, - smb_direct_send_credit_target + cap->max_rdma_ctxs, + sp->send_credit_target + cap->max_rdma_ctxs, 0, IB_POLL_WORKQUEUE); if (IS_ERR(sc->ib.send_cq)) { pr_err("Can't create RDMA send CQ\n"); From be3c1d032fad608f48b428854694422633c4b004 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 15 Aug 2025 12:31:50 +0200 Subject: [PATCH 120/159] smb: server: make use of smbdirect_socket_parameters.negotiate_timeout_msec and change to 5s The server negotiations timer is just 5 seconds in Windows, so use the same. See [MS-SMBD] 3.1.7.2 Connection Arrival. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 0367db232ea8..7d3cf1d22af0 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -33,8 +33,8 @@ #define SMB_DIRECT_VERSION_LE cpu_to_le16(SMBDIRECT_V1) -/* SMB_DIRECT negotiation timeout in seconds */ -#define SMB_DIRECT_NEGOTIATE_TIMEOUT 120 +/* SMB_DIRECT negotiation timeout (for the server) in seconds */ +#define SMB_DIRECT_NEGOTIATE_TIMEOUT 5 /* * Default maximum number of RDMA read/write outstanding on this connection @@ -300,6 +300,7 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) INIT_WORK(&sc->disconnect_work, smb_direct_disconnect_rdma_work); + sp->negotiate_timeout_msec = SMB_DIRECT_NEGOTIATE_TIMEOUT * 1000; sp->recv_credit_max = smb_direct_receive_credit_max; sp->send_credit_target = smb_direct_send_credit_target; sp->max_send_size = smb_direct_max_send_size; @@ -2022,7 +2023,7 @@ static int smb_direct_prepare(struct ksmbd_transport *t) sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED && sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING && sc->status != SMBDIRECT_SOCKET_NEGOTIATE_NEEDED, - SMB_DIRECT_NEGOTIATE_TIMEOUT * HZ); + msecs_to_jiffies(sp->negotiate_timeout_msec)); if (ret <= 0 || sc->status != SMBDIRECT_SOCKET_NEGOTIATE_RUNNING) return ret < 0 ? ret : -ETIMEDOUT; From 49635103e8e68020d80122b9ec408dbbd295d351 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 Aug 2025 12:30:32 +0200 Subject: [PATCH 121/159] smb: server: make use of smbdirect_socket_parameters.{initiator_depth,responder_resources} This will make it easier to specify these from the outside of the core code first and then negotiate the value with the peer. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 7d3cf1d22af0..98b1d6453df8 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -95,8 +95,6 @@ struct smb_direct_transport { struct work_struct send_immediate_work; bool legacy_iwarp; - u8 initiator_depth; - u8 responder_resources; }; #define KSMBD_TRANS(t) (&(t)->transport) @@ -301,6 +299,8 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) INIT_WORK(&sc->disconnect_work, smb_direct_disconnect_rdma_work); sp->negotiate_timeout_msec = SMB_DIRECT_NEGOTIATE_TIMEOUT * 1000; + sp->initiator_depth = SMB_DIRECT_CM_INITIATOR_DEPTH; + sp->responder_resources = 1; sp->recv_credit_max = smb_direct_receive_credit_max; sp->send_credit_target = smb_direct_send_credit_target; sp->max_send_size = smb_direct_max_send_size; @@ -311,9 +311,6 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) sc->rdma.cm_id = cm_id; cm_id->context = t; - t->initiator_depth = SMB_DIRECT_CM_INITIATOR_DEPTH; - t->responder_resources = 1; - sc->ib.dev = sc->rdma.cm_id->device; INIT_WORK(&sc->recv_io.posted.refill_work, @@ -1676,18 +1673,19 @@ static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, static int smb_direct_accept_client(struct smb_direct_transport *t) { struct smbdirect_socket *sc = &t->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; struct rdma_conn_param conn_param; __be32 ird_ord_hdr[2]; int ret; /* * smb_direct_handle_connect_request() - * already negotiated t->initiator_depth - * and t->responder_resources + * already negotiated sp->initiator_depth + * and sp->responder_resources */ memset(&conn_param, 0, sizeof(conn_param)); - conn_param.initiator_depth = t->initiator_depth; - conn_param.responder_resources = t->responder_resources; + conn_param.initiator_depth = sp->initiator_depth; + conn_param.responder_resources = sp->responder_resources; if (t->legacy_iwarp) { ird_ord_hdr[0] = cpu_to_be32(conn_param.responder_resources); @@ -2103,6 +2101,8 @@ static int smb_direct_handle_connect_request(struct rdma_cm_id *new_cm_id, struct rdma_cm_event *event) { struct smb_direct_transport *t; + struct smbdirect_socket *sc; + struct smbdirect_socket_parameters *sp; struct task_struct *handler; u8 peer_initiator_depth; u8 peer_responder_resources; @@ -2118,6 +2118,8 @@ static int smb_direct_handle_connect_request(struct rdma_cm_id *new_cm_id, t = alloc_transport(new_cm_id); if (!t) return -ENOMEM; + sc = &t->socket; + sp = &sc->parameters; peer_initiator_depth = event->param.conn.initiator_depth; peer_responder_resources = event->param.conn.responder_resources; @@ -2165,7 +2167,7 @@ static int smb_direct_handle_connect_request(struct rdma_cm_id *new_cm_id, /* * First set what the we as server are able to support */ - t->initiator_depth = min_t(u8, t->initiator_depth, + sp->initiator_depth = min_t(u8, sp->initiator_depth, new_cm_id->device->attrs.max_qp_rd_atom); /* @@ -2174,10 +2176,10 @@ static int smb_direct_handle_connect_request(struct rdma_cm_id *new_cm_id, * non 0 values. */ if (peer_initiator_depth != 0) - t->initiator_depth = min_t(u8, t->initiator_depth, + sp->initiator_depth = min_t(u8, sp->initiator_depth, peer_initiator_depth); if (peer_responder_resources != 0) - t->responder_resources = min_t(u8, t->responder_resources, + sp->responder_resources = min_t(u8, sp->responder_resources, peer_responder_resources); ret = smb_direct_connect(t); From d0b9b967b35584379fd0421f408c77647e5d6b12 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 Aug 2025 12:32:05 +0200 Subject: [PATCH 122/159] smb: server: make use of smbdirect_socket.rdma.legacy_iwarp Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 98b1d6453df8..8cbbebb9f169 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -93,8 +93,6 @@ struct smb_direct_transport { struct smbdirect_socket socket; struct work_struct send_immediate_work; - - bool legacy_iwarp; }; #define KSMBD_TRANS(t) (&(t)->transport) @@ -1687,7 +1685,7 @@ static int smb_direct_accept_client(struct smb_direct_transport *t) conn_param.initiator_depth = sp->initiator_depth; conn_param.responder_resources = sp->responder_resources; - if (t->legacy_iwarp) { + if (sc->rdma.legacy_iwarp) { ird_ord_hdr[0] = cpu_to_be32(conn_param.responder_resources); ird_ord_hdr[1] = cpu_to_be32(conn_param.initiator_depth); conn_param.private_data = ird_ord_hdr; @@ -2158,7 +2156,7 @@ static int smb_direct_handle_connect_request(struct rdma_cm_id *new_cm_id, ird32 = min_t(u32, ird32, U8_MAX); ord32 = min_t(u32, ord32, U8_MAX); - t->legacy_iwarp = true; + sc->rdma.legacy_iwarp = true; peer_initiator_depth = (u8)ird32; peer_responder_resources = (u8)ord32; } From b8c7776583e72f1fc50f0ed561346954c5d2fe82 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 15 Aug 2025 18:00:36 +0200 Subject: [PATCH 123/159] smb: server: make use of smbdirect_socket.idle.immediate_work With this commit the server only uses struct smbdirect_socket! It doesn't use the idle timer yet, but it will be added soon, from there we'll be ready split common functions. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 8cbbebb9f169..3bb19b17abae 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -91,8 +91,6 @@ struct smb_direct_transport { struct ksmbd_transport transport; struct smbdirect_socket socket; - - struct work_struct send_immediate_work; }; #define KSMBD_TRANS(t) (&(t)->transport) @@ -214,8 +212,6 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work) { struct smbdirect_socket *sc = container_of(work, struct smbdirect_socket, disconnect_work); - struct smb_direct_transport *t = - container_of(sc, struct smb_direct_transport, socket); /* * make sure this and other work is not queued again @@ -224,7 +220,7 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work) */ disable_work(&sc->disconnect_work); disable_work(&sc->recv_io.posted.refill_work); - disable_work(&t->send_immediate_work); + disable_work(&sc->idle.immediate_work); switch (sc->status) { case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: @@ -270,9 +266,10 @@ smb_direct_disconnect_rdma_connection(struct smb_direct_transport *t) static void smb_direct_send_immediate_work(struct work_struct *work) { - struct smb_direct_transport *t = container_of(work, - struct smb_direct_transport, send_immediate_work); - struct smbdirect_socket *sc = &t->socket; + struct smbdirect_socket *sc = + container_of(work, struct smbdirect_socket, idle.immediate_work); + struct smb_direct_transport *t = + container_of(sc, struct smb_direct_transport, socket); if (sc->status != SMBDIRECT_SOCKET_CONNECTED) return; @@ -313,7 +310,7 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) INIT_WORK(&sc->recv_io.posted.refill_work, smb_direct_post_recv_credits); - INIT_WORK(&t->send_immediate_work, smb_direct_send_immediate_work); + INIT_WORK(&sc->idle.immediate_work, smb_direct_send_immediate_work); conn = ksmbd_conn_alloc(); if (!conn) @@ -348,7 +345,7 @@ static void free_transport(struct smb_direct_transport *t) wake_up_all(&sc->send_io.pending.zero_wait_queue); disable_work_sync(&sc->recv_io.posted.refill_work); - disable_work_sync(&t->send_immediate_work); + disable_work_sync(&sc->idle.immediate_work); if (sc->ib.qp) { ib_drain_qp(sc->ib.qp); @@ -565,7 +562,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) if (le16_to_cpu(data_transfer->flags) & SMBDIRECT_FLAG_RESPONSE_REQUESTED) - queue_work(smb_direct_wq, &t->send_immediate_work); + queue_work(smb_direct_wq, &sc->idle.immediate_work); if (atomic_read(&sc->send_io.credits.count) > 0) wake_up(&sc->send_io.credits.wait_queue); @@ -781,7 +778,7 @@ static void smb_direct_post_recv_credits(struct work_struct *work) } if (credits) - queue_work(smb_direct_wq, &t->send_immediate_work); + queue_work(smb_direct_wq, &sc->idle.immediate_work); } static void send_done(struct ib_cq *cq, struct ib_wc *wc) From 8ad3a97eab240dabbe41b4452d37a5b6b64edf72 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 15 Aug 2025 12:36:33 +0200 Subject: [PATCH 124/159] smb: server: implement correct keepalive and timeout handling for smbdirect Now client and server behave in the same way and we can start to share common functions. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 74 ++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 3bb19b17abae..0865ebb943d3 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -36,6 +36,12 @@ /* SMB_DIRECT negotiation timeout (for the server) in seconds */ #define SMB_DIRECT_NEGOTIATE_TIMEOUT 5 +/* The timeout to wait for a keepalive message from peer in seconds */ +#define SMB_DIRECT_KEEPALIVE_SEND_INTERVAL 120 + +/* The timeout to wait for a keepalive message from peer in seconds */ +#define SMB_DIRECT_KEEPALIVE_RECV_TIMEOUT 5 + /* * Default maximum number of RDMA read/write outstanding on this connection * This value is possibly decreased during QP creation on hardware limit @@ -220,6 +226,7 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work) */ disable_work(&sc->disconnect_work); disable_work(&sc->recv_io.posted.refill_work); + disable_delayed_work(&sc->idle.timer_work); disable_work(&sc->idle.immediate_work); switch (sc->status) { @@ -277,6 +284,32 @@ static void smb_direct_send_immediate_work(struct work_struct *work) smb_direct_post_send_data(t, NULL, NULL, 0, 0); } +static void smb_direct_idle_connection_timer(struct work_struct *work) +{ + struct smbdirect_socket *sc = + container_of(work, struct smbdirect_socket, idle.timer_work.work); + struct smbdirect_socket_parameters *sp = &sc->parameters; + struct smb_direct_transport *t = + container_of(sc, struct smb_direct_transport, socket); + + if (sc->idle.keepalive != SMBDIRECT_KEEPALIVE_NONE) { + smb_direct_disconnect_rdma_connection(t); + return; + } + + if (sc->status != SMBDIRECT_SOCKET_CONNECTED) + return; + + /* + * Now use the keepalive timeout (instead of keepalive interval) + * in order to wait for a response + */ + sc->idle.keepalive = SMBDIRECT_KEEPALIVE_PENDING; + mod_delayed_work(smb_direct_wq, &sc->idle.timer_work, + msecs_to_jiffies(sp->keepalive_timeout_msec)); + queue_work(smb_direct_wq, &sc->idle.immediate_work); +} + static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) { struct smb_direct_transport *t; @@ -302,6 +335,8 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) sp->max_fragmented_recv_size = smb_direct_max_fragmented_recv_size; sp->max_recv_size = smb_direct_max_receive_size; sp->max_read_write_size = smb_direct_max_read_write_size; + sp->keepalive_interval_msec = SMB_DIRECT_KEEPALIVE_SEND_INTERVAL * 1000; + sp->keepalive_timeout_msec = SMB_DIRECT_KEEPALIVE_RECV_TIMEOUT * 1000; sc->rdma.cm_id = cm_id; cm_id->context = t; @@ -311,6 +346,7 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) INIT_WORK(&sc->recv_io.posted.refill_work, smb_direct_post_recv_credits); INIT_WORK(&sc->idle.immediate_work, smb_direct_send_immediate_work); + INIT_DELAYED_WORK(&sc->idle.timer_work, smb_direct_idle_connection_timer); conn = ksmbd_conn_alloc(); if (!conn) @@ -345,6 +381,7 @@ static void free_transport(struct smb_direct_transport *t) wake_up_all(&sc->send_io.pending.zero_wait_queue); disable_work_sync(&sc->recv_io.posted.refill_work); + disable_delayed_work_sync(&sc->idle.timer_work); disable_work_sync(&sc->idle.immediate_work); if (sc->ib.qp) { @@ -493,6 +530,14 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) ib_dma_sync_single_for_cpu(wc->qp->device, recvmsg->sge.addr, recvmsg->sge.length, DMA_FROM_DEVICE); + /* + * Reset timer to the keepalive interval in + * order to trigger our next keepalive message. + */ + sc->idle.keepalive = SMBDIRECT_KEEPALIVE_NONE; + mod_delayed_work(smb_direct_wq, &sc->idle.timer_work, + msecs_to_jiffies(sp->keepalive_interval_msec)); + switch (sc->recv_io.expected) { case SMBDIRECT_EXPECT_NEGOTIATE_REQ: if (wc->byte_len < sizeof(struct smbdirect_negotiate_req)) { @@ -839,6 +884,24 @@ static int manage_credits_prior_sending(struct smb_direct_transport *t) return new_credits; } +static int manage_keep_alive_before_sending(struct smb_direct_transport *t) +{ + struct smbdirect_socket *sc = &t->socket; + struct smbdirect_socket_parameters *sp = &sc->parameters; + + if (sc->idle.keepalive == SMBDIRECT_KEEPALIVE_PENDING) { + sc->idle.keepalive = SMBDIRECT_KEEPALIVE_SENT; + /* + * Now use the keepalive timeout (instead of keepalive interval) + * in order to wait for a response + */ + mod_delayed_work(smb_direct_wq, &sc->idle.timer_work, + msecs_to_jiffies(sp->keepalive_timeout_msec)); + return 1; + } + return 0; +} + static int smb_direct_post_send(struct smb_direct_transport *t, struct ib_send_wr *wr) { @@ -987,6 +1050,9 @@ static int smb_direct_create_header(struct smb_direct_transport *t, packet->credits_granted = cpu_to_le16(manage_credits_prior_sending(t)); packet->flags = 0; + if (manage_keep_alive_before_sending(t)) + packet->flags |= cpu_to_le16(SMBDIRECT_FLAG_RESPONSE_REQUESTED); + packet->reserved = 0; if (!size) packet->data_offset = 0; @@ -1695,6 +1761,14 @@ static int smb_direct_accept_client(struct smb_direct_transport *t) conn_param.rnr_retry_count = SMB_DIRECT_CM_RNR_RETRY; conn_param.flow_control = 0; + /* + * start with the negotiate timeout and SMBDIRECT_KEEPALIVE_PENDING + * so that the timer will cause a disconnect. + */ + sc->idle.keepalive = SMBDIRECT_KEEPALIVE_PENDING; + mod_delayed_work(smb_direct_wq, &sc->idle.timer_work, + msecs_to_jiffies(sp->negotiate_timeout_msec)); + WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED); sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING; ret = rdma_accept(sc->rdma.cm_id, &conn_param); From da7d45b9a3858abc89030cf08368e59b2ab2bdd4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 12:32:48 +0200 Subject: [PATCH 125/159] smb: server: make use of smbdirect_socket.workqueue We still use the single global workqueue, but this will allow us to share common code soon. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 0865ebb943d3..bc05ac7366e6 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -180,7 +180,7 @@ static void put_recvmsg(struct smb_direct_transport *t, list_add(&recvmsg->list, &sc->recv_io.free.list); spin_unlock(&sc->recv_io.free.lock); - queue_work(smb_direct_wq, &sc->recv_io.posted.refill_work); + queue_work(sc->workqueue, &sc->recv_io.posted.refill_work); } static void enqueue_reassembly(struct smb_direct_transport *t, @@ -268,7 +268,7 @@ smb_direct_disconnect_rdma_connection(struct smb_direct_transport *t) { struct smbdirect_socket *sc = &t->socket; - queue_work(smb_direct_wq, &sc->disconnect_work); + queue_work(sc->workqueue, &sc->disconnect_work); } static void smb_direct_send_immediate_work(struct work_struct *work) @@ -305,9 +305,9 @@ static void smb_direct_idle_connection_timer(struct work_struct *work) * in order to wait for a response */ sc->idle.keepalive = SMBDIRECT_KEEPALIVE_PENDING; - mod_delayed_work(smb_direct_wq, &sc->idle.timer_work, + mod_delayed_work(sc->workqueue, &sc->idle.timer_work, msecs_to_jiffies(sp->keepalive_timeout_msec)); - queue_work(smb_direct_wq, &sc->idle.immediate_work); + queue_work(sc->workqueue, &sc->idle.immediate_work); } static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) @@ -324,6 +324,8 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) smbdirect_socket_init(sc); sp = &sc->parameters; + sc->workqueue = smb_direct_wq; + INIT_WORK(&sc->disconnect_work, smb_direct_disconnect_rdma_work); sp->negotiate_timeout_msec = SMB_DIRECT_NEGOTIATE_TIMEOUT * 1000; @@ -535,7 +537,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) * order to trigger our next keepalive message. */ sc->idle.keepalive = SMBDIRECT_KEEPALIVE_NONE; - mod_delayed_work(smb_direct_wq, &sc->idle.timer_work, + mod_delayed_work(sc->workqueue, &sc->idle.timer_work, msecs_to_jiffies(sp->keepalive_interval_msec)); switch (sc->recv_io.expected) { @@ -607,14 +609,14 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) if (le16_to_cpu(data_transfer->flags) & SMBDIRECT_FLAG_RESPONSE_REQUESTED) - queue_work(smb_direct_wq, &sc->idle.immediate_work); + queue_work(sc->workqueue, &sc->idle.immediate_work); if (atomic_read(&sc->send_io.credits.count) > 0) wake_up(&sc->send_io.credits.wait_queue); if (data_length) { if (sc->recv_io.credits.target > old_recv_credit_target) - queue_work(smb_direct_wq, &sc->recv_io.posted.refill_work); + queue_work(sc->workqueue, &sc->recv_io.posted.refill_work); enqueue_reassembly(t, recvmsg, (int)data_length); wake_up(&sc->recv_io.reassembly.wait_queue); @@ -823,7 +825,7 @@ static void smb_direct_post_recv_credits(struct work_struct *work) } if (credits) - queue_work(smb_direct_wq, &sc->idle.immediate_work); + queue_work(sc->workqueue, &sc->idle.immediate_work); } static void send_done(struct ib_cq *cq, struct ib_wc *wc) @@ -895,7 +897,7 @@ static int manage_keep_alive_before_sending(struct smb_direct_transport *t) * Now use the keepalive timeout (instead of keepalive interval) * in order to wait for a response */ - mod_delayed_work(smb_direct_wq, &sc->idle.timer_work, + mod_delayed_work(sc->workqueue, &sc->idle.timer_work, msecs_to_jiffies(sp->keepalive_timeout_msec)); return 1; } @@ -1766,7 +1768,7 @@ static int smb_direct_accept_client(struct smb_direct_transport *t) * so that the timer will cause a disconnect. */ sc->idle.keepalive = SMBDIRECT_KEEPALIVE_PENDING; - mod_delayed_work(smb_direct_wq, &sc->idle.timer_work, + mod_delayed_work(sc->workqueue, &sc->idle.timer_work, msecs_to_jiffies(sp->negotiate_timeout_msec)); WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED); From 01721df4e309e76866dd4d28b78e8683581e9e87 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 01:14:38 +0200 Subject: [PATCH 126/159] smb: server: pass struct smbdirect_socket to {get_free,put}_recvmsg() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 37 ++++++++++++++++------------------ 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index bc05ac7366e6..2e14905c1503 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -147,9 +147,8 @@ static inline void } static struct -smbdirect_recv_io *get_free_recvmsg(struct smb_direct_transport *t) +smbdirect_recv_io *get_free_recvmsg(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &t->socket; struct smbdirect_recv_io *recvmsg = NULL; spin_lock(&sc->recv_io.free.lock); @@ -163,11 +162,9 @@ smbdirect_recv_io *get_free_recvmsg(struct smb_direct_transport *t) return recvmsg; } -static void put_recvmsg(struct smb_direct_transport *t, +static void put_recvmsg(struct smbdirect_socket *sc, struct smbdirect_recv_io *recvmsg) { - struct smbdirect_socket *sc = &t->socket; - if (likely(recvmsg->sge.length != 0)) { ib_dma_unmap_single(sc->ib.dev, recvmsg->sge.addr, @@ -400,7 +397,7 @@ static void free_transport(struct smb_direct_transport *t) if (recvmsg) { list_del(&recvmsg->list); spin_unlock(&sc->recv_io.reassembly.lock); - put_recvmsg(t, recvmsg); + put_recvmsg(sc, recvmsg); } else { spin_unlock(&sc->recv_io.reassembly.lock); } @@ -515,7 +512,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) t = container_of(sc, struct smb_direct_transport, socket); if (wc->status != IB_WC_SUCCESS || wc->opcode != IB_WC_RECV) { - put_recvmsg(t, recvmsg); + put_recvmsg(sc, recvmsg); if (wc->status != IB_WC_WR_FLUSH_ERR) { pr_err("Recv error. status='%s (%d)' opcode=%d\n", ib_wc_status_msg(wc->status), wc->status, @@ -543,7 +540,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) switch (sc->recv_io.expected) { case SMBDIRECT_EXPECT_NEGOTIATE_REQ: if (wc->byte_len < sizeof(struct smbdirect_negotiate_req)) { - put_recvmsg(t, recvmsg); + put_recvmsg(sc, recvmsg); smb_direct_disconnect_rdma_connection(t); return; } @@ -561,7 +558,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) if (wc->byte_len < offsetof(struct smbdirect_data_transfer, padding)) { - put_recvmsg(t, recvmsg); + put_recvmsg(sc, recvmsg); smb_direct_disconnect_rdma_connection(t); return; } @@ -571,7 +568,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) data_offset = le32_to_cpu(data_transfer->data_offset); if (wc->byte_len < data_offset || wc->byte_len < (u64)data_offset + data_length) { - put_recvmsg(t, recvmsg); + put_recvmsg(sc, recvmsg); smb_direct_disconnect_rdma_connection(t); return; } @@ -579,7 +576,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) data_length > sp->max_fragmented_recv_size || (u64)remaining_data_length + (u64)data_length > (u64)sp->max_fragmented_recv_size) { - put_recvmsg(t, recvmsg); + put_recvmsg(sc, recvmsg); smb_direct_disconnect_rdma_connection(t); return; } @@ -621,7 +618,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) enqueue_reassembly(t, recvmsg, (int)data_length); wake_up(&sc->recv_io.reassembly.wait_queue); } else - put_recvmsg(t, recvmsg); + put_recvmsg(sc, recvmsg); return; } @@ -634,7 +631,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) * This is an internal error! */ WARN_ON_ONCE(sc->recv_io.expected != SMBDIRECT_EXPECT_DATA_TRANSFER); - put_recvmsg(t, recvmsg); + put_recvmsg(sc, recvmsg); smb_direct_disconnect_rdma_connection(t); } @@ -760,7 +757,7 @@ static int smb_direct_read(struct ksmbd_transport *t, char *buf, spin_unlock_irq(&sc->recv_io.reassembly.lock); } queue_removed++; - put_recvmsg(st, recvmsg); + put_recvmsg(sc, recvmsg); offset = 0; } else { offset += to_copy; @@ -806,7 +803,7 @@ static void smb_direct_post_recv_credits(struct work_struct *work) if (atomic_read(&sc->recv_io.credits.count) < sc->recv_io.credits.target) { while (true) { - recvmsg = get_free_recvmsg(t); + recvmsg = get_free_recvmsg(sc); if (!recvmsg) break; @@ -815,7 +812,7 @@ static void smb_direct_post_recv_credits(struct work_struct *work) ret = smb_direct_post_recv(t, recvmsg); if (ret) { pr_err("Can't post recv: %d\n", ret); - put_recvmsg(t, recvmsg); + put_recvmsg(sc, recvmsg); break; } credits++; @@ -1792,7 +1789,7 @@ static int smb_direct_prepare_negotiation(struct smb_direct_transport *t) sc->recv_io.expected = SMBDIRECT_EXPECT_NEGOTIATE_REQ; - recvmsg = get_free_recvmsg(t); + recvmsg = get_free_recvmsg(sc); if (!recvmsg) return -ENOMEM; @@ -1811,7 +1808,7 @@ static int smb_direct_prepare_negotiation(struct smb_direct_transport *t) smb_direct_post_recv_credits(&sc->recv_io.posted.refill_work); return 0; out_err: - put_recvmsg(t, recvmsg); + put_recvmsg(sc, recvmsg); return ret; } @@ -1911,7 +1908,7 @@ static void smb_direct_destroy_pools(struct smb_direct_transport *t) struct smbdirect_socket *sc = &t->socket; struct smbdirect_recv_io *recvmsg; - while ((recvmsg = get_free_recvmsg(t))) + while ((recvmsg = get_free_recvmsg(sc))) mempool_free(recvmsg, sc->recv_io.mem.pool); mempool_destroy(sc->recv_io.mem.pool); @@ -2123,7 +2120,7 @@ static int smb_direct_prepare(struct ksmbd_transport *t) sc->recv_io.reassembly.queue_length--; list_del(&recvmsg->list); spin_unlock_irq(&sc->recv_io.reassembly.lock); - put_recvmsg(st, recvmsg); + put_recvmsg(sc, recvmsg); return ret; } From ce85071d2cd63badaa71651033aa9f702ed36734 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 13:50:42 +0200 Subject: [PATCH 127/159] smb: server: pass struct smbdirect_socket to smb_direct_{create,destroy}_pools() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 2e14905c1503..7e1afe30ed3c 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -133,7 +133,7 @@ static inline int get_buf_page_count(void *buf, int size) (uintptr_t)buf / PAGE_SIZE; } -static void smb_direct_destroy_pools(struct smb_direct_transport *transport); +static void smb_direct_destroy_pools(struct smbdirect_socket *sc); static void smb_direct_post_recv_credits(struct work_struct *work); static int smb_direct_post_send_data(struct smb_direct_transport *t, struct smbdirect_send_batch *send_ctx, @@ -413,7 +413,7 @@ static void free_transport(struct smb_direct_transport *t) if (sc->rdma.cm_id) rdma_destroy_id(sc->rdma.cm_id); - smb_direct_destroy_pools(t); + smb_direct_destroy_pools(sc); ksmbd_conn_free(KSMBD_TRANS(t)->conn); } @@ -1903,9 +1903,8 @@ static int smb_direct_init_params(struct smb_direct_transport *t, return 0; } -static void smb_direct_destroy_pools(struct smb_direct_transport *t) +static void smb_direct_destroy_pools(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &t->socket; struct smbdirect_recv_io *recvmsg; while ((recvmsg = get_free_recvmsg(sc))) @@ -1924,15 +1923,14 @@ static void smb_direct_destroy_pools(struct smb_direct_transport *t) sc->send_io.mem.cache = NULL; } -static int smb_direct_create_pools(struct smb_direct_transport *t) +static int smb_direct_create_pools(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &t->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; char name[80]; int i; struct smbdirect_recv_io *recvmsg; - snprintf(name, sizeof(name), "smbdirect_send_io_pool_%p", t); + snprintf(name, sizeof(name), "smbdirect_send_io_pool_%p", sc); sc->send_io.mem.cache = kmem_cache_create(name, sizeof(struct smbdirect_send_io) + sizeof(struct smbdirect_negotiate_resp), @@ -1946,7 +1944,7 @@ static int smb_direct_create_pools(struct smb_direct_transport *t) if (!sc->send_io.mem.pool) goto err; - snprintf(name, sizeof(name), "smbdirect_recv_io_pool_%p", t); + snprintf(name, sizeof(name), "smbdirect_recv_io_pool_%p", sc); sc->recv_io.mem.cache = kmem_cache_create(name, sizeof(struct smbdirect_recv_io) + sp->max_recv_size, @@ -1971,7 +1969,7 @@ static int smb_direct_create_pools(struct smb_direct_transport *t) return 0; err: - smb_direct_destroy_pools(t); + smb_direct_destroy_pools(sc); return -ENOMEM; } @@ -2127,6 +2125,7 @@ static int smb_direct_prepare(struct ksmbd_transport *t) static int smb_direct_connect(struct smb_direct_transport *st) { + struct smbdirect_socket *sc = &st->socket; int ret; struct ib_qp_cap qp_cap; @@ -2136,7 +2135,7 @@ static int smb_direct_connect(struct smb_direct_transport *st) return ret; } - ret = smb_direct_create_pools(st); + ret = smb_direct_create_pools(sc); if (ret) { pr_err("Can't init RDMA pool: %d\n", ret); return ret; From 57131bf9e87677dcb64c8ce517c220b1fc403022 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 13:55:17 +0200 Subject: [PATCH 128/159] smb: server: pass struct smbdirect_socket to smb_direct_get_max_fr_pages() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 7e1afe30ed3c..547657e14544 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -1812,10 +1812,8 @@ static int smb_direct_prepare_negotiation(struct smb_direct_transport *t) return ret; } -static unsigned int smb_direct_get_max_fr_pages(struct smb_direct_transport *t) +static unsigned int smb_direct_get_max_fr_pages(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &t->socket; - return min_t(unsigned int, sc->ib.dev->attrs.max_fast_reg_page_list_len, 256); @@ -1846,7 +1844,7 @@ static int smb_direct_init_params(struct smb_direct_transport *t, * are needed for MR registration, RDMA R/W, local & remote * MR invalidation. */ - sc->rw_io.credits.num_pages = smb_direct_get_max_fr_pages(t); + sc->rw_io.credits.num_pages = smb_direct_get_max_fr_pages(sc); sc->rw_io.credits.max = DIV_ROUND_UP(sp->max_read_write_size, (sc->rw_io.credits.num_pages - 1) * PAGE_SIZE); From a25075f112b4bc02335d4df930409982405987f6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 14:04:34 +0200 Subject: [PATCH 129/159] smb: server: pass struct smbdirect_socket to smb_direct_init_params() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 547657e14544..ce2426ec5ec6 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -1819,10 +1819,9 @@ static unsigned int smb_direct_get_max_fr_pages(struct smbdirect_socket *sc) 256); } -static int smb_direct_init_params(struct smb_direct_transport *t, +static int smb_direct_init_params(struct smbdirect_socket *sc, struct ib_qp_cap *cap) { - struct smbdirect_socket *sc = &t->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; struct ib_device *device = sc->ib.dev; int max_send_sges, max_rw_wrs, max_send_wrs; @@ -2127,7 +2126,7 @@ static int smb_direct_connect(struct smb_direct_transport *st) int ret; struct ib_qp_cap qp_cap; - ret = smb_direct_init_params(st, &qp_cap); + ret = smb_direct_init_params(sc, &qp_cap); if (ret) { pr_err("Can't configure RDMA parameters\n"); return ret; From ece37ea815a70cd170d6922d33b7c9a7e8f2aa9e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 14:48:01 +0200 Subject: [PATCH 130/159] smb: server: pass struct smbdirect_socket to smb_direct_disconnect_rdma_connection() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index ce2426ec5ec6..acf3f8bba223 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -261,10 +261,8 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work) } static void -smb_direct_disconnect_rdma_connection(struct smb_direct_transport *t) +smb_direct_disconnect_rdma_connection(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &t->socket; - queue_work(sc->workqueue, &sc->disconnect_work); } @@ -286,11 +284,9 @@ static void smb_direct_idle_connection_timer(struct work_struct *work) struct smbdirect_socket *sc = container_of(work, struct smbdirect_socket, idle.timer_work.work); struct smbdirect_socket_parameters *sp = &sc->parameters; - struct smb_direct_transport *t = - container_of(sc, struct smb_direct_transport, socket); if (sc->idle.keepalive != SMBDIRECT_KEEPALIVE_NONE) { - smb_direct_disconnect_rdma_connection(t); + smb_direct_disconnect_rdma_connection(sc); return; } @@ -517,7 +513,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) pr_err("Recv error. status='%s (%d)' opcode=%d\n", ib_wc_status_msg(wc->status), wc->status, wc->opcode); - smb_direct_disconnect_rdma_connection(t); + smb_direct_disconnect_rdma_connection(sc); } return; } @@ -541,7 +537,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) case SMBDIRECT_EXPECT_NEGOTIATE_REQ: if (wc->byte_len < sizeof(struct smbdirect_negotiate_req)) { put_recvmsg(sc, recvmsg); - smb_direct_disconnect_rdma_connection(t); + smb_direct_disconnect_rdma_connection(sc); return; } sc->recv_io.reassembly.full_packet_received = true; @@ -559,7 +555,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) if (wc->byte_len < offsetof(struct smbdirect_data_transfer, padding)) { put_recvmsg(sc, recvmsg); - smb_direct_disconnect_rdma_connection(t); + smb_direct_disconnect_rdma_connection(sc); return; } @@ -569,7 +565,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) if (wc->byte_len < data_offset || wc->byte_len < (u64)data_offset + data_length) { put_recvmsg(sc, recvmsg); - smb_direct_disconnect_rdma_connection(t); + smb_direct_disconnect_rdma_connection(sc); return; } if (remaining_data_length > sp->max_fragmented_recv_size || @@ -577,7 +573,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) (u64)remaining_data_length + (u64)data_length > (u64)sp->max_fragmented_recv_size) { put_recvmsg(sc, recvmsg); - smb_direct_disconnect_rdma_connection(t); + smb_direct_disconnect_rdma_connection(sc); return; } @@ -632,7 +628,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) */ WARN_ON_ONCE(sc->recv_io.expected != SMBDIRECT_EXPECT_DATA_TRANSFER); put_recvmsg(sc, recvmsg); - smb_direct_disconnect_rdma_connection(t); + smb_direct_disconnect_rdma_connection(sc); } static int smb_direct_post_recv(struct smb_direct_transport *t, @@ -666,7 +662,7 @@ static int smb_direct_post_recv(struct smb_direct_transport *t, recvmsg->sge.addr, recvmsg->sge.length, DMA_FROM_DEVICE); recvmsg->sge.length = 0; - smb_direct_disconnect_rdma_connection(t); + smb_direct_disconnect_rdma_connection(sc); return ret; } return ret; @@ -844,7 +840,7 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc) pr_err("Send error. status='%s (%d)', opcode=%d\n", ib_wc_status_msg(wc->status), wc->status, wc->opcode); - smb_direct_disconnect_rdma_connection(t); + smb_direct_disconnect_rdma_connection(sc); } if (atomic_dec_and_test(&sc->send_io.pending.count)) @@ -913,7 +909,7 @@ static int smb_direct_post_send(struct smb_direct_transport *t, pr_err("failed to post send: %d\n", ret); if (atomic_dec_and_test(&sc->send_io.pending.count)) wake_up(&sc->send_io.pending.zero_wait_queue); - smb_direct_disconnect_rdma_connection(t); + smb_direct_disconnect_rdma_connection(sc); } return ret; } @@ -1409,15 +1405,13 @@ static void read_write_done(struct ib_cq *cq, struct ib_wc *wc, struct smbdirect_rw_io *msg = container_of(wc->wr_cqe, struct smbdirect_rw_io, cqe); struct smbdirect_socket *sc = msg->socket; - struct smb_direct_transport *t = - container_of(sc, struct smb_direct_transport, socket); if (wc->status != IB_WC_SUCCESS) { msg->error = -EIO; pr_err("read/write error. opcode = %d, status = %s(%d)\n", wc->opcode, ib_wc_status_msg(wc->status), wc->status); if (wc->status != IB_WC_WR_FLUSH_ERR) - smb_direct_disconnect_rdma_connection(t); + smb_direct_disconnect_rdma_connection(sc); } complete(msg->completion); @@ -1655,7 +1649,7 @@ static void smb_direct_qpair_handler(struct ib_event *event, void *context) switch (event->event) { case IB_EVENT_CQ_ERR: case IB_EVENT_QP_FATAL: - smb_direct_disconnect_rdma_connection(t); + smb_direct_disconnect_rdma_connection(sc); break; default: break; From 56227a7aa5c6e159205d79444833c0e2874dcc94 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 14:44:16 +0200 Subject: [PATCH 131/159] smb: server: pass struct smbdirect_socket to smb_direct_cm_handler() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index acf3f8bba223..8ca75afe082c 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -334,7 +334,7 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) sp->keepalive_timeout_msec = SMB_DIRECT_KEEPALIVE_RECV_TIMEOUT * 1000; sc->rdma.cm_id = cm_id; - cm_id->context = t; + cm_id->context = sc; sc->ib.dev = sc->rdma.cm_id->device; @@ -1600,8 +1600,7 @@ static void smb_direct_shutdown(struct ksmbd_transport *t) static int smb_direct_cm_handler(struct rdma_cm_id *cm_id, struct rdma_cm_event *event) { - struct smb_direct_transport *t = cm_id->context; - struct smbdirect_socket *sc = &t->socket; + struct smbdirect_socket *sc = cm_id->context; ksmbd_debug(RDMA, "RDMA CM event. cm_id=%p event=%s (%d)\n", cm_id, rdma_event_msg(event->event), event->event); From f75c226db0d29ee422f9b3ffd0a4730e6c552fbe Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 14:49:18 +0200 Subject: [PATCH 132/159] smb: server: pass struct smbdirect_socket to smb_direct_qpair_handler() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 8ca75afe082c..9ccc0930e99e 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -1639,8 +1639,7 @@ static int smb_direct_cm_handler(struct rdma_cm_id *cm_id, static void smb_direct_qpair_handler(struct ib_event *event, void *context) { - struct smb_direct_transport *t = context; - struct smbdirect_socket *sc = &t->socket; + struct smbdirect_socket *sc = context; ksmbd_debug(RDMA, "Received QP event. cm_id=%p, event=%s (%d)\n", sc->rdma.cm_id, ib_event_msg(event->event), event->event); @@ -1980,7 +1979,7 @@ static int smb_direct_create_qpair(struct smb_direct_transport *t, return ret; } - sc->ib.send_cq = ib_alloc_cq(sc->ib.dev, t, + sc->ib.send_cq = ib_alloc_cq(sc->ib.dev, sc, sp->send_credit_target + cap->max_rdma_ctxs, 0, IB_POLL_WORKQUEUE); if (IS_ERR(sc->ib.send_cq)) { @@ -1990,7 +1989,7 @@ static int smb_direct_create_qpair(struct smb_direct_transport *t, goto err; } - sc->ib.recv_cq = ib_alloc_cq(sc->ib.dev, t, + sc->ib.recv_cq = ib_alloc_cq(sc->ib.dev, sc, sp->recv_credit_max, 0, IB_POLL_WORKQUEUE); if (IS_ERR(sc->ib.recv_cq)) { pr_err("Can't create RDMA recv CQ\n"); @@ -2001,7 +2000,7 @@ static int smb_direct_create_qpair(struct smb_direct_transport *t, memset(&qp_attr, 0, sizeof(qp_attr)); qp_attr.event_handler = smb_direct_qpair_handler; - qp_attr.qp_context = t; + qp_attr.qp_context = sc; qp_attr.cap = *cap; qp_attr.sq_sig_type = IB_SIGNAL_REQ_WR; qp_attr.qp_type = IB_QPT_RC; From cf789396479593d4929bdfdc775a45c9b7482360 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 14:50:32 +0200 Subject: [PATCH 133/159] smb: server: pass struct smbdirect_socket to smb_direct_create_qpair() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 9ccc0930e99e..6d1a39afd2a2 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -1962,10 +1962,9 @@ static int smb_direct_create_pools(struct smbdirect_socket *sc) return -ENOMEM; } -static int smb_direct_create_qpair(struct smb_direct_transport *t, +static int smb_direct_create_qpair(struct smbdirect_socket *sc, struct ib_qp_cap *cap) { - struct smbdirect_socket *sc = &t->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; int ret; struct ib_qp_init_attr qp_attr; @@ -2130,7 +2129,7 @@ static int smb_direct_connect(struct smb_direct_transport *st) return ret; } - ret = smb_direct_create_qpair(st, &qp_cap); + ret = smb_direct_create_qpair(sc, &qp_cap); if (ret) { pr_err("Can't accept RDMA client: %d\n", ret); return ret; From 9221b12b356729cb9cb2a0e0ca3062b73aafb04c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 14:52:04 +0200 Subject: [PATCH 134/159] smb: server: pass struct smbdirect_socket to smb_direct_post_recv() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 6d1a39afd2a2..01b1d35a0b1c 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -631,10 +631,9 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) smb_direct_disconnect_rdma_connection(sc); } -static int smb_direct_post_recv(struct smb_direct_transport *t, +static int smb_direct_post_recv(struct smbdirect_socket *sc, struct smbdirect_recv_io *recvmsg) { - struct smbdirect_socket *sc = &t->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; struct ib_recv_wr wr; int ret; @@ -791,8 +790,6 @@ static void smb_direct_post_recv_credits(struct work_struct *work) { struct smbdirect_socket *sc = container_of(work, struct smbdirect_socket, recv_io.posted.refill_work); - struct smb_direct_transport *t = - container_of(sc, struct smb_direct_transport, socket); struct smbdirect_recv_io *recvmsg; int credits = 0; int ret; @@ -805,7 +802,7 @@ static void smb_direct_post_recv_credits(struct work_struct *work) recvmsg->first_segment = false; - ret = smb_direct_post_recv(t, recvmsg); + ret = smb_direct_post_recv(sc, recvmsg); if (ret) { pr_err("Can't post recv: %d\n", ret); put_recvmsg(sc, recvmsg); @@ -1785,7 +1782,7 @@ static int smb_direct_prepare_negotiation(struct smb_direct_transport *t) if (!recvmsg) return -ENOMEM; - ret = smb_direct_post_recv(t, recvmsg); + ret = smb_direct_post_recv(sc, recvmsg); if (ret) { pr_err("Can't post recv: %d\n", ret); goto out_err; From 56bcc18d24f73f66b4211d4d028a626c0a5c56af Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 14:53:13 +0200 Subject: [PATCH 135/159] smb: server: pass struct smbdirect_socket to smb_direct_accept_client() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 01b1d35a0b1c..d2836780308e 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -1719,9 +1719,8 @@ static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, return 0; } -static int smb_direct_accept_client(struct smb_direct_transport *t) +static int smb_direct_accept_client(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &t->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; struct rdma_conn_param conn_param; __be32 ird_ord_hdr[2]; @@ -1788,7 +1787,7 @@ static int smb_direct_prepare_negotiation(struct smb_direct_transport *t) goto out_err; } - ret = smb_direct_accept_client(t); + ret = smb_direct_accept_client(sc); if (ret) { pr_err("Can't accept client\n"); goto out_err; From 7cb0ab73f82f19a7d88d01a2949fc1275f56be39 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 14:54:17 +0200 Subject: [PATCH 136/159] smb: server: pass struct smbdirect_socket to smb_direct_prepare_negotiation() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index d2836780308e..4ae94b67461f 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -1766,11 +1766,10 @@ static int smb_direct_accept_client(struct smbdirect_socket *sc) return 0; } -static int smb_direct_prepare_negotiation(struct smb_direct_transport *t) +static int smb_direct_prepare_negotiation(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &t->socket; - int ret; struct smbdirect_recv_io *recvmsg; + int ret; WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_CREATED); sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED; @@ -2131,7 +2130,7 @@ static int smb_direct_connect(struct smb_direct_transport *st) return ret; } - ret = smb_direct_prepare_negotiation(st); + ret = smb_direct_prepare_negotiation(sc); if (ret) { pr_err("Can't negotiate: %d\n", ret); return ret; From 100aec545ad170ac9139dd66e3475501f4b5bda4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 14:55:50 +0200 Subject: [PATCH 137/159] smb: server: pass struct smbdirect_socket to smb_direct_connect() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 4ae94b67461f..f8d08a329153 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -2106,11 +2106,10 @@ static int smb_direct_prepare(struct ksmbd_transport *t) return ret; } -static int smb_direct_connect(struct smb_direct_transport *st) +static int smb_direct_connect(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &st->socket; - int ret; struct ib_qp_cap qp_cap; + int ret; ret = smb_direct_init_params(sc, &qp_cap); if (ret) { @@ -2232,7 +2231,7 @@ static int smb_direct_handle_connect_request(struct rdma_cm_id *new_cm_id, sp->responder_resources = min_t(u8, sp->responder_resources, peer_responder_resources); - ret = smb_direct_connect(t); + ret = smb_direct_connect(sc); if (ret) goto out_err; From 789cfc2ffa72d75394cee78abf3fd4d57d623399 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 15:07:35 +0200 Subject: [PATCH 138/159] smb: server: pass struct smbdirect_socket to smb_direct_{alloc,free}_sendmsg() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index f8d08a329153..05900f62f2e7 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -414,9 +414,8 @@ static void free_transport(struct smb_direct_transport *t) } static struct smbdirect_send_io -*smb_direct_alloc_sendmsg(struct smb_direct_transport *t) +*smb_direct_alloc_sendmsg(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &t->socket; struct smbdirect_send_io *msg; msg = mempool_alloc(sc->send_io.mem.pool, KSMBD_DEFAULT_GFP); @@ -428,10 +427,9 @@ static struct smbdirect_send_io return msg; } -static void smb_direct_free_sendmsg(struct smb_direct_transport *t, +static void smb_direct_free_sendmsg(struct smbdirect_socket *sc, struct smbdirect_send_io *msg) { - struct smbdirect_socket *sc = &t->socket; int i; if (msg->num_sge > 0) { @@ -821,13 +819,11 @@ static void smb_direct_post_recv_credits(struct work_struct *work) static void send_done(struct ib_cq *cq, struct ib_wc *wc) { struct smbdirect_send_io *sendmsg, *sibling; - struct smb_direct_transport *t; struct smbdirect_socket *sc; struct list_head *pos, *prev, *end; sendmsg = container_of(wc->wr_cqe, struct smbdirect_send_io, cqe); sc = sendmsg->socket; - t = container_of(sc, struct smb_direct_transport, socket); ksmbd_debug(RDMA, "Send completed. status='%s (%d)', opcode=%d\n", ib_wc_status_msg(wc->status), wc->status, @@ -849,11 +845,11 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc) for (pos = &sendmsg->sibling_list, prev = pos->prev, end = sendmsg->sibling_list.next; prev != end; pos = prev, prev = prev->prev) { sibling = container_of(pos, struct smbdirect_send_io, sibling_list); - smb_direct_free_sendmsg(t, sibling); + smb_direct_free_sendmsg(sc, sibling); } sibling = container_of(pos, struct smbdirect_send_io, sibling_list); - smb_direct_free_sendmsg(t, sibling); + smb_direct_free_sendmsg(sc, sibling); } static int manage_credits_prior_sending(struct smb_direct_transport *t) @@ -957,7 +953,7 @@ static int smb_direct_flush_send_list(struct smb_direct_transport *t, wake_up(&sc->send_io.credits.wait_queue); list_for_each_entry_safe(first, last, &send_ctx->msg_list, sibling_list) { - smb_direct_free_sendmsg(t, first); + smb_direct_free_sendmsg(sc, first); } } return ret; @@ -1032,7 +1028,7 @@ static int smb_direct_create_header(struct smb_direct_transport *t, int header_length; int ret; - sendmsg = smb_direct_alloc_sendmsg(t); + sendmsg = smb_direct_alloc_sendmsg(sc); if (IS_ERR(sendmsg)) return PTR_ERR(sendmsg); @@ -1075,7 +1071,7 @@ static int smb_direct_create_header(struct smb_direct_transport *t, DMA_TO_DEVICE); ret = ib_dma_mapping_error(sc->ib.dev, sendmsg->sge[0].addr); if (ret) { - smb_direct_free_sendmsg(t, sendmsg); + smb_direct_free_sendmsg(sc, sendmsg); return ret; } @@ -1231,7 +1227,7 @@ static int smb_direct_post_send_data(struct smb_direct_transport *t, goto err; return 0; err: - smb_direct_free_sendmsg(t, msg); + smb_direct_free_sendmsg(sc, msg); atomic_inc(&sc->send_io.credits.count); return ret; } @@ -1660,7 +1656,7 @@ static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, struct smbdirect_negotiate_resp *resp; int ret; - sendmsg = smb_direct_alloc_sendmsg(t); + sendmsg = smb_direct_alloc_sendmsg(sc); if (IS_ERR(sendmsg)) return -ENOMEM; @@ -1696,7 +1692,7 @@ static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, DMA_TO_DEVICE); ret = ib_dma_mapping_error(sc->ib.dev, sendmsg->sge[0].addr); if (ret) { - smb_direct_free_sendmsg(t, sendmsg); + smb_direct_free_sendmsg(sc, sendmsg); return ret; } @@ -1706,7 +1702,7 @@ static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, ret = post_sendmsg(t, NULL, sendmsg); if (ret) { - smb_direct_free_sendmsg(t, sendmsg); + smb_direct_free_sendmsg(sc, sendmsg); return ret; } From 56b442a248b18e20b7a1b17d8bce2a97c62c8063 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 15:08:27 +0200 Subject: [PATCH 139/159] smb: server: remove unused struct struct smb_direct_transport argument from smb_direct_send_ctx_init() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 05900f62f2e7..a9cee7f3da85 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -907,8 +907,7 @@ static int smb_direct_post_send(struct smb_direct_transport *t, return ret; } -static void smb_direct_send_ctx_init(struct smb_direct_transport *t, - struct smbdirect_send_batch *send_ctx, +static void smb_direct_send_ctx_init(struct smbdirect_send_batch *send_ctx, bool need_invalidate_rkey, unsigned int remote_key) { @@ -945,7 +944,7 @@ static int smb_direct_flush_send_list(struct smb_direct_transport *t, ret = smb_direct_post_send(t, &first->wr); if (!ret) { - smb_direct_send_ctx_init(t, send_ctx, + smb_direct_send_ctx_init(send_ctx, send_ctx->need_invalidate_rkey, send_ctx->remote_key); } else { @@ -1261,7 +1260,7 @@ static int smb_direct_writev(struct ksmbd_transport *t, remaining_data_length = buflen; ksmbd_debug(RDMA, "Sending smb (RDMA): smb_len=%u\n", buflen); - smb_direct_send_ctx_init(st, &send_ctx, need_invalidate, remote_key); + smb_direct_send_ctx_init(&send_ctx, need_invalidate, remote_key); while (remaining_data_length) { struct kvec vecs[SMBDIRECT_SEND_IO_MAX_SGE - 1]; /* minus smbdirect hdr */ size_t possible_bytes = max_iov_size; From ecb56dbc93c67a0e03b6c4877ac1ead4cde0e9ca Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 15:46:53 +0200 Subject: [PATCH 140/159] smb: server: pass struct smbdirect_socket to smb_direct_post_send() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index a9cee7f3da85..c5bc4a850e6b 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -890,10 +890,9 @@ static int manage_keep_alive_before_sending(struct smb_direct_transport *t) return 0; } -static int smb_direct_post_send(struct smb_direct_transport *t, +static int smb_direct_post_send(struct smbdirect_socket *sc, struct ib_send_wr *wr) { - struct smbdirect_socket *sc = &t->socket; int ret; atomic_inc(&sc->send_io.pending.count); @@ -942,7 +941,7 @@ static int smb_direct_flush_send_list(struct smb_direct_transport *t, last->wr.ex.invalidate_rkey = send_ctx->remote_key; } - ret = smb_direct_post_send(t, &first->wr); + ret = smb_direct_post_send(sc, &first->wr); if (!ret) { smb_direct_send_ctx_init(send_ctx, send_ctx->need_invalidate_rkey, @@ -1162,7 +1161,7 @@ static int post_sendmsg(struct smb_direct_transport *t, msg->wr.wr_cqe = &msg->cqe; msg->wr.send_flags = IB_SEND_SIGNALED; - return smb_direct_post_send(t, &msg->wr); + return smb_direct_post_send(sc, &msg->wr); } static int smb_direct_post_send_data(struct smb_direct_transport *t, From d14910bbf64404cb74f35419ca2cb427a558a43c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 15:48:05 +0200 Subject: [PATCH 141/159] smb: server: pass struct smbdirect_socket to smb_direct_flush_send_list() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index c5bc4a850e6b..dc5a3cf9d0c7 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -916,11 +916,10 @@ static void smb_direct_send_ctx_init(struct smbdirect_send_batch *send_ctx, send_ctx->remote_key = remote_key; } -static int smb_direct_flush_send_list(struct smb_direct_transport *t, +static int smb_direct_flush_send_list(struct smbdirect_socket *sc, struct smbdirect_send_batch *send_ctx, bool is_last) { - struct smbdirect_socket *sc = &t->socket; struct smbdirect_send_io *first, *last; int ret; @@ -988,7 +987,7 @@ static int wait_for_send_credits(struct smb_direct_transport *t, if (send_ctx && (send_ctx->wr_cnt >= 16 || atomic_read(&sc->send_io.credits.count) <= 1)) { - ret = smb_direct_flush_send_list(t, send_ctx, false); + ret = smb_direct_flush_send_list(sc, send_ctx, false); if (ret) return ret; } @@ -1358,7 +1357,7 @@ static int smb_direct_writev(struct ksmbd_transport *t, } done: - ret = smb_direct_flush_send_list(st, &send_ctx, true); + ret = smb_direct_flush_send_list(sc, &send_ctx, true); if (unlikely(!ret && error)) ret = error; From 7f4805b7db94b75003d08a97f5125617b42c625b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 15:49:40 +0200 Subject: [PATCH 142/159] smb: server: pass struct smbdirect_socket to wait_for_credits() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index dc5a3cf9d0c7..2ae6500dad2c 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -956,11 +956,10 @@ static int smb_direct_flush_send_list(struct smbdirect_socket *sc, return ret; } -static int wait_for_credits(struct smb_direct_transport *t, +static int wait_for_credits(struct smbdirect_socket *sc, wait_queue_head_t *waitq, atomic_t *total_credits, int needed) { - struct smbdirect_socket *sc = &t->socket; int ret; do { @@ -992,14 +991,14 @@ static int wait_for_send_credits(struct smb_direct_transport *t, return ret; } - return wait_for_credits(t, &sc->send_io.credits.wait_queue, &sc->send_io.credits.count, 1); + return wait_for_credits(sc, &sc->send_io.credits.wait_queue, &sc->send_io.credits.count, 1); } static int wait_for_rw_credits(struct smb_direct_transport *t, int credits) { struct smbdirect_socket *sc = &t->socket; - return wait_for_credits(t, + return wait_for_credits(sc, &sc->rw_io.credits.wait_queue, &sc->rw_io.credits.count, credits); From 2dc6c7e8ba3f348b8bcf348c0f736898170225fd Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 15:51:53 +0200 Subject: [PATCH 143/159] smb: server: pass struct smbdirect_socket to wait_for_send_credits() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 2ae6500dad2c..8a9bf68a0ef9 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -978,10 +978,9 @@ static int wait_for_credits(struct smbdirect_socket *sc, } while (true); } -static int wait_for_send_credits(struct smb_direct_transport *t, +static int wait_for_send_credits(struct smbdirect_socket *sc, struct smbdirect_send_batch *send_ctx) { - struct smbdirect_socket *sc = &t->socket; int ret; if (send_ctx && @@ -1173,7 +1172,7 @@ static int smb_direct_post_send_data(struct smb_direct_transport *t, int data_length; struct scatterlist sg[SMBDIRECT_SEND_IO_MAX_SGE - 1]; - ret = wait_for_send_credits(t, send_ctx); + ret = wait_for_send_credits(sc, send_ctx); if (ret) return ret; From cae2d9a2298d04c237c6b7c57b9584068a2223df Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 15:52:47 +0200 Subject: [PATCH 144/159] smb: server: pass struct smbdirect_socket to wait_for_rw_credits() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 8a9bf68a0ef9..02982cadd304 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -993,10 +993,8 @@ static int wait_for_send_credits(struct smbdirect_socket *sc, return wait_for_credits(sc, &sc->send_io.credits.wait_queue, &sc->send_io.credits.count, 1); } -static int wait_for_rw_credits(struct smb_direct_transport *t, int credits) +static int wait_for_rw_credits(struct smbdirect_socket *sc, int credits) { - struct smbdirect_socket *sc = &t->socket; - return wait_for_credits(sc, &sc->rw_io.credits.wait_queue, &sc->rw_io.credits.count, @@ -1464,7 +1462,7 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, ksmbd_debug(RDMA, "RDMA %s, len %#x, needed credits %#x\n", str_read_write(is_read), buf_len, credits_needed); - ret = wait_for_rw_credits(t, credits_needed); + ret = wait_for_rw_credits(sc, credits_needed); if (ret < 0) return ret; From b156d2c559b0ac9b410effd081262d96aa9bf00e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 15:55:20 +0200 Subject: [PATCH 145/159] smb: server: pass struct smbdirect_socket to calc_rw_credits() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 02982cadd304..9f47faf0ce09 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -1001,11 +1001,9 @@ static int wait_for_rw_credits(struct smbdirect_socket *sc, int credits) credits); } -static int calc_rw_credits(struct smb_direct_transport *t, +static int calc_rw_credits(struct smbdirect_socket *sc, char *buf, unsigned int len) { - struct smbdirect_socket *sc = &t->socket; - return DIV_ROUND_UP(get_buf_page_count(buf, len), sc->rw_io.credits.num_pages); } @@ -1453,7 +1451,7 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, buf_len = 0; } - credits_needed += calc_rw_credits(t, desc_buf, desc_buf_len); + credits_needed += calc_rw_credits(sc, desc_buf, desc_buf_len); desc_buf += desc_buf_len; buf_len -= desc_buf_len; desc_num++; From 663b3c3c864c906373ef231cbb1755b353cb5f9f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 15:57:41 +0200 Subject: [PATCH 146/159] smb: server: pass struct smbdirect_socket to manage_credits_prior_sending() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 9f47faf0ce09..d7cc593705dd 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -852,9 +852,8 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc) smb_direct_free_sendmsg(sc, sibling); } -static int manage_credits_prior_sending(struct smb_direct_transport *t) +static int manage_credits_prior_sending(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &t->socket; int new_credits; if (atomic_read(&sc->recv_io.credits.count) >= sc->recv_io.credits.target) @@ -1026,7 +1025,7 @@ static int smb_direct_create_header(struct smb_direct_transport *t, /* Fill in the packet header */ packet = (struct smbdirect_data_transfer *)sendmsg->packet; packet->credits_requested = cpu_to_le16(sp->send_credit_target); - packet->credits_granted = cpu_to_le16(manage_credits_prior_sending(t)); + packet->credits_granted = cpu_to_le16(manage_credits_prior_sending(sc)); packet->flags = 0; if (manage_keep_alive_before_sending(t)) @@ -1667,7 +1666,7 @@ static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, resp->reserved = 0; resp->credits_requested = cpu_to_le16(sp->send_credit_target); - resp->credits_granted = cpu_to_le16(manage_credits_prior_sending(t)); + resp->credits_granted = cpu_to_le16(manage_credits_prior_sending(sc)); resp->max_readwrite_size = cpu_to_le32(sp->max_read_write_size); resp->preferred_send_size = cpu_to_le32(sp->max_send_size); resp->max_receive_size = cpu_to_le32(sp->max_recv_size); From 4d1dffe0a08d87eb4fb1a62e4d76f541849db94a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 15:59:35 +0200 Subject: [PATCH 147/159] smb: server: pass struct smbdirect_socket to manage_keep_alive_before_sending() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index d7cc593705dd..4bf5903fadb6 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -871,9 +871,8 @@ static int manage_credits_prior_sending(struct smbdirect_socket *sc) return new_credits; } -static int manage_keep_alive_before_sending(struct smb_direct_transport *t) +static int manage_keep_alive_before_sending(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &t->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; if (sc->idle.keepalive == SMBDIRECT_KEEPALIVE_PENDING) { @@ -1028,7 +1027,7 @@ static int smb_direct_create_header(struct smb_direct_transport *t, packet->credits_granted = cpu_to_le16(manage_credits_prior_sending(sc)); packet->flags = 0; - if (manage_keep_alive_before_sending(t)) + if (manage_keep_alive_before_sending(sc)) packet->flags |= cpu_to_le16(SMBDIRECT_FLAG_RESPONSE_REQUESTED); packet->reserved = 0; From 0a715db380444089e2907fa72ed712d2150aae6c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 16:02:21 +0200 Subject: [PATCH 148/159] smb: server: pass struct smbdirect_socket to smb_direct_create_header() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 4bf5903fadb6..5f4d3ebac07c 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -1006,11 +1006,10 @@ static int calc_rw_credits(struct smbdirect_socket *sc, sc->rw_io.credits.num_pages); } -static int smb_direct_create_header(struct smb_direct_transport *t, +static int smb_direct_create_header(struct smbdirect_socket *sc, int size, int remaining_data_length, struct smbdirect_send_io **sendmsg_out) { - struct smbdirect_socket *sc = &t->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; struct smbdirect_send_io *sendmsg; struct smbdirect_data_transfer *packet; @@ -1174,7 +1173,7 @@ static int smb_direct_post_send_data(struct smb_direct_transport *t, for (i = 0; i < niov; i++) data_length += iov[i].iov_len; - ret = smb_direct_create_header(t, data_length, remaining_data_length, + ret = smb_direct_create_header(sc, data_length, remaining_data_length, &msg); if (ret) { atomic_inc(&sc->send_io.credits.count); From ab83128e65a1f56db292a6db9b96750a39ba074b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 16:03:52 +0200 Subject: [PATCH 149/159] smb: server: pass struct smbdirect_socket to post_sendmsg() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 5f4d3ebac07c..4fc1da244bd3 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -1115,11 +1115,10 @@ static int get_mapped_sg_list(struct ib_device *device, void *buf, int size, return ib_dma_map_sg(device, sg_list, npages, dir); } -static int post_sendmsg(struct smb_direct_transport *t, +static int post_sendmsg(struct smbdirect_socket *sc, struct smbdirect_send_batch *send_ctx, struct smbdirect_send_io *msg) { - struct smbdirect_socket *sc = &t->socket; int i; for (i = 0; i < msg->num_sge; i++) @@ -1210,7 +1209,7 @@ static int smb_direct_post_send_data(struct smb_direct_transport *t, } } - ret = post_sendmsg(t, send_ctx, msg); + ret = post_sendmsg(sc, send_ctx, msg); if (ret) goto err; return 0; @@ -1688,7 +1687,7 @@ static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, sendmsg->sge[0].length = sizeof(*resp); sendmsg->sge[0].lkey = sc->ib.pd->local_dma_lkey; - ret = post_sendmsg(t, NULL, sendmsg); + ret = post_sendmsg(sc, NULL, sendmsg); if (ret) { smb_direct_free_sendmsg(sc, sendmsg); return ret; From c0cb9823ac52be33a974b3bfe698e62507f456db Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 16:06:09 +0200 Subject: [PATCH 150/159] smb: server: pass struct smbdirect_socket to smb_direct_post_send_data() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 4fc1da244bd3..4b0147c3b3aa 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -135,7 +135,7 @@ static inline int get_buf_page_count(void *buf, int size) static void smb_direct_destroy_pools(struct smbdirect_socket *sc); static void smb_direct_post_recv_credits(struct work_struct *work); -static int smb_direct_post_send_data(struct smb_direct_transport *t, +static int smb_direct_post_send_data(struct smbdirect_socket *sc, struct smbdirect_send_batch *send_ctx, struct kvec *iov, int niov, int remaining_data_length); @@ -270,13 +270,11 @@ static void smb_direct_send_immediate_work(struct work_struct *work) { struct smbdirect_socket *sc = container_of(work, struct smbdirect_socket, idle.immediate_work); - struct smb_direct_transport *t = - container_of(sc, struct smb_direct_transport, socket); if (sc->status != SMBDIRECT_SOCKET_CONNECTED) return; - smb_direct_post_send_data(t, NULL, NULL, 0, 0); + smb_direct_post_send_data(sc, NULL, NULL, 0, 0); } static void smb_direct_idle_connection_timer(struct work_struct *work) @@ -1153,12 +1151,11 @@ static int post_sendmsg(struct smbdirect_socket *sc, return smb_direct_post_send(sc, &msg->wr); } -static int smb_direct_post_send_data(struct smb_direct_transport *t, +static int smb_direct_post_send_data(struct smbdirect_socket *sc, struct smbdirect_send_batch *send_ctx, struct kvec *iov, int niov, int remaining_data_length) { - struct smbdirect_socket *sc = &t->socket; int i, j, ret; struct smbdirect_send_io *msg; int data_length; @@ -1337,7 +1334,7 @@ static int smb_direct_writev(struct ksmbd_transport *t, remaining_data_length -= bytes; - ret = smb_direct_post_send_data(st, &send_ctx, + ret = smb_direct_post_send_data(sc, &send_ctx, vecs, nvecs, remaining_data_length); if (unlikely(ret)) { From 5e90c56e0e8b787b3a7ab1ff565c93c918f27f1c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 16:08:49 +0200 Subject: [PATCH 151/159] smb: server: pass struct smbdirect_socket to {enqueue,get_first}_reassembly() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 4b0147c3b3aa..afd03b6a0313 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -180,12 +180,10 @@ static void put_recvmsg(struct smbdirect_socket *sc, queue_work(sc->workqueue, &sc->recv_io.posted.refill_work); } -static void enqueue_reassembly(struct smb_direct_transport *t, +static void enqueue_reassembly(struct smbdirect_socket *sc, struct smbdirect_recv_io *recvmsg, int data_length) { - struct smbdirect_socket *sc = &t->socket; - spin_lock(&sc->recv_io.reassembly.lock); list_add_tail(&recvmsg->list, &sc->recv_io.reassembly.list); sc->recv_io.reassembly.queue_length++; @@ -200,10 +198,8 @@ static void enqueue_reassembly(struct smb_direct_transport *t, spin_unlock(&sc->recv_io.reassembly.lock); } -static struct smbdirect_recv_io *get_first_reassembly(struct smb_direct_transport *t) +static struct smbdirect_recv_io *get_first_reassembly(struct smbdirect_socket *sc) { - struct smbdirect_socket *sc = &t->socket; - if (!list_empty(&sc->recv_io.reassembly.list)) return list_first_entry(&sc->recv_io.reassembly.list, struct smbdirect_recv_io, list); @@ -387,7 +383,7 @@ static void free_transport(struct smb_direct_transport *t) ksmbd_debug(RDMA, "drain the reassembly queue\n"); do { spin_lock(&sc->recv_io.reassembly.lock); - recvmsg = get_first_reassembly(t); + recvmsg = get_first_reassembly(sc); if (recvmsg) { list_del(&recvmsg->list); spin_unlock(&sc->recv_io.reassembly.lock); @@ -494,14 +490,12 @@ static int smb_direct_check_recvmsg(struct smbdirect_recv_io *recvmsg) static void recv_done(struct ib_cq *cq, struct ib_wc *wc) { struct smbdirect_recv_io *recvmsg; - struct smb_direct_transport *t; struct smbdirect_socket *sc; struct smbdirect_socket_parameters *sp; recvmsg = container_of(wc->wr_cqe, struct smbdirect_recv_io, cqe); sc = recvmsg->socket; sp = &sc->parameters; - t = container_of(sc, struct smb_direct_transport, socket); if (wc->status != IB_WC_SUCCESS || wc->opcode != IB_WC_RECV) { put_recvmsg(sc, recvmsg); @@ -539,7 +533,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) sc->recv_io.reassembly.full_packet_received = true; WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_NEGOTIATE_NEEDED); sc->status = SMBDIRECT_SOCKET_NEGOTIATE_RUNNING; - enqueue_reassembly(t, recvmsg, 0); + enqueue_reassembly(sc, recvmsg, 0); wake_up(&sc->status_wait); return; case SMBDIRECT_EXPECT_DATA_TRANSFER: { @@ -607,7 +601,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) if (sc->recv_io.credits.target > old_recv_credit_target) queue_work(sc->workqueue, &sc->recv_io.posted.refill_work); - enqueue_reassembly(t, recvmsg, (int)data_length); + enqueue_reassembly(sc, recvmsg, (int)data_length); wake_up(&sc->recv_io.reassembly.wait_queue); } else put_recvmsg(sc, recvmsg); @@ -702,7 +696,7 @@ static int smb_direct_read(struct ksmbd_transport *t, char *buf, to_read = size; offset = sc->recv_io.reassembly.first_entry_offset; while (data_read < size) { - recvmsg = get_first_reassembly(st); + recvmsg = get_first_reassembly(sc); data_transfer = smbdirect_recv_io_payload(recvmsg); data_length = le32_to_cpu(data_transfer->data_length); remaining_data_length = @@ -2054,7 +2048,7 @@ static int smb_direct_prepare(struct ksmbd_transport *t) if (ret <= 0 || sc->status != SMBDIRECT_SOCKET_NEGOTIATE_RUNNING) return ret < 0 ? ret : -ETIMEDOUT; - recvmsg = get_first_reassembly(st); + recvmsg = get_first_reassembly(sc); if (!recvmsg) return -ECONNABORTED; From 9d0050874767ec5977843d4bfca3aeb9a43a8f74 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 22 Aug 2025 16:11:34 +0200 Subject: [PATCH 152/159] smb: server: pass struct smbdirect_socket to smb_direct_send_negotiate_response() This will make it easier to move function to the common code in future. Cc: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index afd03b6a0313..a61898ea2a3f 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -1625,10 +1625,9 @@ static void smb_direct_qpair_handler(struct ib_event *event, void *context) } } -static int smb_direct_send_negotiate_response(struct smb_direct_transport *t, +static int smb_direct_send_negotiate_response(struct smbdirect_socket *sc, int failed) { - struct smbdirect_socket *sc = &t->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; struct smbdirect_send_io *sendmsg; struct smbdirect_negotiate_resp *resp; @@ -2069,7 +2068,7 @@ static int smb_direct_prepare(struct ksmbd_transport *t) sc->recv_io.credits.target = min_t(u16, sc->recv_io.credits.target, sp->recv_credit_max); sc->recv_io.credits.target = max_t(u16, sc->recv_io.credits.target, 1); - ret = smb_direct_send_negotiate_response(st, ret); + ret = smb_direct_send_negotiate_response(sc, ret); out: spin_lock_irq(&sc->recv_io.reassembly.lock); sc->recv_io.reassembly.queue_length--; From b3fd52a0d85c688a381e2ce72912db0a73727ce9 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 28 Aug 2025 10:39:56 +0200 Subject: [PATCH 153/159] smb: server: let smb_direct_disconnect_rdma_connection() set SMBDIRECT_SOCKET_ERROR... smb_direct_disconnect_rdma_connection() should turn the status into an error state instead of leaving it as is until smb_direct_disconnect_rdma_work() is running. Cc: Steve French Cc: Tom Talpey Cc: Long Li Acked-by: Namjae Jeon Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 40 ++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index a61898ea2a3f..67345c58bfe9 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -259,6 +259,46 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work) static void smb_direct_disconnect_rdma_connection(struct smbdirect_socket *sc) { + switch (sc->status) { + case SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED: + case SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED: + case SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED: + case SMBDIRECT_SOCKET_NEGOTIATE_FAILED: + case SMBDIRECT_SOCKET_ERROR: + case SMBDIRECT_SOCKET_DISCONNECTING: + case SMBDIRECT_SOCKET_DISCONNECTED: + case SMBDIRECT_SOCKET_DESTROYED: + /* + * Keep the current error status + */ + break; + + case SMBDIRECT_SOCKET_RESOLVE_ADDR_NEEDED: + case SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING: + sc->status = SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED; + break; + + case SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED: + case SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING: + sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED; + break; + + case SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED: + case SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING: + sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED; + break; + + case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: + case SMBDIRECT_SOCKET_NEGOTIATE_RUNNING: + sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED; + break; + + case SMBDIRECT_SOCKET_CREATED: + case SMBDIRECT_SOCKET_CONNECTED: + sc->status = SMBDIRECT_SOCKET_ERROR; + break; + } + queue_work(sc->workqueue, &sc->disconnect_work); } From 3d71e7cdbcf056a0b8ca3e9634f161b9a7b1e634 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 28 Aug 2025 12:14:07 +0200 Subject: [PATCH 154/159] smb: server: fill in smbdirect_socket.first_error on error For now we just use -ECONNABORTED, but it will get more detailed later. Acked-by: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 67345c58bfe9..44fa0af21b45 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -222,6 +222,9 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work) disable_delayed_work(&sc->idle.timer_work); disable_work(&sc->idle.immediate_work); + if (sc->first_error == 0) + sc->first_error = -ECONNABORTED; + switch (sc->status) { case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: case SMBDIRECT_SOCKET_NEGOTIATE_RUNNING: @@ -259,6 +262,9 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work) static void smb_direct_disconnect_rdma_connection(struct smbdirect_socket *sc) { + if (sc->first_error == 0) + sc->first_error = -ECONNABORTED; + switch (sc->status) { case SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED: case SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED: From 7d729df9945a5ff9d4947bbc3c1297040ae3c507 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 28 Aug 2025 12:17:23 +0200 Subject: [PATCH 155/159] smb: server: let smb_direct_disconnect_rdma_connection() disable all work but disconnect_work There's no point run these if we already know the connection is broken. Acked-by: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 44fa0af21b45..cd4398ae8b98 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -262,6 +262,15 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work) static void smb_direct_disconnect_rdma_connection(struct smbdirect_socket *sc) { + /* + * make sure other work (than disconnect_work) is + * not queued again but here we don't block and avoid + * disable[_delayed]_work_sync() + */ + disable_work(&sc->recv_io.posted.refill_work); + disable_work(&sc->idle.immediate_work); + disable_delayed_work(&sc->idle.timer_work); + if (sc->first_error == 0) sc->first_error = -ECONNABORTED; From 0491f26f8980d7a4028d3528df09e23f5a64adbe Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 2 Sep 2025 12:36:50 +0200 Subject: [PATCH 156/159] smb: server: let {free_transport,smb_direct_disconnect_rdma_{work,connection}}() wake up all wait queues This is important in order to let all waiters notice a broken connection. We also go via smb_direct_disconnect_rdma_{work,connection}() for broken connections. Acked-by: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 40 +++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index cd4398ae8b98..ba4dfdcb321a 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -207,6 +207,19 @@ static struct smbdirect_recv_io *get_first_reassembly(struct smbdirect_socket *s return NULL; } +static void smb_direct_disconnect_wake_up_all(struct smbdirect_socket *sc) +{ + /* + * Wake up all waiters in all wait queues + * in order to notice the broken connection. + */ + wake_up_all(&sc->status_wait); + wake_up_all(&sc->send_io.credits.wait_queue); + wake_up_all(&sc->send_io.pending.zero_wait_queue); + wake_up_all(&sc->recv_io.reassembly.wait_queue); + wake_up_all(&sc->rw_io.credits.wait_queue); +} + static void smb_direct_disconnect_rdma_work(struct work_struct *work) { struct smbdirect_socket *sc = @@ -257,6 +270,12 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work) case SMBDIRECT_SOCKET_DESTROYED: break; } + + /* + * Wake up all waiters in all wait queues + * in order to notice the broken connection. + */ + smb_direct_disconnect_wake_up_all(sc); } static void @@ -314,6 +333,12 @@ smb_direct_disconnect_rdma_connection(struct smbdirect_socket *sc) break; } + /* + * Wake up all waiters in all wait queues + * in order to notice the broken connection. + */ + smb_direct_disconnect_wake_up_all(sc); + queue_work(sc->workqueue, &sc->disconnect_work); } @@ -421,8 +446,14 @@ static void free_transport(struct smb_direct_transport *t) sc->status == SMBDIRECT_SOCKET_DISCONNECTED); } - wake_up_all(&sc->send_io.credits.wait_queue); - wake_up_all(&sc->send_io.pending.zero_wait_queue); + /* + * Wake up all waiters in all wait queues + * in order to notice the broken connection. + * + * Most likely this was already called via + * smb_direct_disconnect_rdma_work(), but call it again... + */ + smb_direct_disconnect_wake_up_all(sc); disable_work_sync(&sc->recv_io.posted.refill_work); disable_delayed_work_sync(&sc->idle.timer_work); @@ -1644,14 +1675,11 @@ static int smb_direct_cm_handler(struct rdma_cm_id *cm_id, sc->status = SMBDIRECT_SOCKET_DISCONNECTED; smb_direct_disconnect_rdma_work(&sc->disconnect_work); - wake_up_all(&sc->status_wait); - wake_up_all(&sc->recv_io.reassembly.wait_queue); - wake_up_all(&sc->send_io.credits.wait_queue); break; } case RDMA_CM_EVENT_CONNECT_ERROR: { sc->status = SMBDIRECT_SOCKET_DISCONNECTED; - wake_up_all(&sc->status_wait); + smb_direct_disconnect_rdma_work(&sc->disconnect_work); break; } default: From 8aa23bae607e3bd5ced892afc26bfbe8945f531b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 27 Aug 2025 15:54:35 +0200 Subject: [PATCH 157/159] smb: server: make consitent use of spin_lock_irq{save,restore}() in transport_rdma.c There is a mix of using spin_lock() and spin_lock_irq(), which is confusing as IB_POLL_WORKQUEUE is used and no code would be called from any interrupt. So using spin_lock() or even mutexes would be ok. But we'll soon share common code with the client, which uses IB_POLL_SOFTIRQ. And Documentation/kernel-hacking/locking.rst section "Cheat Sheet For Locking" says: - Otherwise (== data can be touched in an interrupt), use spin_lock_irqsave() and spin_unlock_irqrestore(). So in order to keep it simple and safe we use that version now. It will help merging functions into common code and have consistent locking in all cases. Acked-by: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 39 +++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index ba4dfdcb321a..f9734d7025b4 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -150,21 +150,24 @@ static struct smbdirect_recv_io *get_free_recvmsg(struct smbdirect_socket *sc) { struct smbdirect_recv_io *recvmsg = NULL; + unsigned long flags; - spin_lock(&sc->recv_io.free.lock); + spin_lock_irqsave(&sc->recv_io.free.lock, flags); if (!list_empty(&sc->recv_io.free.list)) { recvmsg = list_first_entry(&sc->recv_io.free.list, struct smbdirect_recv_io, list); list_del(&recvmsg->list); } - spin_unlock(&sc->recv_io.free.lock); + spin_unlock_irqrestore(&sc->recv_io.free.lock, flags); return recvmsg; } static void put_recvmsg(struct smbdirect_socket *sc, struct smbdirect_recv_io *recvmsg) { + unsigned long flags; + if (likely(recvmsg->sge.length != 0)) { ib_dma_unmap_single(sc->ib.dev, recvmsg->sge.addr, @@ -173,9 +176,9 @@ static void put_recvmsg(struct smbdirect_socket *sc, recvmsg->sge.length = 0; } - spin_lock(&sc->recv_io.free.lock); + spin_lock_irqsave(&sc->recv_io.free.lock, flags); list_add(&recvmsg->list, &sc->recv_io.free.list); - spin_unlock(&sc->recv_io.free.lock); + spin_unlock_irqrestore(&sc->recv_io.free.lock, flags); queue_work(sc->workqueue, &sc->recv_io.posted.refill_work); } @@ -184,7 +187,9 @@ static void enqueue_reassembly(struct smbdirect_socket *sc, struct smbdirect_recv_io *recvmsg, int data_length) { - spin_lock(&sc->recv_io.reassembly.lock); + unsigned long flags; + + spin_lock_irqsave(&sc->recv_io.reassembly.lock, flags); list_add_tail(&recvmsg->list, &sc->recv_io.reassembly.list); sc->recv_io.reassembly.queue_length++; /* @@ -195,7 +200,7 @@ static void enqueue_reassembly(struct smbdirect_socket *sc, */ virt_wmb(); sc->recv_io.reassembly.data_length += data_length; - spin_unlock(&sc->recv_io.reassembly.lock); + spin_unlock_irqrestore(&sc->recv_io.reassembly.lock, flags); } static struct smbdirect_recv_io *get_first_reassembly(struct smbdirect_socket *sc) @@ -468,14 +473,16 @@ static void free_transport(struct smb_direct_transport *t) ksmbd_debug(RDMA, "drain the reassembly queue\n"); do { - spin_lock(&sc->recv_io.reassembly.lock); + unsigned long flags; + + spin_lock_irqsave(&sc->recv_io.reassembly.lock, flags); recvmsg = get_first_reassembly(sc); if (recvmsg) { list_del(&recvmsg->list); - spin_unlock(&sc->recv_io.reassembly.lock); + spin_unlock_irqrestore(&sc->recv_io.reassembly.lock, flags); put_recvmsg(sc, recvmsg); } else { - spin_unlock(&sc->recv_io.reassembly.lock); + spin_unlock_irqrestore(&sc->recv_io.reassembly.lock, flags); } } while (recvmsg); sc->recv_io.reassembly.data_length = 0; @@ -768,6 +775,7 @@ static int smb_direct_read(struct ksmbd_transport *t, char *buf, if (sc->recv_io.reassembly.data_length >= size) { int queue_length; int queue_removed = 0; + unsigned long flags; /* * Need to make sure reassembly_data_length is read before @@ -823,9 +831,9 @@ static int smb_direct_read(struct ksmbd_transport *t, char *buf, if (queue_length) { list_del(&recvmsg->list); } else { - spin_lock_irq(&sc->recv_io.reassembly.lock); + spin_lock_irqsave(&sc->recv_io.reassembly.lock, flags); list_del(&recvmsg->list); - spin_unlock_irq(&sc->recv_io.reassembly.lock); + spin_unlock_irqrestore(&sc->recv_io.reassembly.lock, flags); } queue_removed++; put_recvmsg(sc, recvmsg); @@ -838,10 +846,10 @@ static int smb_direct_read(struct ksmbd_transport *t, char *buf, data_read += to_copy; } - spin_lock_irq(&sc->recv_io.reassembly.lock); + spin_lock_irqsave(&sc->recv_io.reassembly.lock, flags); sc->recv_io.reassembly.data_length -= data_read; sc->recv_io.reassembly.queue_length -= queue_removed; - spin_unlock_irq(&sc->recv_io.reassembly.lock); + spin_unlock_irqrestore(&sc->recv_io.reassembly.lock, flags); sc->recv_io.reassembly.first_entry_offset = offset; ksmbd_debug(RDMA, @@ -2107,6 +2115,7 @@ static int smb_direct_prepare(struct ksmbd_transport *t) struct smbdirect_socket_parameters *sp = &sc->parameters; struct smbdirect_recv_io *recvmsg; struct smbdirect_negotiate_req *req; + unsigned long flags; int ret; /* @@ -2153,10 +2162,10 @@ static int smb_direct_prepare(struct ksmbd_transport *t) ret = smb_direct_send_negotiate_response(sc, ret); out: - spin_lock_irq(&sc->recv_io.reassembly.lock); + spin_lock_irqsave(&sc->recv_io.reassembly.lock, flags); sc->recv_io.reassembly.queue_length--; list_del(&recvmsg->list); - spin_unlock_irq(&sc->recv_io.reassembly.lock); + spin_unlock_irqrestore(&sc->recv_io.reassembly.lock, flags); put_recvmsg(sc, recvmsg); return ret; From 942ce74ab9a3f1e18fe00bffa80ecf6294e9e6b5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 15 Sep 2025 08:05:31 +0200 Subject: [PATCH 158/159] smb: server: make use of ib_alloc_cq_any() instead of ib_alloc_cq() commit 20cf4e026730 ("rdma: Enable ib_alloc_cq to spread work over a device's comp_vectors") happened before ksmbd was upstreamed, but after the out of tree ksmbd (a.k.a. cifsd) was developed. So we still used ib_alloc_cq(). Acked-by: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index f9734d7025b4..e78347831d2f 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -2037,9 +2037,10 @@ static int smb_direct_create_qpair(struct smbdirect_socket *sc, return ret; } - sc->ib.send_cq = ib_alloc_cq(sc->ib.dev, sc, - sp->send_credit_target + cap->max_rdma_ctxs, - 0, IB_POLL_WORKQUEUE); + sc->ib.send_cq = ib_alloc_cq_any(sc->ib.dev, sc, + sp->send_credit_target + + cap->max_rdma_ctxs, + IB_POLL_WORKQUEUE); if (IS_ERR(sc->ib.send_cq)) { pr_err("Can't create RDMA send CQ\n"); ret = PTR_ERR(sc->ib.send_cq); @@ -2047,8 +2048,9 @@ static int smb_direct_create_qpair(struct smbdirect_socket *sc, goto err; } - sc->ib.recv_cq = ib_alloc_cq(sc->ib.dev, sc, - sp->recv_credit_max, 0, IB_POLL_WORKQUEUE); + sc->ib.recv_cq = ib_alloc_cq_any(sc->ib.dev, sc, + sp->recv_credit_max, + IB_POLL_WORKQUEUE); if (IS_ERR(sc->ib.recv_cq)) { pr_err("Can't create RDMA recv CQ\n"); ret = PTR_ERR(sc->ib.recv_cq); From 1b53426334c3c942db47e0959a2527a4f815af50 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 8 Sep 2025 22:22:35 +0200 Subject: [PATCH 159/159] smb: server: let smb_direct_flush_send_list() invalidate a remote key first If we want to invalidate a remote key we should do that as soon as possible, so do it in the first send work request. Acked-by: Namjae Jeon Cc: Steve French Cc: Tom Talpey Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index e78347831d2f..27e3fc5139cc 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -1017,12 +1017,15 @@ static int smb_direct_flush_send_list(struct smbdirect_socket *sc, struct smbdirect_send_io, sibling_list); + if (send_ctx->need_invalidate_rkey) { + first->wr.opcode = IB_WR_SEND_WITH_INV; + first->wr.ex.invalidate_rkey = send_ctx->remote_key; + send_ctx->need_invalidate_rkey = false; + send_ctx->remote_key = 0; + } + last->wr.send_flags = IB_SEND_SIGNALED; last->wr.wr_cqe = &last->cqe; - if (is_last && send_ctx->need_invalidate_rkey) { - last->wr.opcode = IB_WR_SEND_WITH_INV; - last->wr.ex.invalidate_rkey = send_ctx->remote_key; - } ret = smb_direct_post_send(sc, &first->wr); if (!ret) {