[PATCH v2 05/20] smb: server: make use of smbdirect_socket.send_io.bcredits
Stefan Metzmacher
metze at samba.org
Thu Jan 22 17:16:45 UTC 2026
It turns out that our code will corrupt the stream of
reassabled data transfer messages when we trigger an
immendiate (empty) send.
In order to fix this we'll have a single 'batch' credit per
connection. And code getting that credit is free to use
as much messages until remaining_length reaches 0, then
the batch credit it given back and the next logical send can
happen.
Cc: <stable at vger.kernel.org> # 6.18.x
Cc: Namjae Jeon <linkinjeon at kernel.org>
Cc: Steve French <smfrench at gmail.com>
Cc: Tom Talpey <tom at talpey.com>
Cc: linux-cifs at vger.kernel.org
Cc: samba-technical at lists.samba.org
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Acked-by: Namjae Jeon <linkinjeon at kernel.org>
---
fs/smb/server/transport_rdma.c | 53 ++++++++++++++++++++++++++++++++--
1 file changed, 51 insertions(+), 2 deletions(-)
diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c
index fc29b4c3b645..84a654715ed5 100644
--- a/fs/smb/server/transport_rdma.c
+++ b/fs/smb/server/transport_rdma.c
@@ -221,6 +221,7 @@ static void smb_direct_disconnect_wake_up_all(struct smbdirect_socket *sc)
* in order to notice the broken connection.
*/
wake_up_all(&sc->status_wait);
+ wake_up_all(&sc->send_io.bcredits.wait_queue);
wake_up_all(&sc->send_io.lcredits.wait_queue);
wake_up_all(&sc->send_io.credits.wait_queue);
wake_up_all(&sc->send_io.pending.zero_wait_queue);
@@ -1152,6 +1153,7 @@ static void smb_direct_send_ctx_init(struct smbdirect_send_batch *send_ctx,
send_ctx->wr_cnt = 0;
send_ctx->need_invalidate_rkey = need_invalidate_rkey;
send_ctx->remote_key = remote_key;
+ send_ctx->credit = 0;
}
static int smb_direct_flush_send_list(struct smbdirect_socket *sc,
@@ -1159,10 +1161,10 @@ static int smb_direct_flush_send_list(struct smbdirect_socket *sc,
bool is_last)
{
struct smbdirect_send_io *first, *last;
- int ret;
+ int ret = 0;
if (list_empty(&send_ctx->msg_list))
- return 0;
+ goto release_credit;
first = list_first_entry(&send_ctx->msg_list,
struct smbdirect_send_io,
@@ -1204,6 +1206,13 @@ static int smb_direct_flush_send_list(struct smbdirect_socket *sc,
smb_direct_free_sendmsg(sc, last);
}
+release_credit:
+ if (is_last && !ret && send_ctx->credit) {
+ atomic_add(send_ctx->credit, &sc->send_io.bcredits.count);
+ send_ctx->credit = 0;
+ wake_up(&sc->send_io.bcredits.wait_queue);
+ }
+
return ret;
}
@@ -1229,6 +1238,25 @@ static int wait_for_credits(struct smbdirect_socket *sc,
} while (true);
}
+static int wait_for_send_bcredit(struct smbdirect_socket *sc,
+ struct smbdirect_send_batch *send_ctx)
+{
+ int ret;
+
+ if (send_ctx->credit)
+ return 0;
+
+ ret = wait_for_credits(sc,
+ &sc->send_io.bcredits.wait_queue,
+ &sc->send_io.bcredits.count,
+ 1);
+ if (ret)
+ return ret;
+
+ send_ctx->credit = 1;
+ return 0;
+}
+
static int wait_for_send_lcredit(struct smbdirect_socket *sc,
struct smbdirect_send_batch *send_ctx)
{
@@ -1432,6 +1460,16 @@ static int smb_direct_post_send_data(struct smbdirect_socket *sc,
struct smbdirect_send_io *msg;
int data_length;
struct scatterlist sg[SMBDIRECT_SEND_IO_MAX_SGE - 1];
+ struct smbdirect_send_batch _send_ctx;
+
+ if (!send_ctx) {
+ smb_direct_send_ctx_init(&_send_ctx, false, 0);
+ send_ctx = &_send_ctx;
+ }
+
+ ret = wait_for_send_bcredit(sc, send_ctx);
+ if (ret)
+ goto bcredit_failed;
ret = wait_for_send_lcredit(sc, send_ctx);
if (ret)
@@ -1483,6 +1521,13 @@ static int smb_direct_post_send_data(struct smbdirect_socket *sc,
ret = post_sendmsg(sc, send_ctx, msg);
if (ret)
goto err;
+
+ if (send_ctx == &_send_ctx) {
+ ret = smb_direct_flush_send_list(sc, send_ctx, true);
+ if (ret)
+ goto err;
+ }
+
return 0;
err:
smb_direct_free_sendmsg(sc, msg);
@@ -1491,6 +1536,9 @@ static int smb_direct_post_send_data(struct smbdirect_socket *sc,
credit_failed:
atomic_inc(&sc->send_io.lcredits.count);
lcredit_failed:
+ atomic_add(send_ctx->credit, &sc->send_io.bcredits.count);
+ send_ctx->credit = 0;
+bcredit_failed:
return ret;
}
@@ -1962,6 +2010,7 @@ static int smb_direct_send_negotiate_response(struct smbdirect_socket *sc,
resp->max_fragmented_size =
cpu_to_le32(sp->max_fragmented_recv_size);
+ atomic_set(&sc->send_io.bcredits.count, 1);
sc->recv_io.expected = SMBDIRECT_EXPECT_DATA_TRANSFER;
sc->status = SMBDIRECT_SOCKET_CONNECTED;
}
--
2.43.0
More information about the samba-technical
mailing list