From: Sasha Levin <sashal@kernel.org>
To: stable@vger.kernel.org
Cc: Zihan Xi <zihanx@nebusec.ai>, Vega <vega@nebusec.ai>,
Luxing Yin <root@tr0jan.top>,
Frank Sorenson <sorenson@redhat.com>,
Paulo Alcantara <pc@manguebit.org>,
Sasha Levin <sashal@kernel.org>
Subject: [PATCH 5.10.y] smb: client: close completed creates on compound wait errors
Date: Wed, 30 Sep 2026 20:59:10 -0400 [thread overview]
Message-ID: <20261001005910.2548403-1-sashal@kernel.org> (raw)
In-Reply-To: <2026092949-cardinal-reconfirm-a259@gregkh>
From: Zihan Xi <zihanx@nebusec.ai>
[ Upstream commit 6c5c547f037bc18f0b8d0b5db5a648f8f630ce85 ]
compound_send_recv() waits for responses in order. If a later wait is
interrupted, or if a later MID fails during response synchronization, an
earlier CREATE may already have opened a remote handle. The earlier mid
is then released without invoking handle_cancelled_mid(), leaving the
remote handle open because no FID was copied to the caller.
Mark completed earlier mids as cancelled when a compound wait or MID
synchronization aborts. Keep their response buffers attached while the
MIDs are synchronized, and transfer them only after synchronization of
the processed responses, so the release path can inspect successful
CREATE responses and queue SMB2_close() after a later failure. Account for
a remote open only after the close work is allocated and before it is
queued, since the caller has not yet updated num_remote_opens. Mark the
create+close compound used by smb2_unlink() so it is not closed again.
Non-CREATE responses and compounds that already include a close keep their
existing behavior.
Fixes: e0bba0b85481 ("cifs: add compound_send_recv()")
Cc: stable@vger.kernel.org
Reported-by: Vega <vega@nebusec.ai>
Assisted-by: LLM
Co-developed-by: Luxing Yin <root@tr0jan.top>
Signed-off-by: Luxing Yin <root@tr0jan.top>
Signed-off-by: Zihan Xi <zihanx@nebusec.ai>
Tested-by: Frank Sorenson <sorenson@redhat.com>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
[ adapted MID cancellation to use 5.10’s GlobalMid_Lock and MID_WAIT_CANCELLED flag. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/cifs/smb2misc.c | 9 ++++--
fs/cifs/transport.c | 70 ++++++++++++++++++++++++++++++++++-----------
2 files changed, 60 insertions(+), 19 deletions(-)
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index 2013489431ac1..76670fb299859 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -803,7 +803,8 @@ smb2_cancelled_close_fid(struct work_struct *work)
*/
static int
__smb2_handle_cancelled_cmd(struct cifs_tcon *tcon, __u16 cmd, __u64 mid,
- __u64 persistent_fid, __u64 volatile_fid)
+ __u64 persistent_fid, __u64 volatile_fid,
+ bool account_remote_open)
{
struct close_cancelled_open *cancelled;
@@ -817,6 +818,8 @@ __smb2_handle_cancelled_cmd(struct cifs_tcon *tcon, __u16 cmd, __u64 mid,
cancelled->cmd = cmd;
cancelled->mid = mid;
INIT_WORK(&cancelled->work, smb2_cancelled_close_fid);
+ if (account_remote_open)
+ atomic_inc(&tcon->num_remote_opens);
WARN_ON(queue_work(cifsiod_wq, &cancelled->work) == false);
return 0;
@@ -849,7 +852,7 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid,
spin_unlock(&cifs_tcp_ses_lock);
rc = __smb2_handle_cancelled_cmd(tcon, SMB2_CLOSE_HE, 0,
- persistent_fid, volatile_fid);
+ persistent_fid, volatile_fid, false);
if (rc)
cifs_put_tcon(tcon);
@@ -877,7 +880,7 @@ smb2_handle_cancelled_mid(struct mid_q_entry *mid, struct TCP_Server_Info *serve
le16_to_cpu(hdr->Command),
le64_to_cpu(hdr->MessageId),
rsp->PersistentFileId,
- rsp->VolatileFileId);
+ rsp->VolatileFileId, true);
if (rc)
cifs_put_tcon(tcon);
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 9b0fa5fd965a2..3332e1b232b1f 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -1033,6 +1033,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
int *resp_buf_type, struct kvec *resp_iov)
{
int i, j, optype, rc = 0;
+ int num_processed = 0;
struct mid_q_entry *midQ[MAX_COMPOUND];
bool cancelled_mid[MAX_COMPOUND] = {false};
struct cifs_credits credits[MAX_COMPOUND] = {
@@ -1166,6 +1167,17 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
break;
}
if (rc != 0) {
+ /*
+ * A completed CREATE earlier in the compound chain may have
+ * opened a remote handle even though a later wait was
+ * interrupted. Mark it cancelled so the mid release path
+ * invokes the existing unmatched-open cleanup.
+ */
+ spin_lock(&GlobalMid_Lock);
+ for (j = 0; j < i; j++)
+ midQ[j]->mid_flags |= MID_WAIT_CANCELLED;
+ spin_unlock(&GlobalMid_Lock);
+
for (; i < num_rqst; i++) {
cifs_server_dbg(FYI, "Cancelling wait for mid %llu cmd: %d\n",
midQ[i]->mid, le16_to_cpu(midQ[i]->command));
@@ -1188,6 +1200,17 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
rc = cifs_sync_mid_result(midQ[i], server);
if (rc != 0) {
+ /*
+ * A previous CREATE may have completed before this
+ * response failed. Mark it cancelled so its remote
+ * handle is closed when the mid is released.
+ */
+ spin_lock(&GlobalMid_Lock);
+ for (j = 0; j < i; j++)
+ midQ[j]->mid_flags |= MID_WAIT_CANCELLED;
+ spin_unlock(&GlobalMid_Lock);
+ /* Keep their response buffers for cancelled-mid cleanup. */
+ num_processed = 0;
/* mark this mid as cancelled to not free it below */
cancelled_mid[i] = true;
goto out;
@@ -1197,32 +1220,48 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
midQ[i]->mid_state != MID_RESPONSE_READY) {
rc = -EIO;
cifs_dbg(FYI, "Bad MID state?\n");
+ spin_lock(&GlobalMid_Lock);
+ for (j = 0; j < i; j++)
+ midQ[j]->mid_flags |= MID_WAIT_CANCELLED;
+ spin_unlock(&GlobalMid_Lock);
+ num_processed = 0;
goto out;
}
- buf = (char *)midQ[i]->resp_buf;
- resp_iov[i].iov_base = buf;
- resp_iov[i].iov_len = midQ[i]->resp_buf_size +
- server->vals->header_preamble_size;
-
- if (midQ[i]->large_buf)
- resp_buf_type[i] = CIFS_LARGE_BUFFER;
- else
- resp_buf_type[i] = CIFS_SMALL_BUFFER;
-
rc = server->ops->check_receive(midQ[i], server,
flags & CIFS_LOG_ERROR);
+ num_processed = i + 1;
+ }
- /* mark it so buf will not be freed by cifs_delete_mid */
- if ((flags & CIFS_NO_RSP_BUF) == 0)
- midQ[i]->resp_buf = NULL;
-
+out:
+ /*
+ * Delay moving response buffers out of their mids until response
+ * synchronization completes. This lets cancelled-mid cleanup inspect
+ * an earlier CREATE response if a later MID fails.
+ */
+ if (resp_iov) {
+ for (i = 0; i < num_processed; i++) {
+ buf = (char *)midQ[i]->resp_buf;
+ resp_iov[i].iov_base = buf;
+ resp_iov[i].iov_len = midQ[i]->resp_buf_size +
+ server->vals->header_preamble_size;
+
+ if (midQ[i]->large_buf)
+ resp_buf_type[i] = CIFS_LARGE_BUFFER;
+ else
+ resp_buf_type[i] = CIFS_SMALL_BUFFER;
+
+ /* mark it so buf will not be freed by cifs_delete_mid */
+ if ((flags & CIFS_NO_RSP_BUF) == 0)
+ midQ[i]->resp_buf = NULL;
+ }
}
/*
* Compounding is never used during session establish.
*/
- if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) {
+ if (num_processed == num_rqst &&
+ ((ses->status == CifsNew) || (optype & CIFS_NEG_OP))) {
struct kvec iov = {
.iov_base = resp_iov[0].iov_base,
.iov_len = resp_iov[0].iov_len
@@ -1232,7 +1271,6 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
mutex_unlock(&server->srv_mutex);
}
-out:
/*
* This will dequeue all mids. After this it is important that the
* demultiplex_thread will not process any of these mids any futher.
--
2.53.0
prev parent reply other threads:[~2026-10-01 0:59 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-29 11:51 FAILED: patch "[PATCH] smb: client: close completed creates on compound wait errors" failed to apply to 5.10-stable tree gregkh
2026-10-01 0:59 ` Sasha Levin [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261001005910.2548403-1-sashal@kernel.org \
--to=sashal@kernel.org \
--cc=pc@manguebit.org \
--cc=root@tr0jan.top \
--cc=sorenson@redhat.com \
--cc=stable@vger.kernel.org \
--cc=vega@nebusec.ai \
--cc=zihanx@nebusec.ai \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox