[PATCH 6.18 23/49] smb: client: make use of smbdirect_socket.send_io.bcredits

Greg Kroah-Hartman
2026-02-13T13:53:05Z

From: Stefan Metzmacher <metze@samba.org>

commit 21538121efe6c8c5b51c742fa02cbe820bc48714 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: 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>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/smb/client/smbdirect.c | 58 +++++++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 3 deletions(-)

diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c
index ef3b237bccc1..dbb2d939bc44 100644
--- a/fs/smb/client/smbdirect.c
+++ b/fs/smb/client/smbdirect.c
@@ -657,6 +657,7 @@ static bool process_negotiation_response(
sp->max_frmr_depth * PAGE_SIZE);
sp->max_frmr_depth = sp->max_read_write_size / PAGE_SIZE;

+ atomic_set(&sc->send_io.bcredits.count, 1);
sc->recv_io.expected = SMBDIRECT_EXPECT_DATA_TRANSFER;
return true;
}
@@ -1214,6 +1215,7 @@ static void smbd_send_batch_init(struct smbdirect_send_batch *batch,
batch->wr_cnt = 0;
batch->need_invalidate_rkey = need_invalidate_rkey;
batch->remote_key = remote_key;
+ batch->credit = 0;
}

static int smbd_send_batch_flush(struct smbdirect_socket *sc,
@@ -1224,7 +1226,7 @@ static int smbd_send_batch_flush(struct smbdirect_socket *sc,
int ret = 0;

if (list_empty(&batch->msg_list))
- return 0;
+ goto release_credit;

first = list_first_entry(&batch->msg_list,
struct smbdirect_send_io,
@@ -1266,6 +1268,13 @@ static int smbd_send_batch_flush(struct smbdirect_socket *sc,
smbd_free_send_io(last);
}

+release_credit:
+ if (is_last && !ret && batch->credit) {
+ atomic_add(batch->credit, &sc->send_io.bcredits.count);
+ batch->credit = 0;
+ wake_up(&sc->send_io.bcredits.wait_queue);
+ }
+
return ret;
}

@@ -1291,6 +1300,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 *batch)
+{
+ int ret;
+
+ if (batch->credit)
+ return 0;
+
+ ret = wait_for_credits(sc,
+ &sc->send_io.bcredits.wait_queue,
+ &sc->send_io.bcredits.count,
+ 1);
+ if (ret)
+ return ret;
+
+ batch->credit = 1;
+ return 0;
+}
+
static int wait_for_send_lcredit(struct smbdirect_socket *sc,
struct smbdirect_send_batch *batch)
{
@@ -1338,6 +1366,19 @@ static int smbd_post_send_iter(struct smbdirect_socket *sc,
struct smbdirect_send_io *request;
struct smbdirect_data_transfer *packet;
int new_credits = 0;
+ struct smbdirect_send_batch _batch;
+
+ if (!batch) {
+ smbd_send_batch_init(&_batch, false, 0);
+ batch = &_batch;
+ }
+
+ rc = wait_for_send_bcredit(sc, batch);
+ if (rc) {
+ log_outgoing(ERR, "disconnected not sending on wait_bcredit\n");
+ rc = -EAGAIN;
+ goto err_wait_bcredit;
+ }

rc = wait_for_send_lcredit(sc, batch);
if (rc) {
@@ -1432,8 +1473,14 @@ static int smbd_post_send_iter(struct smbdirect_socket *sc,
le32_to_cpu(packet->remaining_data_length));

rc = smbd_post_send(sc, batch, request);
- if (!rc)
- return 0;
+ if (!rc) {
+ if (batch != &_batch)
+ return 0;
+
+ rc = smbd_send_batch_flush(sc, batch, true);
+ if (!rc)
+ return 0;
+ }

err_dma:
smbd_free_send_io(request);
@@ -1447,6 +1494,11 @@ static int smbd_post_send_iter(struct smbdirect_socket *sc,
wake_up(&sc->send_io.lcredits.wait_queue);

err_wait_lcredit:
+ atomic_add(batch->credit, &sc->send_io.bcredits.count);
+ batch->credit = 0;
+ wake_up(&sc->send_io.bcredits.wait_queue);
+
+err_wait_bcredit:
return rc;
}

--
2.53.0