diff options
| author | Stefan Metzmacher <metze@samba.org> | 2026-01-22 20:16:57 +0300 |
|---|---|---|
| committer | Steve French <stfrench@microsoft.com> | 2026-02-09 02:12:58 +0300 |
| commit | 21538121efe6c8c5b51c742fa02cbe820bc48714 (patch) | |
| tree | f911cf0a2df8fc9d6f3f8f48bb0f6ef777759b95 | |
| parent | 2c1ac39ce9cd4112f406775c626eef7f3eb4c481 (diff) | |
| download | linux-21538121efe6c8c5b51c742fa02cbe820bc48714.tar.xz | |
smb: client: make use of smbdirect_socket.send_io.bcredits
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>
| -rw-r--r-- | fs/smb/client/smbdirect.c | 58 |
1 files 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 @@ err_wait_credit: 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; } |
