All of lore.kernel.org
 help / color / mirror / Atom feed
From: Namjae Jeon <linkinjeon@kernel.org>
To: linux-cifs@vger.kernel.org
Cc: smfrench@gmail.com, senozhatsky@chromium.org, tom@talpey.com,
	atteh.mailbox@gmail.com, Namjae Jeon <linkinjeon@kernel.org>
Subject: [PATCH 05/29] ksmbd: handle durable v2 app instance id
Date: Sun, 21 Jun 2026 21:48:20 +0900	[thread overview]
Message-ID: <20260621124844.6235-5-linkinjeon@kernel.org> (raw)
In-Reply-To: <20260621124844.6235-1-linkinjeon@kernel.org>

The SMB2_CREATE_APP_INSTANCE_ID create context is used with durable v2
opens to identify another open from the same application instance. When
a new durable v2 open arrives with the same AppInstanceId as an existing
open, the server should close the previous open without sending an
oplock break notification.

ksmbd ignored this create context. A second durable v2 batch oplock open
with the same AppInstanceId therefore went through the normal competing
open path and sent an oplock break to the first opener. smbtorture
smb2.durable-v2-open.app-instance expects no oplock break and then
expects the old handle to be closed.

Parse and store AppInstanceId for durable v2 opens. Before creating the
new open, find an existing file with the same AppInstanceId and close it
through the normal close teardown path without issuing an oplock break.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
---
 fs/smb/server/smb2pdu.c   | 37 ++++++++++++++++++++
 fs/smb/server/vfs_cache.c | 72 +++++++++++++++++++++++++++++++++++++++
 fs/smb/server/vfs_cache.h |  1 +
 3 files changed, 110 insertions(+)

diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 35db86da79d3..a21760394637 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -2807,8 +2807,10 @@ struct durable_info {
 	unsigned short int type;
 	bool persistent;
 	bool reconnected;
+	bool app_instance_id;
 	unsigned int timeout;
 	char *CreateGuid;
+	char AppInstanceId[SMB2_CREATE_GUID_SIZE];
 };
 
 static int parse_durable_handle_context(struct ksmbd_work *work,
@@ -2993,6 +2995,31 @@ static int parse_durable_handle_context(struct ksmbd_work *work,
 	return err;
 }
 
+static int parse_app_instance_id(struct smb2_create_req *req,
+				 struct durable_info *dh_info)
+{
+	struct create_context *context;
+	char *data;
+
+	context = smb2_find_context_vals(req, SMB2_CREATE_APP_INSTANCE_ID,
+					 SMB2_CREATE_GUID_SIZE);
+	if (IS_ERR(context))
+		return PTR_ERR(context);
+	if (!context)
+		return 0;
+
+	if (le32_to_cpu(context->DataLength) < 20)
+		return -EINVAL;
+
+	data = (char *)context + le16_to_cpu(context->DataOffset);
+	if (data[0] != 20 || data[1])
+		return -EINVAL;
+
+	memcpy(dh_info->AppInstanceId, data + 4, SMB2_CREATE_GUID_SIZE);
+	dh_info->app_instance_id = true;
+	return 0;
+}
+
 /**
  * smb2_open() - handler for smb file open request
  * @work:	smb work containing request buffer
@@ -3135,6 +3162,9 @@ int smb2_open(struct ksmbd_work *work)
 			ksmbd_debug(SMB, "error parsing durable handle context\n");
 			goto err_out2;
 		}
+		rc = parse_app_instance_id(req, &dh_info);
+		if (rc)
+			goto err_out2;
 
 		if (dh_info.reconnected == true) {
 			rc = smb2_check_durable_oplock(conn, share, dh_info.fp,
@@ -3161,6 +3191,9 @@ int smb2_open(struct ksmbd_work *work)
 
 			goto reconnected_fp;
 		}
+
+		if (dh_info.type == DURABLE_REQ_V2 && dh_info.app_instance_id)
+			ksmbd_close_fd_app_instance_id(dh_info.AppInstanceId);
 	} else if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) {
 		lc = parse_lease_state(req);
 		if (IS_ERR(lc)) {
@@ -3775,6 +3808,10 @@ int smb2_open(struct ksmbd_work *work)
 		if (dh_info.type == DURABLE_REQ_V2) {
 			memcpy(fp->create_guid, dh_info.CreateGuid,
 					SMB2_CREATE_GUID_SIZE);
+			if (dh_info.app_instance_id)
+				memcpy(fp->app_instance_id,
+				       dh_info.AppInstanceId,
+				       SMB2_CREATE_GUID_SIZE);
 			if (dh_info.timeout)
 				fp->durable_timeout =
 					min_t(unsigned int, dh_info.timeout,
diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c
index 3546d95df76f..5a2fddadcddf 100644
--- a/fs/smb/server/vfs_cache.c
+++ b/fs/smb/server/vfs_cache.c
@@ -37,6 +37,8 @@ static struct ksmbd_file_table global_ft;
 static atomic_long_t fd_limit;
 static struct kmem_cache *filp_cache;
 
+static int ksmbd_mark_fp_closed(struct ksmbd_file *fp);
+
 #define OPLOCK_NONE      0
 #define OPLOCK_EXCLUSIVE 1
 #define OPLOCK_BATCH     2
@@ -773,6 +775,76 @@ bool ksmbd_has_other_active_fd(struct ksmbd_file *fp)
 	return ret;
 }
 
+static struct ksmbd_file *ksmbd_lookup_fd_app_instance_id(char *app_instance_id)
+{
+	struct ksmbd_file *fp = NULL;
+	unsigned int id;
+
+	if (!memchr_inv(app_instance_id, 0, SMB2_CREATE_GUID_SIZE))
+		return NULL;
+
+	read_lock(&global_ft.lock);
+	idr_for_each_entry(global_ft.idr, fp, id) {
+		if (!memcmp(fp->app_instance_id, app_instance_id,
+			    SMB2_CREATE_GUID_SIZE)) {
+			fp = ksmbd_fp_get(fp);
+			break;
+		}
+	}
+	read_unlock(&global_ft.lock);
+
+	return fp;
+}
+
+int ksmbd_close_fd_app_instance_id(char *app_instance_id)
+{
+	struct ksmbd_file_table *ft;
+	struct ksmbd_file *fp;
+	struct oplock_info *opinfo;
+	int n_to_drop = 0;
+
+	fp = ksmbd_lookup_fd_app_instance_id(app_instance_id);
+	if (!fp)
+		return 0;
+
+	opinfo = opinfo_get(fp);
+	if (!opinfo || !opinfo->sess)
+		goto out;
+
+	ft = &opinfo->sess->file_table;
+	write_lock(&ft->lock);
+	if (fp->f_state == FP_INITED) {
+		if (has_file_id(fp->volatile_id)) {
+			idr_remove(ft->idr, fp->volatile_id);
+			fp->volatile_id = KSMBD_NO_FID;
+		}
+		n_to_drop = ksmbd_mark_fp_closed(fp);
+	}
+	write_unlock(&ft->lock);
+	opinfo_put(opinfo);
+	opinfo = NULL;
+
+	if (!n_to_drop)
+		goto out;
+
+	down_write(&fp->f_ci->m_lock);
+	list_del_init(&fp->node);
+	up_write(&fp->f_ci->m_lock);
+
+	if (atomic_sub_and_test(n_to_drop, &fp->refcount)) {
+		if (fp->conn)
+			atomic_dec(&fp->conn->stats.open_files_count);
+		__ksmbd_close_fd(NULL, fp);
+	}
+	return 0;
+
+out:
+	if (opinfo)
+		opinfo_put(opinfo);
+	ksmbd_put_durable_fd(fp);
+	return 0;
+}
+
 int ksmbd_invalidate_durable_fd(unsigned long long id)
 {
 	struct ksmbd_file *fp;
diff --git a/fs/smb/server/vfs_cache.h b/fs/smb/server/vfs_cache.h
index 4803f41a91ef..ca391d597e2e 100644
--- a/fs/smb/server/vfs_cache.h
+++ b/fs/smb/server/vfs_cache.h
@@ -168,6 +168,7 @@ struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id);
 void ksmbd_put_durable_fd(struct ksmbd_file *fp);
 int ksmbd_invalidate_durable_fd(unsigned long long id);
 bool ksmbd_has_other_active_fd(struct ksmbd_file *fp);
+int ksmbd_close_fd_app_instance_id(char *app_instance_id);
 struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid);
 struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry);
 unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp);
-- 
2.25.1


  parent reply	other threads:[~2026-06-21 12:49 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-21 12:48 [PATCH 01/29] ksmbd: handle missing create contexts for lease opens Namjae Jeon
2026-06-21 12:48 ` [PATCH 02/29] ksmbd: supersede disconnected delete-on-close durable handle Namjae Jeon
2026-06-21 12:48 ` [PATCH 03/29] ksmbd: invalidate durable handles on oplock break Namjae Jeon
2026-06-21 12:48 ` [PATCH 04/29] ksmbd: fix durable reconnect context parsing Namjae Jeon
2026-06-21 12:48 ` Namjae Jeon [this message]
2026-06-21 12:48 ` [PATCH 06/29] ksmbd: preserve open change time across rename Namjae Jeon
2026-06-21 12:48 ` [PATCH 07/29] ksmbd: check parent directory sharing conflicts on rename Namjae Jeon
2026-06-21 12:48 ` [PATCH 08/29] ksmbd: deny renaming directory with open children Namjae Jeon
2026-06-21 12:48 ` [PATCH 09/29] ksmbd: propagate failed command status in related compounds Namjae Jeon
2026-06-21 12:48 ` [PATCH 10/29] ksmbd: validate handle for create or get object id Namjae Jeon
2026-06-21 12:48 ` [PATCH 11/29] ksmbd: preserve compound responses for chained errors Namjae Jeon
2026-06-21 12:48 ` [PATCH 12/29] ksmbd: return success for deferred final close Namjae Jeon
2026-06-21 12:48 ` [PATCH 13/29] ksmbd: send pending interim for last compound I/O Namjae Jeon
2026-06-21 12:48 ` [PATCH 14/29] ksmbd: honor stream delete sharing for base file Namjae Jeon
2026-06-21 12:48 ` [PATCH 15/29] ksmbd: reject empty-attribute synchronize-only create Namjae Jeon
2026-06-21 12:48 ` [PATCH 16/29] ksmbd: tighten create file attribute validation Namjae Jeon
2026-06-21 12:48 ` [PATCH 17/29] ksmbd: return requested create allocation size Namjae Jeon
2026-06-22 23:01   ` Nathan Chancellor
2026-06-23  1:28     ` Namjae Jeon
2026-06-21 12:48 ` [PATCH 18/29] ksmbd: apply create security descriptor first Namjae Jeon
2026-06-21 12:48 ` [PATCH 19/29] ksmbd: downgrade oplock after break timeout Namjae Jeon
2026-06-21 12:48 ` [PATCH 20/29] ksmbd: avoid level II oplock break notification on unlink Namjae Jeon
2026-06-21 12:48 ` [PATCH 21/29] ksmbd: return oplock protocol error for level II ack Namjae Jeon
2026-06-21 12:48 ` [PATCH 22/29] ksmbd: normalize ungrantable lease states Namjae Jeon
2026-06-21 12:48 ` [PATCH 23/29] ksmbd: break handle caching for share conflicts Namjae Jeon
2026-06-21 12:48 ` [PATCH 24/29] ksmbd: break conflicting-open leases only as far as needed Namjae Jeon
2026-06-21 12:48 ` [PATCH 25/29] ksmbd: validate :: stream type against directory create Namjae Jeon
2026-06-21 12:48 ` [PATCH 26/29] ksmbd: treat read-control opens as stat opens only for leases Namjae Jeon
2026-06-21 12:48 ` [PATCH 27/29] ksmbd: start file id allocation at 1 Namjae Jeon
2026-06-21 12:48 ` [PATCH 28/29] ksmbd: sleep interruptibly in the durable handle scavenger Namjae Jeon
2026-06-21 12:48 ` [PATCH 29/29] ksmbd: fix UBSAN array-index-out-of-bounds in decode_compress_ctxt() Namjae Jeon

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=20260621124844.6235-5-linkinjeon@kernel.org \
    --to=linkinjeon@kernel.org \
    --cc=atteh.mailbox@gmail.com \
    --cc=linux-cifs@vger.kernel.org \
    --cc=senozhatsky@chromium.org \
    --cc=smfrench@gmail.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.