Linux CIFS filesystem development
 help / color / mirror / Atom feed
From: ChenXiaoSong <chenxiaosong@chenxiaosong.com>
To: smfrench@gmail.com, linkinjeon@kernel.org, pc@manguebit.org,
	ronniesahlberg@gmail.com, sprasad@microsoft.com, tom@talpey.com,
	bharathsm@microsoft.com, senozhatsky@chromium.org,
	dhowells@redhat.com, metze@samba.org
Cc: linux-cifs@vger.kernel.org, ChenXiaoSong <chenxiaosong@kylinos.cn>
Subject: [PATCH 8/9] smb/client: send SMB2 cancel requests
Date: Wed,  1 Jul 2026 08:25:06 +0000	[thread overview]
Message-ID: <20260701082507.786487-9-chenxiaosong@chenxiaosong.com> (raw)
In-Reply-To: <20260701082507.786487-1-chenxiaosong@chenxiaosong.com>

From: ChenXiaoSong <chenxiaosong@kylinos.cn>

Wire up the generic cancel callback for SMB2 and later dialects. When a
synchronous wait is interrupted, the client can now send SMB2_CANCEL for
the outstanding mid instead of only marking the mid as cancelled locally.

Build cancel requests from the original request header so the message id,
session id, tree id, signing state, and any saved async id target the
request that is being abandoned. Encrypted shares wrap the cancel in a
transform request before sending it.

Signed-off-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
---
 fs/smb/client/smb2ops.c       |   4 ++
 fs/smb/client/smb2proto.h     |   3 +
 fs/smb/client/smb2transport.c | 105 ++++++++++++++++++++++++++++++++++
 3 files changed, 112 insertions(+)

diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 40f1ae0e9735..1f5dc1d9897f 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -5484,6 +5484,7 @@ static int smb2_make_node(unsigned int xid, struct inode *inode,
 
 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
 struct smb_version_operations smb20_operations = {
+	.send_cancel = smb2_send_cancel,
 	.compare_fids = smb2_compare_fids,
 	.setup_request = smb2_setup_request,
 	.setup_async_request = smb2_setup_async_request,
@@ -5586,6 +5587,7 @@ struct smb_version_operations smb20_operations = {
 #endif /* CIFS_ALLOW_INSECURE_LEGACY */
 
 struct smb_version_operations smb21_operations = {
+	.send_cancel = smb2_send_cancel,
 	.compare_fids = smb2_compare_fids,
 	.setup_request = smb2_setup_request,
 	.setup_async_request = smb2_setup_async_request,
@@ -5690,6 +5692,7 @@ struct smb_version_operations smb21_operations = {
 };
 
 struct smb_version_operations smb30_operations = {
+	.send_cancel = smb2_send_cancel,
 	.compare_fids = smb2_compare_fids,
 	.setup_request = smb2_setup_request,
 	.setup_async_request = smb2_setup_async_request,
@@ -5806,6 +5809,7 @@ struct smb_version_operations smb30_operations = {
 };
 
 struct smb_version_operations smb311_operations = {
+	.send_cancel = smb2_send_cancel,
 	.compare_fids = smb2_compare_fids,
 	.setup_request = smb2_setup_request,
 	.setup_async_request = smb2_setup_async_request,
diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h
index 78a4e1c340f9..855d5c4637f0 100644
--- a/fs/smb/client/smb2proto.h
+++ b/fs/smb/client/smb2proto.h
@@ -40,6 +40,9 @@ int smb2_verify_signature(struct smb_rqst *rqst,
 			  struct TCP_Server_Info *server);
 int smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
 		       bool log_error);
+int smb2_send_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
+		     struct smb_rqst *rqst, struct mid_q_entry *mid,
+		     unsigned int xid);
 struct mid_q_entry *smb2_setup_request(struct cifs_ses *ses,
 				       struct TCP_Server_Info *server,
 				       struct smb_rqst *rqst);
diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index 1143ee52470a..3c113e0e17b1 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -591,6 +591,111 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 		return 0;
 }
 
+int
+smb2_send_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server,
+		 struct smb_rqst *rqst, struct mid_q_entry *mid,
+		 unsigned int xid)
+{
+	struct smb2_pdu *req;
+	struct smb2_hdr *shdr;
+	struct smb2_transform_hdr tr_hdr;
+	struct smb_rqst new_rqst[2] = {};
+	struct kvec tr_iov = {
+		.iov_base = &tr_hdr,
+		.iov_len = sizeof(tr_hdr),
+	};
+	struct kvec iov[1];
+	struct smb_rqst crqst = {
+		.rq_iov = iov,
+		.rq_nvec = 1,
+	};
+	struct cifs_tcon *tcon;
+	__le32 flags;
+	__le32 pid;
+	__le32 tid;
+	__le64 sid;
+	__u64 async_id;
+	bool async_cmd;
+	bool encrypt = false;
+	int rc;
+
+	if (!ses || !server || !rqst || !rqst->rq_iov || !mid)
+		return -EINVAL;
+
+	if (rqst->rq_iov[0].iov_len < sizeof(struct smb2_hdr) + 4)
+		return -EINVAL;
+
+	req = rqst->rq_iov[0].iov_base;
+	if (!req)
+		return -EINVAL;
+
+	shdr = &req->hdr;
+	flags = shdr->Flags & SMB2_FLAGS_SIGNED;
+	pid = shdr->Id.SyncId.ProcessId;
+	tid = shdr->Id.SyncId.TreeId;
+	sid = shdr->SessionId;
+	spin_lock(&mid->mid_lock);
+	async_cmd = mid->async_cmd;
+	async_id = mid->async_id;
+	spin_unlock(&mid->mid_lock);
+
+	tcon = smb2_find_smb_tcon(server, le64_to_cpu(sid), le32_to_cpu(tid));
+	if (tcon) {
+		encrypt = smb3_encryption_required(tcon);
+		cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_cancelled_mid);
+	}
+	if (encrypt)
+		flags = 0;
+
+	/* SMB2_CANCEL targets an existing mid and does not get a response. */
+	memset(req, 0, sizeof(struct smb2_hdr) + 4);
+	shdr->ProtocolId = SMB2_PROTO_NUMBER;
+	shdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
+	shdr->Command = SMB2_CANCEL;
+	shdr->Flags = flags;
+	shdr->MessageId = cpu_to_le64(mid->mid);
+	if (async_cmd) {
+		shdr->Flags |= SMB2_FLAGS_ASYNC_COMMAND;
+		shdr->Id.AsyncId = cpu_to_le64(async_id);
+	} else {
+		shdr->Id.SyncId.ProcessId = pid;
+		shdr->Id.SyncId.TreeId = tid;
+	}
+	shdr->SessionId = sid;
+	req->StructureSize2 = cpu_to_le16(4);
+
+	iov[0].iov_base = req;
+	iov[0].iov_len = sizeof(struct smb2_hdr) + 4;
+
+	cifs_server_lock(server);
+	if (encrypt) {
+		if (!server->ops->init_transform_rq) {
+			rc = smb_EIO(smb_eio_trace_tx_need_transform);
+			goto unlock;
+		}
+
+		new_rqst[0].rq_iov = &tr_iov;
+		new_rqst[0].rq_nvec = 1;
+		rc = server->ops->init_transform_rq(server, 2, new_rqst,
+						    &crqst);
+		if (!rc) {
+			rc = __smb_send_cancel_rqst(server, 2, new_rqst);
+			smb3_free_compound_rqst(1, &new_rqst[1]);
+		}
+	} else {
+		rc = smb2_sign_rqst(&crqst, server);
+		if (!rc)
+			rc = __smb_send_cancel_rqst(server, 1, &crqst);
+	}
+
+unlock:
+	cifs_server_unlock(server);
+
+	cifs_dbg(FYI, "issued SMB2_CANCEL for mid %llu xid=%u rc=%d\n",
+		 mid->mid, xid, rc);
+	return rc;
+}
+
 /*
  * Set message id for the request. Should be called after wait_for_free_request
  * and when srv_mutex is held.
-- 
2.54.0


  parent reply	other threads:[~2026-07-01  8:26 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-01  8:24 [PATCH 0/9] smb/client: improve change notify support ChenXiaoSong
2026-07-01  8:24 ` [PATCH 1/9] smb/client: factor out cifs_new_dir_fileinfo() ChenXiaoSong
2026-07-01  8:25 ` [PATCH 2/9] smb/client: close cached notify handles on closedir ChenXiaoSong
2026-07-01  8:25 ` [PATCH 3/9] smb/client: prepare notify ioctl per-open state ChenXiaoSong
2026-07-01  8:25 ` [PATCH 4/9] smb/client: cache SMB3 change notify handles ChenXiaoSong
2026-07-01  8:25 ` [PATCH 5/9] smb/client: retry change notify after invalid cached handle ChenXiaoSong
2026-07-01  8:25 ` [PATCH 6/9] smb/client: add helpers for sending cancel requests ChenXiaoSong
2026-07-01  8:25 ` [PATCH 7/9] smb/client: remember async ids from SMB2 pending responses ChenXiaoSong
2026-07-01  8:25 ` ChenXiaoSong [this message]
2026-07-01  8:25 ` [PATCH 9/9] smb/client: make SMB2 change notify interruptible ChenXiaoSong

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=20260701082507.786487-9-chenxiaosong@chenxiaosong.com \
    --to=chenxiaosong@chenxiaosong.com \
    --cc=bharathsm@microsoft.com \
    --cc=chenxiaosong@kylinos.cn \
    --cc=dhowells@redhat.com \
    --cc=linkinjeon@kernel.org \
    --cc=linux-cifs@vger.kernel.org \
    --cc=metze@samba.org \
    --cc=pc@manguebit.org \
    --cc=ronniesahlberg@gmail.com \
    --cc=senozhatsky@chromium.org \
    --cc=smfrench@gmail.com \
    --cc=sprasad@microsoft.com \
    --cc=tom@talpey.com \
    /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