All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/10] improve smbdirect_mr_io lifetime
@ 2025-10-12 19:10 Stefan Metzmacher
  2025-10-12 19:10 ` [PATCH 01/10] smb: smbdirect: introduce smbdirect_mr_io.{kref,mutex} and SMBDIRECT_MR_DISABLED Stefan Metzmacher
                   ` (10 more replies)
  0 siblings, 11 replies; 14+ messages in thread
From: Stefan Metzmacher @ 2025-10-12 19:10 UTC (permalink / raw)
  To: linux-cifs, samba-technical
  Cc: metze, Steve French, Tom Talpey, Long Li, Namjae Jeon

Hi,

these patches improve and simplify our handling of
smbdirect_mr_io structures and their lifetime.

smbd_register_mr() returns a pointer to struct smbdirect_mr_io
and smbd_deregister_mr() gives the pointer back.

But currently the memory itself is managed by the connection
(struct smbdirect_socket) and smbd_destroy() has a strange
wait loop in order to wait for smbd_deregister_mr() being
called. It means code in smbd_destroy() is aware of
the server mutex in the generic smb client handling above
the transport layer.

These patches do some cleanups and fixes before changing
the logic to use a kref and a mutex in order to allow
smbd_deregister_mr() being called after smbd_destroy()
as the memory of smbdirect_mr_io will stay in memory
but will be detached from the connection.

This makes the code independent of cifs_server_[un]lock()
and will allow us to move more smbdirect code into common
functions (shared between client and server).

I think these should go into 6.18.

Stefan Metzmacher (10):
  smb: smbdirect: introduce smbdirect_mr_io.{kref,mutex} and
    SMBDIRECT_MR_DISABLED
  smb: client: change smbd_deregister_mr() to return void
  smb: client: let destroy_mr_list() call list_del(&mr->list)
  smb: client: let destroy_mr_list() remove locked from the list
  smb: client: improve logic in allocate_mr_list()
  smb: client: improve logic in smbd_register_mr()
  smb: client: improve logic in smbd_deregister_mr()
  smb: client: call ib_dma_unmap_sg if mr->sgt.nents is not 0
  smb: client: let destroy_mr_list() call ib_dereg_mr() before
    ib_dma_unmap_sg()
  smb: client: let destroy_mr_list() keep smbdirect_mr_io memory if
    registered

 fs/smb/client/smbdirect.c                  | 312 ++++++++++++++-------
 fs/smb/client/smbdirect.h                  |   2 +-
 fs/smb/common/smbdirect/smbdirect_socket.h |  11 +-
 3 files changed, 224 insertions(+), 101 deletions(-)

-- 
2.43.0


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

* [PATCH 01/10] smb: smbdirect: introduce smbdirect_mr_io.{kref,mutex} and SMBDIRECT_MR_DISABLED
  2025-10-12 19:10 [PATCH 00/10] improve smbdirect_mr_io lifetime Stefan Metzmacher
@ 2025-10-12 19:10 ` Stefan Metzmacher
  2025-10-12 19:10 ` [PATCH 02/10] smb: client: change smbd_deregister_mr() to return void Stefan Metzmacher
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Stefan Metzmacher @ 2025-10-12 19:10 UTC (permalink / raw)
  To: linux-cifs, samba-technical
  Cc: metze, Steve French, Tom Talpey, Long Li, Namjae Jeon

This will be used in the next commits in order to improve the
client code.

A broken connection can just disable the smbdirect_mr_io while
keeping the memory arround for the caller.

Cc: Steve French <smfrench@gmail.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Long Li <longli@microsoft.com>
Cc: Namjae Jeon <linkinjeon@kernel.org>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 fs/smb/common/smbdirect/smbdirect_socket.h | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h
index db22a1d0546b..361db7f9f623 100644
--- a/fs/smb/common/smbdirect/smbdirect_socket.h
+++ b/fs/smb/common/smbdirect/smbdirect_socket.h
@@ -437,13 +437,22 @@ enum smbdirect_mr_state {
 	SMBDIRECT_MR_READY,
 	SMBDIRECT_MR_REGISTERED,
 	SMBDIRECT_MR_INVALIDATED,
-	SMBDIRECT_MR_ERROR
+	SMBDIRECT_MR_ERROR,
+	SMBDIRECT_MR_DISABLED
 };
 
 struct smbdirect_mr_io {
 	struct smbdirect_socket *socket;
 	struct ib_cqe cqe;
 
+	/*
+	 * We can have up to two references:
+	 * 1. by the connection
+	 * 2. by the registration
+	 */
+	struct kref kref;
+	struct mutex mutex;
+
 	struct list_head list;
 
 	enum smbdirect_mr_state state;
-- 
2.43.0


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

* [PATCH 02/10] smb: client: change smbd_deregister_mr() to return void
  2025-10-12 19:10 [PATCH 00/10] improve smbdirect_mr_io lifetime Stefan Metzmacher
  2025-10-12 19:10 ` [PATCH 01/10] smb: smbdirect: introduce smbdirect_mr_io.{kref,mutex} and SMBDIRECT_MR_DISABLED Stefan Metzmacher
@ 2025-10-12 19:10 ` Stefan Metzmacher
  2025-10-12 19:10 ` [PATCH 03/10] smb: client: let destroy_mr_list() call list_del(&mr->list) Stefan Metzmacher
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Stefan Metzmacher @ 2025-10-12 19:10 UTC (permalink / raw)
  To: linux-cifs, samba-technical
  Cc: metze, Steve French, Tom Talpey, Long Li, Namjae Jeon

No callers checks the return value and this makes further
changes easier.

Cc: Steve French <smfrench@gmail.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Long Li <longli@microsoft.com>
Cc: Namjae Jeon <linkinjeon@kernel.org>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 fs/smb/client/smbdirect.c | 4 +---
 fs/smb/client/smbdirect.h | 2 +-
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c
index 316f398c70f4..a20aa2ddf57d 100644
--- a/fs/smb/client/smbdirect.c
+++ b/fs/smb/client/smbdirect.c
@@ -2612,7 +2612,7 @@ 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 smbdirect_mr_io *smbdirect_mr)
+void smbd_deregister_mr(struct smbdirect_mr_io *smbdirect_mr)
 {
 	struct ib_send_wr *wr;
 	struct smbdirect_socket *sc = smbdirect_mr->socket;
@@ -2662,8 +2662,6 @@ int smbd_deregister_mr(struct smbdirect_mr_io *smbdirect_mr)
 done:
 	if (atomic_dec_and_test(&sc->mr_io.used.count))
 		wake_up(&sc->mr_io.cleanup.wait_queue);
-
-	return rc;
 }
 
 static bool smb_set_sge(struct smb_extract_to_rdma *rdma,
diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h
index d67ac5ddaff4..577d37dbeb8a 100644
--- a/fs/smb/client/smbdirect.h
+++ b/fs/smb/client/smbdirect.h
@@ -60,7 +60,7 @@ int smbd_send(struct TCP_Server_Info *server,
 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 smbdirect_mr_io *mr);
+void smbd_deregister_mr(struct smbdirect_mr_io *mr);
 
 #else
 #define cifs_rdma_enabled(server)	0
-- 
2.43.0


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

* [PATCH 03/10] smb: client: let destroy_mr_list() call list_del(&mr->list)
  2025-10-12 19:10 [PATCH 00/10] improve smbdirect_mr_io lifetime Stefan Metzmacher
  2025-10-12 19:10 ` [PATCH 01/10] smb: smbdirect: introduce smbdirect_mr_io.{kref,mutex} and SMBDIRECT_MR_DISABLED Stefan Metzmacher
  2025-10-12 19:10 ` [PATCH 02/10] smb: client: change smbd_deregister_mr() to return void Stefan Metzmacher
@ 2025-10-12 19:10 ` Stefan Metzmacher
  2025-10-12 19:10 ` [PATCH 04/10] smb: client: let destroy_mr_list() remove locked from the list Stefan Metzmacher
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Stefan Metzmacher @ 2025-10-12 19:10 UTC (permalink / raw)
  To: linux-cifs, samba-technical
  Cc: metze, Steve French, Tom Talpey, Long Li, Namjae Jeon

This makes the code clearer and will make further changes easier.

Cc: Steve French <smfrench@gmail.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Long Li <longli@microsoft.com>
Cc: Namjae Jeon <linkinjeon@kernel.org>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 fs/smb/client/smbdirect.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c
index a20aa2ddf57d..b7be67dacd09 100644
--- a/fs/smb/client/smbdirect.c
+++ b/fs/smb/client/smbdirect.c
@@ -2363,6 +2363,7 @@ static void destroy_mr_list(struct smbdirect_socket *sc)
 				mr->sgt.nents, mr->dir);
 		ib_dereg_mr(mr->mr);
 		kfree(mr->sgt.sgl);
+		list_del(&mr->list);
 		kfree(mr);
 	}
 }
-- 
2.43.0


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

* [PATCH 04/10] smb: client: let destroy_mr_list() remove locked from the list
  2025-10-12 19:10 [PATCH 00/10] improve smbdirect_mr_io lifetime Stefan Metzmacher
                   ` (2 preceding siblings ...)
  2025-10-12 19:10 ` [PATCH 03/10] smb: client: let destroy_mr_list() call list_del(&mr->list) Stefan Metzmacher
@ 2025-10-12 19:10 ` Stefan Metzmacher
  2025-10-12 19:10 ` [PATCH 05/10] smb: client: improve logic in allocate_mr_list() Stefan Metzmacher
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Stefan Metzmacher @ 2025-10-12 19:10 UTC (permalink / raw)
  To: linux-cifs, samba-technical
  Cc: metze, Steve French, Tom Talpey, Long Li, Namjae Jeon

This should make sure get_mr() can't see the removed entries.

Cc: Steve French <smfrench@gmail.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Long Li <longli@microsoft.com>
Cc: Namjae Jeon <linkinjeon@kernel.org>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 fs/smb/client/smbdirect.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c
index b7be67dacd09..b974ca4e0b2e 100644
--- a/fs/smb/client/smbdirect.c
+++ b/fs/smb/client/smbdirect.c
@@ -2355,9 +2355,16 @@ static void smbd_mr_recovery_work(struct work_struct *work)
 static void destroy_mr_list(struct smbdirect_socket *sc)
 {
 	struct smbdirect_mr_io *mr, *tmp;
+	LIST_HEAD(all_list);
+	unsigned long flags;
 
 	disable_work_sync(&sc->mr_io.recovery_work);
-	list_for_each_entry_safe(mr, tmp, &sc->mr_io.all.list, list) {
+
+	spin_lock_irqsave(&sc->mr_io.all.lock, flags);
+	list_splice_tail_init(&sc->mr_io.all.list, &all_list);
+	spin_unlock_irqrestore(&sc->mr_io.all.lock, flags);
+
+	list_for_each_entry_safe(mr, tmp, &all_list, list) {
 		if (mr->state == SMBDIRECT_MR_INVALIDATED)
 			ib_dma_unmap_sg(sc->ib.dev, mr->sgt.sgl,
 				mr->sgt.nents, mr->dir);
-- 
2.43.0


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

* [PATCH 05/10] smb: client: improve logic in allocate_mr_list()
  2025-10-12 19:10 [PATCH 00/10] improve smbdirect_mr_io lifetime Stefan Metzmacher
                   ` (3 preceding siblings ...)
  2025-10-12 19:10 ` [PATCH 04/10] smb: client: let destroy_mr_list() remove locked from the list Stefan Metzmacher
@ 2025-10-12 19:10 ` Stefan Metzmacher
  2025-10-12 19:10 ` [PATCH 06/10] smb: client: improve logic in smbd_register_mr() Stefan Metzmacher
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Stefan Metzmacher @ 2025-10-12 19:10 UTC (permalink / raw)
  To: linux-cifs, samba-technical
  Cc: metze, Steve French, Tom Talpey, Long Li, Namjae Jeon

- use 'mr' as variable name
- use goto lables for easier cleanup
- use destroy_mr_list()
- style fixes
- INIT_WORK(&sc->mr_io.recovery_work, smbd_mr_recovery_work) on success

This will make further changes easier.

Cc: Steve French <smfrench@gmail.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Long Li <longli@microsoft.com>
Cc: Namjae Jeon <linkinjeon@kernel.org>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 fs/smb/client/smbdirect.c | 65 +++++++++++++++++++++------------------
 1 file changed, 35 insertions(+), 30 deletions(-)

diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c
index b974ca4e0b2e..658ca11cb26c 100644
--- a/fs/smb/client/smbdirect.c
+++ b/fs/smb/client/smbdirect.c
@@ -2385,10 +2385,9 @@ static void destroy_mr_list(struct smbdirect_socket *sc)
 static int allocate_mr_list(struct smbdirect_socket *sc)
 {
 	struct smbdirect_socket_parameters *sp = &sc->parameters;
-	int i;
-	struct smbdirect_mr_io *smbdirect_mr, *tmp;
-
-	INIT_WORK(&sc->mr_io.recovery_work, smbd_mr_recovery_work);
+	struct smbdirect_mr_io *mr;
+	int ret;
+	u32 i;
 
 	if (sp->responder_resources == 0) {
 		log_rdma_mr(ERR, "responder_resources negotiated as 0\n");
@@ -2397,42 +2396,48 @@ static int allocate_mr_list(struct smbdirect_socket *sc)
 
 	/* Allocate more MRs (2x) than hardware responder_resources */
 	for (i = 0; i < sp->responder_resources * 2; i++) {
-		smbdirect_mr = kzalloc(sizeof(*smbdirect_mr), GFP_KERNEL);
-		if (!smbdirect_mr)
-			goto cleanup_entries;
-		smbdirect_mr->mr = ib_alloc_mr(sc->ib.pd, sc->mr_io.type,
-					sp->max_frmr_depth);
-		if (IS_ERR(smbdirect_mr->mr)) {
+		mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+		if (!mr) {
+			ret = -ENOMEM;
+			goto kzalloc_mr_failed;
+		}
+
+		mr->mr = ib_alloc_mr(sc->ib.pd,
+				     sc->mr_io.type,
+				     sp->max_frmr_depth);
+		if (IS_ERR(mr->mr)) {
+			ret = PTR_ERR(mr->mr);
 			log_rdma_mr(ERR, "ib_alloc_mr failed mr_type=%x max_frmr_depth=%x\n",
 				    sc->mr_io.type, sp->max_frmr_depth);
-			goto out;
+			goto ib_alloc_mr_failed;
 		}
-		smbdirect_mr->sgt.sgl = kcalloc(sp->max_frmr_depth,
-						sizeof(struct scatterlist),
-						GFP_KERNEL);
-		if (!smbdirect_mr->sgt.sgl) {
+
+		mr->sgt.sgl = kcalloc(sp->max_frmr_depth,
+				      sizeof(struct scatterlist),
+				      GFP_KERNEL);
+		if (!mr->sgt.sgl) {
+			ret = -ENOMEM;
 			log_rdma_mr(ERR, "failed to allocate sgl\n");
-			ib_dereg_mr(smbdirect_mr->mr);
-			goto out;
+			goto kcalloc_sgl_failed;
 		}
-		smbdirect_mr->state = SMBDIRECT_MR_READY;
-		smbdirect_mr->socket = sc;
+		mr->state = SMBDIRECT_MR_READY;
+		mr->socket = sc;
 
-		list_add_tail(&smbdirect_mr->list, &sc->mr_io.all.list);
+		list_add_tail(&mr->list, &sc->mr_io.all.list);
 		atomic_inc(&sc->mr_io.ready.count);
 	}
+
+	INIT_WORK(&sc->mr_io.recovery_work, smbd_mr_recovery_work);
+
 	return 0;
 
-out:
-	kfree(smbdirect_mr);
-cleanup_entries:
-	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);
-		kfree(smbdirect_mr);
-	}
-	return -ENOMEM;
+kcalloc_sgl_failed:
+	ib_dereg_mr(mr->mr);
+ib_alloc_mr_failed:
+	kfree(mr);
+kzalloc_mr_failed:
+	destroy_mr_list(sc);
+	return ret;
 }
 
 /*
-- 
2.43.0


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

* [PATCH 06/10] smb: client: improve logic in smbd_register_mr()
  2025-10-12 19:10 [PATCH 00/10] improve smbdirect_mr_io lifetime Stefan Metzmacher
                   ` (4 preceding siblings ...)
  2025-10-12 19:10 ` [PATCH 05/10] smb: client: improve logic in allocate_mr_list() Stefan Metzmacher
@ 2025-10-12 19:10 ` Stefan Metzmacher
  2025-10-12 19:10 ` [PATCH 07/10] smb: client: improve logic in smbd_deregister_mr() Stefan Metzmacher
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Stefan Metzmacher @ 2025-10-12 19:10 UTC (permalink / raw)
  To: linux-cifs, samba-technical
  Cc: metze, Steve French, Tom Talpey, Long Li, Namjae Jeon

- use 'mr' as variable name
- style fixes

This will make further changes easier.

Cc: Steve French <smfrench@gmail.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Long Li <longli@microsoft.com>
Cc: Namjae Jeon <linkinjeon@kernel.org>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 fs/smb/client/smbdirect.c | 52 +++++++++++++++++----------------------
 1 file changed, 23 insertions(+), 29 deletions(-)

diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c
index 658ca11cb26c..a863b6fff87a 100644
--- a/fs/smb/client/smbdirect.c
+++ b/fs/smb/client/smbdirect.c
@@ -2517,9 +2517,8 @@ struct smbdirect_mr_io *smbd_register_mr(struct smbd_connection *info,
 {
 	struct smbdirect_socket *sc = &info->socket;
 	struct smbdirect_socket_parameters *sp = &sc->parameters;
-	struct smbdirect_mr_io *smbdirect_mr;
+	struct smbdirect_mr_io *mr;
 	int rc, num_pages;
-	enum dma_data_direction dir;
 	struct ib_reg_wr *reg_wr;
 
 	num_pages = iov_iter_npages(iter, sp->max_frmr_depth + 1);
@@ -2530,49 +2529,45 @@ struct smbdirect_mr_io *smbd_register_mr(struct smbd_connection *info,
 		return NULL;
 	}
 
-	smbdirect_mr = get_mr(sc);
-	if (!smbdirect_mr) {
+	mr = get_mr(sc);
+	if (!mr) {
 		log_rdma_mr(ERR, "get_mr returning NULL\n");
 		return NULL;
 	}
 
-	dir = writing ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-	smbdirect_mr->dir = dir;
-	smbdirect_mr->need_invalidate = need_invalidate;
-	smbdirect_mr->sgt.nents = 0;
-	smbdirect_mr->sgt.orig_nents = 0;
+	mr->dir = writing ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+	mr->need_invalidate = need_invalidate;
+	mr->sgt.nents = 0;
+	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), sp->max_frmr_depth);
-	smbd_iter_to_mr(iter, &smbdirect_mr->sgt, sp->max_frmr_depth);
+	smbd_iter_to_mr(iter, &mr->sgt, sp->max_frmr_depth);
 
-	rc = ib_dma_map_sg(sc->ib.dev, smbdirect_mr->sgt.sgl,
-			   smbdirect_mr->sgt.nents, dir);
+	rc = ib_dma_map_sg(sc->ib.dev, mr->sgt.sgl, mr->sgt.nents, mr->dir);
 	if (!rc) {
 		log_rdma_mr(ERR, "ib_dma_map_sg num_pages=%x dir=%x rc=%x\n",
-			num_pages, dir, rc);
+			    num_pages, mr->dir, rc);
 		goto dma_map_error;
 	}
 
-	rc = ib_map_mr_sg(smbdirect_mr->mr, smbdirect_mr->sgt.sgl,
-			  smbdirect_mr->sgt.nents, NULL, PAGE_SIZE);
-	if (rc != smbdirect_mr->sgt.nents) {
+	rc = ib_map_mr_sg(mr->mr, mr->sgt.sgl, mr->sgt.nents, NULL, PAGE_SIZE);
+	if (rc != mr->sgt.nents) {
 		log_rdma_mr(ERR,
-			"ib_map_mr_sg failed rc = %d nents = %x\n",
-			rc, smbdirect_mr->sgt.nents);
+			    "ib_map_mr_sg failed rc = %d nents = %x\n",
+			    rc, mr->sgt.nents);
 		goto map_mr_error;
 	}
 
-	ib_update_fast_reg_key(smbdirect_mr->mr,
-		ib_inc_rkey(smbdirect_mr->mr->rkey));
-	reg_wr = &smbdirect_mr->wr;
+	ib_update_fast_reg_key(mr->mr, ib_inc_rkey(mr->mr->rkey));
+	reg_wr = &mr->wr;
 	reg_wr->wr.opcode = IB_WR_REG_MR;
-	smbdirect_mr->cqe.done = register_mr_done;
-	reg_wr->wr.wr_cqe = &smbdirect_mr->cqe;
+	mr->cqe.done = register_mr_done;
+	reg_wr->wr.wr_cqe = &mr->cqe;
 	reg_wr->wr.num_sge = 0;
 	reg_wr->wr.send_flags = IB_SEND_SIGNALED;
-	reg_wr->mr = smbdirect_mr->mr;
-	reg_wr->key = smbdirect_mr->mr->rkey;
+	reg_wr->mr = mr->mr;
+	reg_wr->key = mr->mr->rkey;
 	reg_wr->access = writing ?
 			IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE :
 			IB_ACCESS_REMOTE_READ;
@@ -2584,18 +2579,17 @@ struct smbdirect_mr_io *smbd_register_mr(struct smbd_connection *info,
 	 */
 	rc = ib_post_send(sc->ib.qp, &reg_wr->wr, NULL);
 	if (!rc)
-		return smbdirect_mr;
+		return mr;
 
 	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 SMBDIRECT_MR_ERROR*/
 map_mr_error:
-	ib_dma_unmap_sg(sc->ib.dev, smbdirect_mr->sgt.sgl,
-			smbdirect_mr->sgt.nents, smbdirect_mr->dir);
+	ib_dma_unmap_sg(sc->ib.dev, mr->sgt.sgl, mr->sgt.nents, mr->dir);
 
 dma_map_error:
-	smbdirect_mr->state = SMBDIRECT_MR_ERROR;
+	mr->state = SMBDIRECT_MR_ERROR;
 	if (atomic_dec_and_test(&sc->mr_io.used.count))
 		wake_up(&sc->mr_io.cleanup.wait_queue);
 
-- 
2.43.0


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

* [PATCH 07/10] smb: client: improve logic in smbd_deregister_mr()
  2025-10-12 19:10 [PATCH 00/10] improve smbdirect_mr_io lifetime Stefan Metzmacher
                   ` (5 preceding siblings ...)
  2025-10-12 19:10 ` [PATCH 06/10] smb: client: improve logic in smbd_register_mr() Stefan Metzmacher
@ 2025-10-12 19:10 ` Stefan Metzmacher
  2025-10-12 19:10 ` [PATCH 08/10] smb: client: call ib_dma_unmap_sg if mr->sgt.nents is not 0 Stefan Metzmacher
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Stefan Metzmacher @ 2025-10-12 19:10 UTC (permalink / raw)
  To: linux-cifs, samba-technical
  Cc: metze, Steve French, Tom Talpey, Long Li, Namjae Jeon

- use 'mr' as variable name
- style fixes

This will make further changes easier.

Cc: Steve French <smfrench@gmail.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Long Li <longli@microsoft.com>
Cc: Namjae Jeon <linkinjeon@kernel.org>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 fs/smb/client/smbdirect.c | 35 ++++++++++++++++-------------------
 1 file changed, 16 insertions(+), 19 deletions(-)

diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c
index a863b6fff87a..af0642e94d7e 100644
--- a/fs/smb/client/smbdirect.c
+++ b/fs/smb/client/smbdirect.c
@@ -2619,44 +2619,41 @@ 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
  */
-void smbd_deregister_mr(struct smbdirect_mr_io *smbdirect_mr)
+void smbd_deregister_mr(struct smbdirect_mr_io *mr)
 {
-	struct ib_send_wr *wr;
-	struct smbdirect_socket *sc = smbdirect_mr->socket;
-	int rc = 0;
+	struct smbdirect_socket *sc = mr->socket;
+
+	if (mr->need_invalidate) {
+		struct ib_send_wr *wr = &mr->inv_wr;
+		int rc;
 
-	if (smbdirect_mr->need_invalidate) {
 		/* Need to finish local invalidation before returning */
-		wr = &smbdirect_mr->inv_wr;
 		wr->opcode = IB_WR_LOCAL_INV;
-		smbdirect_mr->cqe.done = local_inv_done;
-		wr->wr_cqe = &smbdirect_mr->cqe;
+		mr->cqe.done = local_inv_done;
+		wr->wr_cqe = &mr->cqe;
 		wr->num_sge = 0;
-		wr->ex.invalidate_rkey = smbdirect_mr->mr->rkey;
+		wr->ex.invalidate_rkey = mr->mr->rkey;
 		wr->send_flags = IB_SEND_SIGNALED;
 
-		init_completion(&smbdirect_mr->invalidate_done);
+		init_completion(&mr->invalidate_done);
 		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(sc);
 			goto done;
 		}
-		wait_for_completion(&smbdirect_mr->invalidate_done);
-		smbdirect_mr->need_invalidate = false;
+		wait_for_completion(&mr->invalidate_done);
+		mr->need_invalidate = false;
 	} else
 		/*
 		 * 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 = SMBDIRECT_MR_INVALIDATED;
+		mr->state = SMBDIRECT_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 = SMBDIRECT_MR_READY;
+	if (mr->state == SMBDIRECT_MR_INVALIDATED) {
+		ib_dma_unmap_sg(sc->ib.dev, mr->sgt.sgl, mr->sgt.nents, mr->dir);
+		mr->state = SMBDIRECT_MR_READY;
 		if (atomic_inc_return(&sc->mr_io.ready.count) == 1)
 			wake_up(&sc->mr_io.ready.wait_queue);
 	} else
-- 
2.43.0


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

* [PATCH 08/10] smb: client: call ib_dma_unmap_sg if mr->sgt.nents is not 0
  2025-10-12 19:10 [PATCH 00/10] improve smbdirect_mr_io lifetime Stefan Metzmacher
                   ` (6 preceding siblings ...)
  2025-10-12 19:10 ` [PATCH 07/10] smb: client: improve logic in smbd_deregister_mr() Stefan Metzmacher
@ 2025-10-12 19:10 ` Stefan Metzmacher
  2025-10-12 19:10 ` [PATCH 09/10] smb: client: let destroy_mr_list() call ib_dereg_mr() before ib_dma_unmap_sg() Stefan Metzmacher
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Stefan Metzmacher @ 2025-10-12 19:10 UTC (permalink / raw)
  To: linux-cifs, samba-technical
  Cc: metze, Steve French, Tom Talpey, Long Li, Namjae Jeon

This seems to be the more reliable way to check if we need to
call ib_dma_unmap_sg().

Fixes: c7398583340a ("CIFS: SMBD: Implement RDMA memory registration")
Cc: Steve French <smfrench@gmail.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Long Li <longli@microsoft.com>
Cc: Namjae Jeon <linkinjeon@kernel.org>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 fs/smb/client/smbdirect.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c
index af0642e94d7e..21dcd326af3d 100644
--- a/fs/smb/client/smbdirect.c
+++ b/fs/smb/client/smbdirect.c
@@ -2365,9 +2365,8 @@ static void destroy_mr_list(struct smbdirect_socket *sc)
 	spin_unlock_irqrestore(&sc->mr_io.all.lock, flags);
 
 	list_for_each_entry_safe(mr, tmp, &all_list, list) {
-		if (mr->state == SMBDIRECT_MR_INVALIDATED)
-			ib_dma_unmap_sg(sc->ib.dev, mr->sgt.sgl,
-				mr->sgt.nents, mr->dir);
+		if (mr->sgt.nents)
+			ib_dma_unmap_sg(sc->ib.dev, mr->sgt.sgl, mr->sgt.nents, mr->dir);
 		ib_dereg_mr(mr->mr);
 		kfree(mr->sgt.sgl);
 		list_del(&mr->list);
@@ -2589,6 +2588,7 @@ struct smbdirect_mr_io *smbd_register_mr(struct smbd_connection *info,
 	ib_dma_unmap_sg(sc->ib.dev, mr->sgt.sgl, mr->sgt.nents, mr->dir);
 
 dma_map_error:
+	mr->sgt.nents = 0;
 	mr->state = SMBDIRECT_MR_ERROR;
 	if (atomic_dec_and_test(&sc->mr_io.used.count))
 		wake_up(&sc->mr_io.cleanup.wait_queue);
@@ -2651,8 +2651,12 @@ void smbd_deregister_mr(struct smbdirect_mr_io *mr)
 		 */
 		mr->state = SMBDIRECT_MR_INVALIDATED;
 
-	if (mr->state == SMBDIRECT_MR_INVALIDATED) {
+	if (mr->sgt.nents) {
 		ib_dma_unmap_sg(sc->ib.dev, mr->sgt.sgl, mr->sgt.nents, mr->dir);
+		mr->sgt.nents = 0;
+	}
+
+	if (mr->state == SMBDIRECT_MR_INVALIDATED) {
 		mr->state = SMBDIRECT_MR_READY;
 		if (atomic_inc_return(&sc->mr_io.ready.count) == 1)
 			wake_up(&sc->mr_io.ready.wait_queue);
-- 
2.43.0


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

* [PATCH 09/10] smb: client: let destroy_mr_list() call ib_dereg_mr() before ib_dma_unmap_sg()
  2025-10-12 19:10 [PATCH 00/10] improve smbdirect_mr_io lifetime Stefan Metzmacher
                   ` (7 preceding siblings ...)
  2025-10-12 19:10 ` [PATCH 08/10] smb: client: call ib_dma_unmap_sg if mr->sgt.nents is not 0 Stefan Metzmacher
@ 2025-10-12 19:10 ` Stefan Metzmacher
  2025-10-12 19:10 ` [PATCH 10/10] smb: client: let destroy_mr_list() keep smbdirect_mr_io memory if registered Stefan Metzmacher
  2025-10-13  3:05 ` [PATCH 00/10] improve smbdirect_mr_io lifetime Steve French
  10 siblings, 0 replies; 14+ messages in thread
From: Stefan Metzmacher @ 2025-10-12 19:10 UTC (permalink / raw)
  To: linux-cifs, samba-technical
  Cc: metze, Steve French, Tom Talpey, Long Li, Namjae Jeon

This is more consistent as we call ib_dma_unmap_sg() only
when the memory is no longer registered.

This is the same pattern as calling ib_dma_unmap_sg() after
IB_WR_LOCAL_INV.

Fixes: c7398583340a ("CIFS: SMBD: Implement RDMA memory registration")
Cc: Steve French <smfrench@gmail.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Long Li <longli@microsoft.com>
Cc: Namjae Jeon <linkinjeon@kernel.org>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 fs/smb/client/smbdirect.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c
index 21dcd326af3d..c3330e43488f 100644
--- a/fs/smb/client/smbdirect.c
+++ b/fs/smb/client/smbdirect.c
@@ -2365,9 +2365,10 @@ static void destroy_mr_list(struct smbdirect_socket *sc)
 	spin_unlock_irqrestore(&sc->mr_io.all.lock, flags);
 
 	list_for_each_entry_safe(mr, tmp, &all_list, list) {
+		if (mr->mr)
+			ib_dereg_mr(mr->mr);
 		if (mr->sgt.nents)
 			ib_dma_unmap_sg(sc->ib.dev, mr->sgt.sgl, mr->sgt.nents, mr->dir);
-		ib_dereg_mr(mr->mr);
 		kfree(mr->sgt.sgl);
 		list_del(&mr->list);
 		kfree(mr);
-- 
2.43.0


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

* [PATCH 10/10] smb: client: let destroy_mr_list() keep smbdirect_mr_io memory if registered
  2025-10-12 19:10 [PATCH 00/10] improve smbdirect_mr_io lifetime Stefan Metzmacher
                   ` (8 preceding siblings ...)
  2025-10-12 19:10 ` [PATCH 09/10] smb: client: let destroy_mr_list() call ib_dereg_mr() before ib_dma_unmap_sg() Stefan Metzmacher
@ 2025-10-12 19:10 ` Stefan Metzmacher
  2025-10-15  7:20   ` Stefan Metzmacher
  2025-10-13  3:05 ` [PATCH 00/10] improve smbdirect_mr_io lifetime Steve French
  10 siblings, 1 reply; 14+ messages in thread
From: Stefan Metzmacher @ 2025-10-12 19:10 UTC (permalink / raw)
  To: linux-cifs, samba-technical
  Cc: metze, Steve French, Tom Talpey, Long Li, Namjae Jeon

If a smbdirect_mr_io structure if still visible to callers of
smbd_register_mr() we can't free the related memory when the
connection is disconnected! Otherwise smbd_deregister_mr()
will crash.

Now we use a mutex and refcounting in order to keep the
memory around if the connection is disconnected.

It means smbd_deregister_mr() can be called at any later time to free
the memory, which is no longer referenced by nor referencing the
connection.

It also means smbd_destroy() no longer needs to wait for
mr_io.used.count to become 0.

Fixes: 050b8c374019 ("smbd: Make upper layer decide when to destroy the transport")
Cc: Steve French <smfrench@gmail.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Long Li <longli@microsoft.com>
Cc: Namjae Jeon <linkinjeon@kernel.org>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
 fs/smb/client/smbdirect.c | 145 +++++++++++++++++++++++++++++++++-----
 1 file changed, 126 insertions(+), 19 deletions(-)

diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c
index c3330e43488f..e78b4ceb6d32 100644
--- a/fs/smb/client/smbdirect.c
+++ b/fs/smb/client/smbdirect.c
@@ -1624,19 +1624,7 @@ void smbd_destroy(struct TCP_Server_Info *server)
 	log_rdma_event(INFO, "free receive buffers\n");
 	destroy_receive_buffers(sc);
 
-	/*
-	 * For performance reasons, memory registration and deregistration
-	 * are not locked by srv_mutex. It is possible some processes are
-	 * blocked on transport srv_mutex while holding memory registration.
-	 * Release the transport srv_mutex to allow them to hit the failure
-	 * path when sending data, and then release memory registrations.
-	 */
 	log_rdma_event(INFO, "freeing mr list\n");
-	while (atomic_read(&sc->mr_io.used.count)) {
-		cifs_server_unlock(server);
-		msleep(1000);
-		cifs_server_lock(server);
-	}
 	destroy_mr_list(sc);
 
 	ib_free_cq(sc->ib.send_cq);
@@ -2352,6 +2340,46 @@ static void smbd_mr_recovery_work(struct work_struct *work)
 	}
 }
 
+static void smbd_mr_disable_locked(struct smbdirect_mr_io *mr)
+{
+	struct smbdirect_socket *sc = mr->socket;
+
+	lockdep_assert_held(&mr->mutex);
+
+	if (mr->state == SMBDIRECT_MR_DISABLED)
+		return;
+
+	if (mr->mr)
+		ib_dereg_mr(mr->mr);
+	if (mr->sgt.nents)
+		ib_dma_unmap_sg(sc->ib.dev, mr->sgt.sgl, mr->sgt.nents, mr->dir);
+	kfree(mr->sgt.sgl);
+
+	mr->mr = NULL;
+	mr->sgt.sgl = NULL;
+	mr->sgt.nents = 0;
+
+	mr->state = SMBDIRECT_MR_DISABLED;
+}
+
+static void smbd_mr_free_locked(struct kref *kref)
+{
+	struct smbdirect_mr_io *mr =
+		container_of(kref, struct smbdirect_mr_io, kref);
+
+	lockdep_assert_held(&mr->mutex);
+
+	/*
+	 * smbd_mr_disable_locked() should already be called!
+	 */
+	if (WARN_ON_ONCE(mr->state != SMBDIRECT_MR_DISABLED))
+		smbd_mr_disable_locked(mr);
+
+	mutex_unlock(&mr->mutex);
+	mutex_destroy(&mr->mutex);
+	kfree(mr);
+}
+
 static void destroy_mr_list(struct smbdirect_socket *sc)
 {
 	struct smbdirect_mr_io *mr, *tmp;
@@ -2365,13 +2393,31 @@ static void destroy_mr_list(struct smbdirect_socket *sc)
 	spin_unlock_irqrestore(&sc->mr_io.all.lock, flags);
 
 	list_for_each_entry_safe(mr, tmp, &all_list, list) {
-		if (mr->mr)
-			ib_dereg_mr(mr->mr);
-		if (mr->sgt.nents)
-			ib_dma_unmap_sg(sc->ib.dev, mr->sgt.sgl, mr->sgt.nents, mr->dir);
-		kfree(mr->sgt.sgl);
+		mutex_lock(&mr->mutex);
+
+		smbd_mr_disable_locked(mr);
 		list_del(&mr->list);
-		kfree(mr);
+		mr->socket = NULL;
+
+		/*
+		 * No kref_put_mutex() as it's already locked.
+		 *
+		 * If smbd_mr_free_locked() is called
+		 * and the mutex is unlocked and mr is gone,
+		 * in that case kref_put() returned 1.
+		 *
+		 * If kref_put() returned 0 we know that
+		 * smbd_mr_free_locked() didn't
+		 * run. Not by us nor by anyone else, as we
+		 * still hold the mutex, so we need to unlock.
+		 *
+		 * If the mr is still registered it will
+		 * be dangling (detached from the connection
+		 * waiting for smbd_deregister_mr() to be
+		 * called in order to free the memory.
+		 */
+		if (!kref_put(&mr->kref, smbd_mr_free_locked))
+			mutex_unlock(&mr->mutex);
 	}
 }
 
@@ -2402,6 +2448,9 @@ static int allocate_mr_list(struct smbdirect_socket *sc)
 			goto kzalloc_mr_failed;
 		}
 
+		kref_init(&mr->kref);
+		mutex_init(&mr->mutex);
+
 		mr->mr = ib_alloc_mr(sc->ib.pd,
 				     sc->mr_io.type,
 				     sp->max_frmr_depth);
@@ -2471,6 +2520,7 @@ static struct smbdirect_mr_io *get_mr(struct smbdirect_socket *sc)
 	list_for_each_entry(ret, &sc->mr_io.all.list, list) {
 		if (ret->state == SMBDIRECT_MR_READY) {
 			ret->state = SMBDIRECT_MR_REGISTERED;
+			kref_get(&ret->kref);
 			spin_unlock_irqrestore(&sc->mr_io.all.lock, flags);
 			atomic_dec(&sc->mr_io.ready.count);
 			atomic_inc(&sc->mr_io.used.count);
@@ -2535,6 +2585,8 @@ struct smbdirect_mr_io *smbd_register_mr(struct smbd_connection *info,
 		return NULL;
 	}
 
+	mutex_lock(&mr->mutex);
+
 	mr->dir = writing ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
 	mr->need_invalidate = need_invalidate;
 	mr->sgt.nents = 0;
@@ -2578,8 +2630,16 @@ struct smbdirect_mr_io *smbd_register_mr(struct smbd_connection *info,
 	 * on the next ib_post_send when we actually send I/O to remote peer
 	 */
 	rc = ib_post_send(sc->ib.qp, &reg_wr->wr, NULL);
-	if (!rc)
+	if (!rc) {
+		/*
+		 * get_mr() gave us a reference
+		 * via kref_get(&mr->kref), we keep that and let
+		 * the caller use smbd_deregister_mr()
+		 * to remove it again.
+		 */
+		mutex_unlock(&mr->mutex);
 		return mr;
+	}
 
 	log_rdma_mr(ERR, "ib_post_send failed rc=%x reg_wr->key=%x\n",
 		rc, reg_wr->key);
@@ -2596,6 +2656,25 @@ struct smbdirect_mr_io *smbd_register_mr(struct smbd_connection *info,
 
 	smbd_disconnect_rdma_connection(sc);
 
+	/*
+	 * get_mr() gave us a reference
+	 * via kref_get(&mr->kref), we need to remove it again
+	 * on error.
+	 *
+	 * No kref_put_mutex() as it's already locked.
+	 *
+	 * If smbd_mr_free_locked() is called
+	 * and the mutex is unlocked and mr is gone,
+	 * in that case kref_put() returned 1.
+	 *
+	 * If kref_put() returned 0 we know that
+	 * smbd_mr_free_locked() didn't
+	 * run. Not by us nor by anyone else, as we
+	 * still hold the mutex, so we need to unlock.
+	 */
+	if (!kref_put(&mr->kref, smbd_mr_free_locked))
+		mutex_unlock(&mr->mutex);
+
 	return NULL;
 }
 
@@ -2624,6 +2703,15 @@ void smbd_deregister_mr(struct smbdirect_mr_io *mr)
 {
 	struct smbdirect_socket *sc = mr->socket;
 
+	mutex_lock(&mr->mutex);
+	if (mr->state == SMBDIRECT_MR_DISABLED)
+		goto put_kref;
+
+	if (sc->status != SMBDIRECT_SOCKET_CONNECTED) {
+		smbd_mr_disable_locked(mr);
+		goto put_kref;
+	}
+
 	if (mr->need_invalidate) {
 		struct ib_send_wr *wr = &mr->inv_wr;
 		int rc;
@@ -2640,6 +2728,7 @@ void smbd_deregister_mr(struct smbdirect_mr_io *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_mr_disable_locked(mr);
 			smbd_disconnect_rdma_connection(sc);
 			goto done;
 		}
@@ -2671,6 +2760,24 @@ void smbd_deregister_mr(struct smbdirect_mr_io *mr)
 done:
 	if (atomic_dec_and_test(&sc->mr_io.used.count))
 		wake_up(&sc->mr_io.cleanup.wait_queue);
+
+put_kref:
+	/*
+	 * No kref_put_mutex() as it's already locked.
+	 *
+	 * If smbd_mr_free_locked() is called
+	 * and the mutex is unlocked and mr is gone,
+	 * in that case kref_put() returned 1.
+	 *
+	 * If kref_put() returned 0 we know that
+	 * smbd_mr_free_locked() didn't
+	 * run. Not by us nor by anyone else, as we
+	 * still hold the mutex, so we need to unlock
+	 * and keep the mr in SMBDIRECT_MR_READY or
+	 * SMBDIRECT_MR_ERROR state.
+	 */
+	if (!kref_put(&mr->kref, smbd_mr_free_locked))
+		mutex_unlock(&mr->mutex);
 }
 
 static bool smb_set_sge(struct smb_extract_to_rdma *rdma,
-- 
2.43.0


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

* Re: [PATCH 00/10] improve smbdirect_mr_io lifetime
  2025-10-12 19:10 [PATCH 00/10] improve smbdirect_mr_io lifetime Stefan Metzmacher
                   ` (9 preceding siblings ...)
  2025-10-12 19:10 ` [PATCH 10/10] smb: client: let destroy_mr_list() keep smbdirect_mr_io memory if registered Stefan Metzmacher
@ 2025-10-13  3:05 ` Steve French
  10 siblings, 0 replies; 14+ messages in thread
From: Steve French @ 2025-10-13  3:05 UTC (permalink / raw)
  To: Stefan Metzmacher
  Cc: linux-cifs, samba-technical, Tom Talpey, Long Li, Namjae Jeon

merged into cifs-2.6.git for-next pending more testing

On Sun, Oct 12, 2025 at 2:10 PM Stefan Metzmacher <metze@samba.org> wrote:
>
> Hi,
>
> these patches improve and simplify our handling of
> smbdirect_mr_io structures and their lifetime.
>
> smbd_register_mr() returns a pointer to struct smbdirect_mr_io
> and smbd_deregister_mr() gives the pointer back.
>
> But currently the memory itself is managed by the connection
> (struct smbdirect_socket) and smbd_destroy() has a strange
> wait loop in order to wait for smbd_deregister_mr() being
> called. It means code in smbd_destroy() is aware of
> the server mutex in the generic smb client handling above
> the transport layer.
>
> These patches do some cleanups and fixes before changing
> the logic to use a kref and a mutex in order to allow
> smbd_deregister_mr() being called after smbd_destroy()
> as the memory of smbdirect_mr_io will stay in memory
> but will be detached from the connection.
>
> This makes the code independent of cifs_server_[un]lock()
> and will allow us to move more smbdirect code into common
> functions (shared between client and server).
>
> I think these should go into 6.18.
>
> Stefan Metzmacher (10):
>   smb: smbdirect: introduce smbdirect_mr_io.{kref,mutex} and
>     SMBDIRECT_MR_DISABLED
>   smb: client: change smbd_deregister_mr() to return void
>   smb: client: let destroy_mr_list() call list_del(&mr->list)
>   smb: client: let destroy_mr_list() remove locked from the list
>   smb: client: improve logic in allocate_mr_list()
>   smb: client: improve logic in smbd_register_mr()
>   smb: client: improve logic in smbd_deregister_mr()
>   smb: client: call ib_dma_unmap_sg if mr->sgt.nents is not 0
>   smb: client: let destroy_mr_list() call ib_dereg_mr() before
>     ib_dma_unmap_sg()
>   smb: client: let destroy_mr_list() keep smbdirect_mr_io memory if
>     registered
>
>  fs/smb/client/smbdirect.c                  | 312 ++++++++++++++-------
>  fs/smb/client/smbdirect.h                  |   2 +-
>  fs/smb/common/smbdirect/smbdirect_socket.h |  11 +-
>  3 files changed, 224 insertions(+), 101 deletions(-)
>
> --
> 2.43.0
>


-- 
Thanks,

Steve

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

* Re: [PATCH 10/10] smb: client: let destroy_mr_list() keep smbdirect_mr_io memory if registered
  2025-10-12 19:10 ` [PATCH 10/10] smb: client: let destroy_mr_list() keep smbdirect_mr_io memory if registered Stefan Metzmacher
@ 2025-10-15  7:20   ` Stefan Metzmacher
  2025-10-15 12:47     ` Steve French
  0 siblings, 1 reply; 14+ messages in thread
From: Stefan Metzmacher @ 2025-10-15  7:20 UTC (permalink / raw)
  To: Steve French
  Cc: Tom Talpey, Long Li, Namjae Jeon, linux-cifs, samba-technical

Hi Steve,

as already discussed, one additional hunk is needed...

> @@ -2402,6 +2448,9 @@ static int allocate_mr_list(struct smbdirect_socket *sc)
>   			goto kzalloc_mr_failed;
>   		}
>   
> +		kref_init(&mr->kref);
> +		mutex_init(&mr->mutex);
> +
>   		mr->mr = ib_alloc_mr(sc->ib.pd,
>   				     sc->mr_io.type,
>   				     sp->max_frmr_depth);

Here we're missing the following hunk:

@@ -2483,6 +2483,7 @@ static int allocate_mr_list(struct smbdirect_socket *sc)
  kcalloc_sgl_failed:
         ib_dereg_mr(mr->mr);
  ib_alloc_mr_failed:
+       mutex_destroy(&mr->mutex);
         kfree(mr);
  kzalloc_mr_failed:
         destroy_mr_list(sc);

I fixed it in my for-6.18/fs-smb-20251015-v2 branch,
up to commit e4418cd1d5d80a8c24530ac0a41a5451c44f82bf.
git fetch https://git.samba.org/metze/linux/wip.git for-6.18/fs-smb-20251015-v2

The above hunk is the only difference to the current sfrench-cifs-2.6/for-next
(at commit 7949ce089965bd025a8d46dbaa2f5d0a2bd4ec77), I only moved my commits
to the top. So you can just replace 7949ce089965bd025a8d46dbaa2f5d0a2bd4ec77 by
e4418cd1d5d80a8c24530ac0a41a5451c44f82bf.

Thanks!
metze


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

* Re: [PATCH 10/10] smb: client: let destroy_mr_list() keep smbdirect_mr_io memory if registered
  2025-10-15  7:20   ` Stefan Metzmacher
@ 2025-10-15 12:47     ` Steve French
  0 siblings, 0 replies; 14+ messages in thread
From: Steve French @ 2025-10-15 12:47 UTC (permalink / raw)
  To: Stefan Metzmacher
  Cc: Tom Talpey, Long Li, Namjae Jeon, linux-cifs, samba-technical

cifs-2.6.git for-next updated with newer version of  "smb: client: let
destroy_mr_list() keep smbdirect_mr_io memory if registered"

Let me know if additional changes needed or if you spot any issues

On Wed, Oct 15, 2025 at 2:20 AM Stefan Metzmacher <metze@samba.org> wrote:
>
> Hi Steve,
>
> as already discussed, one additional hunk is needed...
>
> > @@ -2402,6 +2448,9 @@ static int allocate_mr_list(struct smbdirect_socket *sc)
> >                       goto kzalloc_mr_failed;
> >               }
> >
> > +             kref_init(&mr->kref);
> > +             mutex_init(&mr->mutex);
> > +
> >               mr->mr = ib_alloc_mr(sc->ib.pd,
> >                                    sc->mr_io.type,
> >                                    sp->max_frmr_depth);
>
> Here we're missing the following hunk:
>
> @@ -2483,6 +2483,7 @@ static int allocate_mr_list(struct smbdirect_socket *sc)
>   kcalloc_sgl_failed:
>          ib_dereg_mr(mr->mr);
>   ib_alloc_mr_failed:
> +       mutex_destroy(&mr->mutex);
>          kfree(mr);
>   kzalloc_mr_failed:
>          destroy_mr_list(sc);
>
> I fixed it in my for-6.18/fs-smb-20251015-v2 branch,
> up to commit e4418cd1d5d80a8c24530ac0a41a5451c44f82bf.
> git fetch https://git.samba.org/metze/linux/wip.git for-6.18/fs-smb-20251015-v2
>
> The above hunk is the only difference to the current sfrench-cifs-2.6/for-next
> (at commit 7949ce089965bd025a8d46dbaa2f5d0a2bd4ec77), I only moved my commits
> to the top. So you can just replace 7949ce089965bd025a8d46dbaa2f5d0a2bd4ec77 by
> e4418cd1d5d80a8c24530ac0a41a5451c44f82bf.
>
> Thanks!
> metze
>


-- 
Thanks,

Steve

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

end of thread, other threads:[~2025-10-15 12:47 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-12 19:10 [PATCH 00/10] improve smbdirect_mr_io lifetime Stefan Metzmacher
2025-10-12 19:10 ` [PATCH 01/10] smb: smbdirect: introduce smbdirect_mr_io.{kref,mutex} and SMBDIRECT_MR_DISABLED Stefan Metzmacher
2025-10-12 19:10 ` [PATCH 02/10] smb: client: change smbd_deregister_mr() to return void Stefan Metzmacher
2025-10-12 19:10 ` [PATCH 03/10] smb: client: let destroy_mr_list() call list_del(&mr->list) Stefan Metzmacher
2025-10-12 19:10 ` [PATCH 04/10] smb: client: let destroy_mr_list() remove locked from the list Stefan Metzmacher
2025-10-12 19:10 ` [PATCH 05/10] smb: client: improve logic in allocate_mr_list() Stefan Metzmacher
2025-10-12 19:10 ` [PATCH 06/10] smb: client: improve logic in smbd_register_mr() Stefan Metzmacher
2025-10-12 19:10 ` [PATCH 07/10] smb: client: improve logic in smbd_deregister_mr() Stefan Metzmacher
2025-10-12 19:10 ` [PATCH 08/10] smb: client: call ib_dma_unmap_sg if mr->sgt.nents is not 0 Stefan Metzmacher
2025-10-12 19:10 ` [PATCH 09/10] smb: client: let destroy_mr_list() call ib_dereg_mr() before ib_dma_unmap_sg() Stefan Metzmacher
2025-10-12 19:10 ` [PATCH 10/10] smb: client: let destroy_mr_list() keep smbdirect_mr_io memory if registered Stefan Metzmacher
2025-10-15  7:20   ` Stefan Metzmacher
2025-10-15 12:47     ` Steve French
2025-10-13  3:05 ` [PATCH 00/10] improve smbdirect_mr_io lifetime Steve French

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.