smb: client: let send_done handle a completion without IB_SEND_SIGNALED

With smbdirect_send_batch processing we likely have requests without
IB_SEND_SIGNALED, which will be destroyed in the final request
that has IB_SEND_SIGNALED set.

If the connection is broken all requests are signaled
even without explicit IB_SEND_SIGNALED.

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>
This commit is contained in:
Stefan Metzmacher 2026-01-22 18:17:00 +01:00 committed by Steve French
parent 5b1c614965
commit cf74fcdc43

View file

@ -554,6 +554,32 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc)
log_rdma_send(INFO, "smbdirect_send_io 0x%p completed wc->status=%s\n",
request, ib_wc_status_msg(wc->status));
if (unlikely(!(request->wr.send_flags & IB_SEND_SIGNALED))) {
/*
* This happens when smbdirect_send_io is a sibling
* before the final message, it is signaled on
* error anyway, so we need to skip
* smbdirect_connection_free_send_io here,
* otherwise is will destroy the memory
* of the siblings too, which will cause
* use after free problems for the others
* triggered from ib_drain_qp().
*/
if (wc->status != IB_WC_SUCCESS)
goto skip_free;
/*
* This should not happen!
* But we better just close the
* connection...
*/
log_rdma_send(ERR,
"unexpected send completion wc->status=%s (%d) wc->opcode=%d\n",
ib_wc_status_msg(wc->status), wc->status, wc->opcode);
smbd_disconnect_rdma_connection(sc);
return;
}
/*
* Free possible siblings and then the main send_io
*/
@ -567,6 +593,7 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc)
lcredits += 1;
if (wc->status != IB_WC_SUCCESS || wc->opcode != IB_WC_SEND) {
skip_free:
if (wc->status != IB_WC_WR_FLUSH_ERR)
log_rdma_send(ERR, "wc->status=%s wc->opcode=%d\n",
ib_wc_status_msg(wc->status), wc->opcode);