From: Stefan Metzmacher metze@samba.org
[ Upstream commit 02548c477a90481c1fd0d6e7c84b4504ec2fcc12 ]
This is already handled in the server, but currently it done in a very complex way there. So we do it much simpler.
Note that put_receive_buffer() will take care of it in case data_length is 0.
Cc: Steve French smfrench@gmail.com Cc: Tom Talpey tom@talpey.com Cc: Long Li longli@microsoft.com Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Acked-by: Namjae Jeon linkinjeon@kernel.org Signed-off-by: Stefan Metzmacher metze@samba.org Signed-off-by: Steve French stfrench@microsoft.com Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
Based on my comprehensive analysis, here is my assessment:
## **YES**
This commit should be backported to stable kernel trees.
### **Detailed Analysis:**
#### **Nature of the Change:** This is a **bug fix** for the SMB Direct (RDMA) credit management system in the Linux SMB client. The issue addresses incorrect handling of receive credit targets when the peer server dynamically raises the credit requirement while sending data.
#### **The Bug Explained:**
**Code Flow Analysis (fs/smb/client/smbdirect.c:520-554):**
The `recv_done()` function handles incoming SMB Direct data transfers. The critical flow is:
1. **Line 520:** Decrements `receive_credits` when data is received 2. **Line 521-522:** Updates `receive_credit_target` from peer's `credits_requested` field 3. **Line 550-554:** If `data_length > 0`, calls `enqueue_reassembly()` and returns 4. **Line 554:** If `data_length == 0`, calls `put_receive_buffer()` which queues `post_send_credits_work` (line 1242)
**The Problem:** When the peer raises `receive_credit_target` while sending data (`data_length > 0`), the old code takes the first branch and never calls `put_receive_buffer()`, so `post_send_credits_work` is never queued. This means new receive buffers are not posted to meet the increased credit target.
**The Fix:** Before enqueueing data (lines 551-553 in the new code), it checks if the credit target increased. If so, it explicitly queues `post_send_credits_work` to post additional receive buffers.
#### **Impact Analysis:**
**What `smbd_post_send_credits()` does (lines 413-430):** Posts new receive buffers until `receive_credits` reaches `receive_credit_target`. Without this work being queued:
1. **Protocol Violation:** SMB Direct protocol ([MS-SMBD] 3.1.1.1) requires clients to maintain receive buffers matching the peer's credit requirements 2. **Performance Degradation:** Server cannot send data at optimal rate if client doesn't provide enough receive credits 3. **Potential Stalls:** In extreme cases, both sides could wait for credits, causing connection hangs
**Server Implementation Comparison (fs/smb/server/transport_rdma.c:617-618):** The ksmbd server already handles this correctly using `is_receive_credit_post_required()` before the `if (data_length)` check. The commit message confirms: *"This is already handled in the server, but currently it done in a very complex way there. So we do it much simpler."*
#### **Backport Suitability Indicators:**
✅ **Already backported:** Sasha Levin (stable maintainer) already backported this (commit 2cc5b4e388bea)
✅ **Expert author:** Stefan Metzmacher (166 commits in smbdirect.c, Samba core developer)
✅ **Maintainer ack:** Acked-by Namjae Jeon (ksmbd maintainer)
✅ **Small and focused:** Only 5 lines added (1 variable declaration, 1 check, 1 queue_work call)
✅ **No regressions:** No subsequent fixes or reverts found in commit history after 2025-08-11
✅ **Minimal risk:** Change is confined to credit management logic with clear purpose
✅ **Long-standing code:** SMB Direct has existed since ~2017-2018, this bug likely affected all versions
#### **Risk Assessment:**
**Low risk of regression:** - The new code path only triggers when `receive_credit_target > old_recv_credit_target` AND `data_length > 0` - `post_send_credits_work` is already called in other code paths (put_receive_buffer), so it's well-tested - The work function (smbd_post_send_credits) has safety checks and won't over-allocate
**High value:** - Fixes protocol compliance issue - Improves SMB over RDMA performance and reliability - Aligns client behavior with server implementation
#### **Conclusion:**
This is a clear-cut backport candidate: important bug fix, minimal risk, small change size, expert authorship, already validated by stable tree maintainer, and no dependencies or follow-up fixes needed.
fs/smb/client/smbdirect.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index e0fce5033004c..c9375dc11f634 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -456,6 +456,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) struct smbdirect_socket_parameters *sp = &sc->parameters; struct smbd_connection *info = container_of(sc, struct smbd_connection, socket); + int old_recv_credit_target; u32 data_offset = 0; u32 data_length = 0; u32 remaining_data_length = 0; @@ -518,6 +519,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) }
atomic_dec(&info->receive_credits); + old_recv_credit_target = info->receive_credit_target; info->receive_credit_target = le16_to_cpu(data_transfer->credits_requested); if (le16_to_cpu(data_transfer->credits_granted)) { @@ -548,6 +550,9 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) * reassembly queue and wake up the reading thread */ if (data_length) { + if (info->receive_credit_target > old_recv_credit_target) + queue_work(info->workqueue, &info->post_send_credits_work); + enqueue_reassembly(info, response, data_length); wake_up_interruptible(&sc->recv_io.reassembly.wait_queue); } else