]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
smb: server: make use of smbdirect_socket.send_io.bcredits
authorStefan Metzmacher <metze@samba.org>
Thu, 22 Jan 2026 17:16:45 +0000 (18:16 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 16 Feb 2026 09:19:41 +0000 (10:19 +0100)
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

index d563b1139ae8c2164ac47b9a3384a1e70bdf942d..8ab9c2093b0f20e331cd2a2072b955beffc668e7 100644 (file)
@@ -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);
@@ -1050,6 +1051,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,
@@ -1057,10 +1059,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,
@@ -1102,6 +1104,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;
 }
 
@@ -1127,6 +1136,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)
 {
@@ -1328,6 +1356,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)
@@ -1380,6 +1418,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);
@@ -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_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;
        }