[PATCH 6.18 11/49] smb: server: make use of smbdirect_socket.send_io.bcredits

Greg Kroah-Hartman
2026-02-13T13:52:21Z

From: Stefan Metzmacher <metze@samba.org>

commit 34abd408c8ba24d7c97bd02ba874d8c714f49db1 upstream.

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@vger.kernel.org> # 6.18.x
Cc: Namjae Jeon <linkinjeon@kernel.org>
Cc: Steve French <smfrench@gmail.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/smb/server/transport_rdma.c | 53 +++++++++++++++++++++++++++++++++++++++--
1 file changed, 51 insertions(+), 2 deletions(-)

--- a/fs/smb/server/transport_rdma.c
+++ b/fs/smb/server/transport_rdma.c
@@ -221,6 +221,7 @@ static void smb_direct_disconnect_wake_u
* 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);
@@ -1050,6 +1051,7 @@ static void smb_direct_send_ctx_init(str
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,
@@ -1057,10 +1059,10 @@ static int smb_direct_flush_send_list(st
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,
@@ -1102,6 +1104,13 @@ static int smb_direct_flush_send_list(st
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;
}

@@ -1127,6 +1136,25 @@ static int wait_for_credits(struct smbdi
} 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)
{
@@ -1328,6 +1356,16 @@ static int smb_direct_post_send_data(str
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)
@@ -1380,6 +1418,13 @@ static int smb_direct_post_send_data(str
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);
@@ -1388,6 +1433,9 @@ header_failed:
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;
}

@@ -1849,6 +1897,7 @@ static int smb_direct_send_negotiate_res
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;
}