[PATCH 6.18 10/49] smb: server: let recv_done() queue a refill when the peer is low on credits

Greg Kroah-Hartman
2026-02-13T13:54:01Z

From: Stefan Metzmacher <metze@samba.org>

commit 8106978d400cc88a99fb94927afe8fec7391ca3e upstream.

In captures I saw that Windows was granting 191 credits in a batch
when its peer posted a lot of messages. We are asking for a
credit target of 255 and 191 is 252*3/4.

So we also use that logic in order to fill the
recv buffers available to the peer.

Fixes: a7eef6144c97 ("smb: server: queue post_recv_credits_work in put_recvmsg() and avoid count_avail_recvmsg")
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 | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

--- a/fs/smb/server/transport_rdma.c
+++ b/fs/smb/server/transport_rdma.c
@@ -661,6 +661,7 @@ static void recv_done(struct ib_cq *cq,
struct smbdirect_data_transfer *data_transfer =
(struct smbdirect_data_transfer *)recvmsg->packet;
u32 remaining_data_length, data_offset, data_length;
+ int current_recv_credits;
u16 old_recv_credit_target;

if (wc->byte_len <
@@ -699,7 +700,7 @@ static void recv_done(struct ib_cq *cq,
}

atomic_dec(&sc->recv_io.posted.count);
- atomic_dec(&sc->recv_io.credits.count);
+ current_recv_credits = atomic_dec_return(&sc->recv_io.credits.count);

old_recv_credit_target = sc->recv_io.credits.target;
sc->recv_io.credits.target =
@@ -719,7 +720,8 @@ static void recv_done(struct ib_cq *cq,
wake_up(&sc->send_io.credits.wait_queue);

if (data_length) {
- if (sc->recv_io.credits.target > old_recv_credit_target)
+ if (current_recv_credits <= (sc->recv_io.credits.target / 4) ||
+ sc->recv_io.credits.target > old_recv_credit_target)
queue_work(sc->workqueue, &sc->recv_io.posted.refill_work);

enqueue_reassembly(sc, recvmsg, (int)data_length);