mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/4] ksmbd: implement Continuously Available (CA) share support
@ 2026-08-24  0:56 Yunseong Kim
  2026-08-24  0:56 ` [PATCH 1/4] ksmbd: advertise SMB2_GLOBAL_CAP_PERSISTENT_HANDLES Yunseong Kim
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Yunseong Kim @ 2026-08-24  0:56 UTC (permalink / raw)
  To: Namjae Jeon, Sergey Senozhatsky, Tom Talpey, ChenXiaoSong
  Cc: linux-cifs, linux-kernel, Yunseong Kim, ysk

Enable the Continuously Available (CA) share infrastructure in ksmbd,
allowing SMB clients to request and use persistent handles on configured shares.

Background
==========

KSMBD already has a complete in-memory durable handle v1/v2
implementation including the persistent handle data model
(fp->is_persistent), protocol parsing (DH2Q with
SMB2_DHANDLE_FLAG_PERSISTENT), and reconnect validation (DH2C). However,
the server never advertises SMB2_GLOBAL_CAP_PERSISTENT_HANDLES or sets
SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY, making this code path unreachable
by clients.

Per MS-SMB2, a client can only request a persistent handle on a share
that advertises SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY. This creates a
chicken-and-egg: we cannot test persistent handles without first
advertising the CA capability.

Implementation Approach
=======================

I chose a top-down approach: enable the CA share capability first,
validate with real clients using Samba smbtorture, and then layer on-disk
state persistence in a follow-up series. This allows us to:

  1. Get end-to-end protocol validation immediately with smbtorture
  2. Discover client behavioral expectations before building persistence
  3. Deliver incremental value (fencing + write-through + disconnect
     resilience) before the harder persistence work

Note: at this stage, handles survive connection/session loss but NOT full
server crash. On-disk state persistence and startup recovery will be
addressed in a follow-up series.

Patches
=======

  Patch 1: Advertise SMB2_GLOBAL_CAP_PERSISTENT_HANDLES in negotiate
            response when durable handles are enabled globally.

  Patch 2: Set SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY in tree connect
            response for shares with 'continuous availability = yes'.

  Patch 3: Add STATUS_FILE_NOT_AVAILABLE fencing: block conflicting
            opens from other clients while a persistent handle is in
            disconnected state (MS-SMB2 3.3.5.9).

  Patch 4: Enforce FILE_WRITE_THROUGH on all opens to CA shares to
            ensure data commits to stable storage (MS-SMB2 3.3.5.9).

The corresponding ksmbd-tools patch that adds the 'continuous availability'
share configuration parameter is submitted:

  https://github.com/namjaejeon/ksmbd-tools/pull/205

Testing
=======

Build the kernel with debug sanitizers enabled:

  $ vng --build --force \
      --configitem CONFIG_SMB_SERVER=y \
      --configitem CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN=y \
      --configitem CONFIG_SMB_SERVER_KERBEROS5=y \
      --configitem CONFIG_CIFS=y \
      --configitem CONFIG_CIFS_XATTR=y \
      --configitem CONFIG_CIFS_POSIX=y \
      --configitem CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y \
      --configitem CONFIG_CIFS_DEBUG=y \
      --configitem CONFIG_DEBUG_KERNEL=y \
      --configitem CONFIG_KASAN=y \
      --configitem CONFIG_KASAN_GENERIC=y \
      --configitem CONFIG_KASAN_INLINE=y \
      --configitem CONFIG_UBSAN=y \
      --configitem CONFIG_LOCKDEP=y \
      --configitem CONFIG_LOCK_DEBUGGING_SUPPORT=y \
      --configitem CONFIG_PROVE_LOCKING=y \
      --configitem CONFIG_DEBUG_SPINLOCK=y

Run the CA-specific smbtorture tests inside virtme-ng:

  $ vng --memory 4G --exec '
      mkdir -p /tmp/ksmbd_share /tmp/ksmbd_ca /tmp/ksmbd_conf
      chmod 777 /tmp/ksmbd_share /tmp/ksmbd_ca
      useradd -u 4242 -M fuzz 2>/dev/null || true
      ksmbd.adduser -C ksmbd-sandbox.config \
          -P /tmp/ksmbd_conf/ksmbdpwd.db -a fuzz -p fuzz
      ksmbd.mountd -C ksmbd-sandbox.config \
          -P /tmp/ksmbd_conf/ksmbdpwd.db -n &
      sleep 3
      T=/path/to/samba/bin/smbtorture
      $T //127.0.0.1/ca_share -U fuzz%fuzz \
          smb2.durable-v2-open.persistent-open-oplock
      $T //127.0.0.1/ca_share -U fuzz%fuzz \
          smb2.durable-v2-open.persistent-open-lease
      $T //127.0.0.1/ca_share -U fuzz%fuzz \
          smb2.durable-v2-open.reopen1
      dmesg | grep -E "BUG:|KASAN:|UBSAN:|WARNING:.*ksmbd"
  '

Key smbtorture tests for CA validation:

  smb2.durable-v2-open.persistent-open-oplock
    - Connects to CA share, verifies SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY
    - Opens file with DH2Q + SMB2_DHANDLE_FLAG_PERSISTENT + batch oplock
    - Verifies server grants persistent handle (response has flag 0x02)
    - Tests various oplock level combinations with persistent flag

  smb2.durable-v2-open.persistent-open-lease
    - Same as above but with lease (RWH) instead of oplock
    - Disconnects TCP, reconnects with DH2C, verifies handle survives
    - Tests lease level combinations with persistent flag

  smb2.durable-v2-open.reopen1
    - Basic durable v2 disconnect/reconnect lifecycle
    - Opens file with batch oplock + DH2Q
    - Disconnects session, establishes new session
    - Reconnects via DH2C with CreateGuid matching
    - Verifies file access resumes after reconnect

  smb2.durable-v2-open.purge-disconnected-rwh-with-rwh-open
    - Tests conflict resolution: a new RWH open from a different client
      should purge (close) a disconnected durable handle with RWH lease
    - Verifies the server correctly resolves lease conflicts

Results on KASAN/UBSAN/LOCKDEP kernel:

    smb2.durable-v2-open.persistent-open-oplock: PASS
    smb2.durable-v2-open.persistent-open-lease:  PASS
    smb2.durable-v2-open.reopen1:                PASS
    smb2.durable-v2-open.purge-disconnected-rwh-with-rwh-open: PASS

    Zero KASAN/UBSAN/lockdep findings

Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
---
Yunseong Kim (4):
      ksmbd: advertise SMB2_GLOBAL_CAP_PERSISTENT_HANDLES
      ksmbd: set SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY in tree connect
      ksmbd: add fencing for disconnected persistent handles
      ksmbd: enforce write-through on CA share opens

 fs/smb/server/smb2ops.c   | 10 +++++-----
 fs/smb/server/smb2pdu.c   | 33 +++++++++++++++++++++++++++++----
 fs/smb/server/vfs_cache.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 fs/smb/server/vfs_cache.h |  2 ++
 4 files changed, 81 insertions(+), 9 deletions(-)
---
base-commit: 4c6320e0ad400d4ee41cfde614c05a0d87f54e1b
change-id: 20260824-b4-ca-ace9405ce4b0

Best regards,
--  
Yunseong Kim <yunseong.kim@est.tech>


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/4] ksmbd: advertise SMB2_GLOBAL_CAP_PERSISTENT_HANDLES
  2026-08-24  0:56 [PATCH 0/4] ksmbd: implement Continuously Available (CA) share support Yunseong Kim
@ 2026-08-24  0:56 ` Yunseong Kim
  2026-08-24  0:56 ` [PATCH 2/4] ksmbd: set SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY in tree connect Yunseong Kim
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Yunseong Kim @ 2026-08-24  0:56 UTC (permalink / raw)
  To: Namjae Jeon, Sergey Senozhatsky, Tom Talpey, ChenXiaoSong
  Cc: linux-cifs, linux-kernel, Yunseong Kim, ysk

Advertise SMB2_GLOBAL_CAP_PERSISTENT_HANDLES in the SMB2 negotiate
response when durable handles are enabled globally. This tells clients
that the server supports persistent handles, which is a prerequisite
for Continuously Available (CA) share functionality.

The capability is gated by KSMBD_GLOBAL_FLAG_DURABLE_HANDLE (controlled
by 'durable handles = yes' in ksmbd.conf) so administrators must
explicitly enable it.

Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
---
 fs/smb/server/smb2ops.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/fs/smb/server/smb2ops.c b/fs/smb/server/smb2ops.c
index 4578291fb172..414153fa2a68 100644
--- a/fs/smb/server/smb2ops.c
+++ b/fs/smb/server/smb2ops.c
@@ -270,10 +270,8 @@ void init_smb3_02_server(struct ksmbd_conn *conn)
 	if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL)
 		conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL;
 
-	/*
-	 * Durable handles are in-memory only.  Do not advertise persistent
-	 * handles until CA recovery and fencing are implemented.
-	 */
+	if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE)
+		conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_PERSISTENT_HANDLES;
 }
 
 /**
@@ -296,7 +294,9 @@ int init_smb3_11_server(struct ksmbd_conn *conn)
 	if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL)
 		conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL;
 
-	/* See init_smb3_02_server(): persistent handles require CA recovery. */
+	if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE)
+		conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_PERSISTENT_HANDLES;
+
 	return 0;
 }
 

-- 
2.47.3


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 2/4] ksmbd: set SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY in tree connect
  2026-08-24  0:56 [PATCH 0/4] ksmbd: implement Continuously Available (CA) share support Yunseong Kim
  2026-08-24  0:56 ` [PATCH 1/4] ksmbd: advertise SMB2_GLOBAL_CAP_PERSISTENT_HANDLES Yunseong Kim
@ 2026-08-24  0:56 ` Yunseong Kim
  2026-08-24  0:56 ` [PATCH 3/4] ksmbd: add fencing for disconnected persistent handles Yunseong Kim
  2026-08-24  0:56 ` [PATCH 4/4] ksmbd: enforce write-through on CA share opens Yunseong Kim
  3 siblings, 0 replies; 5+ messages in thread
From: Yunseong Kim @ 2026-08-24  0:56 UTC (permalink / raw)
  To: Namjae Jeon, Sergey Senozhatsky, Tom Talpey, ChenXiaoSong
  Cc: linux-cifs, linux-kernel, Yunseong Kim, ysk

Set the SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY capability in the tree
connect response for shares configured with the 'continuous availability'
option (KSMBD_SHARE_FLAG_CONTINUOUS_AVAILABILITY).

This capability is only advertised when persistent handles are also
enabled globally (SMB2_GLOBAL_CAP_PERSISTENT_HANDLES). It informs
clients that the share supports persistent handles, allowing them to
request SMB2_DHANDLE_FLAG_PERSISTENT in DH2Q create contexts.

Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
---
 fs/smb/server/smb2pdu.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index bd74b45ce0e7..b4bf36fb7183 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -2858,10 +2858,15 @@ int smb2_tree_connect(struct ksmbd_work *work)
 	rsp->StructureSize = cpu_to_le16(16);
 out_err1:
 	/*
-	 * A configured CA share is not continuously available until persistent
-	 * open recovery, ownership fencing, and failover are implemented.
+	 * Advertise Continuous Availability on shares configured with
+	 * the CA flag, when persistent handles are enabled globally.
 	 */
-	rsp->Capabilities = 0;
+	if (share && test_share_config_flag(share,
+					    KSMBD_SHARE_FLAG_CONTINUOUS_AVAILABILITY) &&
+	    conn->vals->req_capabilities & SMB2_GLOBAL_CAP_PERSISTENT_HANDLES)
+		rsp->Capabilities = cpu_to_le32(SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY);
+	else
+		rsp->Capabilities = 0;
 	rsp->Reserved = 0;
 	/* default manual caching */
 	rsp->ShareFlags = SMB2_SHAREFLAG_MANUAL_CACHING;

-- 
2.47.3


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 3/4] ksmbd: add fencing for disconnected persistent handles
  2026-08-24  0:56 [PATCH 0/4] ksmbd: implement Continuously Available (CA) share support Yunseong Kim
  2026-08-24  0:56 ` [PATCH 1/4] ksmbd: advertise SMB2_GLOBAL_CAP_PERSISTENT_HANDLES Yunseong Kim
  2026-08-24  0:56 ` [PATCH 2/4] ksmbd: set SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY in tree connect Yunseong Kim
@ 2026-08-24  0:56 ` Yunseong Kim
  2026-08-24  0:56 ` [PATCH 4/4] ksmbd: enforce write-through on CA share opens Yunseong Kim
  3 siblings, 0 replies; 5+ messages in thread
From: Yunseong Kim @ 2026-08-24  0:56 UTC (permalink / raw)
  To: Namjae Jeon, Sergey Senozhatsky, Tom Talpey, ChenXiaoSong
  Cc: linux-cifs, linux-kernel, Yunseong Kim, ysk

Per MS-SMB2 3.3.5.9, when a non-reconnect CREATE request arrives for a
file that has a disconnected persistent handle from a different client,
the server SHOULD fail the request with STATUS_FILE_NOT_AVAILABLE.

Add ksmbd_has_disconnected_persistent_handle() which checks the inode's
open list for any persistent handle that is disconnected (fp->conn is
NULL) and belongs to a different client (different ClientGUID). The same
client is allowed through so it can reconnect its own handle via DH2C.

This fencing prevents data corruption by blocking conflicting opens
while the original client's persistent handle is preserved for
reconnection.

Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
---
 fs/smb/server/smb2pdu.c   | 13 +++++++++++++
 fs/smb/server/vfs_cache.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 fs/smb/server/vfs_cache.h |  2 ++
 3 files changed, 60 insertions(+)

diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index b4bf36fb7183..36efc3f0bf15 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -4427,6 +4427,19 @@ int smb2_open(struct ksmbd_work *work)
 	if (!rc) {
 		file_present = true;
 
+		/*
+		 * MS-SMB2 3.3.5.9: If a non-reconnect CREATE arrives for a
+		 * file with a disconnected persistent handle from a different
+		 * client, fail with STATUS_FILE_NOT_AVAILABLE.
+		 */
+		if (!dh_info.reconnected && !dh_info.replay &&
+		    ksmbd_has_disconnected_persistent_handle(path.dentry,
+							    conn->ClientGUID)) {
+			rsp->hdr.Status = STATUS_FILE_NOT_AVAILABLE;
+			rc = -EAGAIN;
+			goto err_out;
+		}
+
 		if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE) {
 			struct xattr_dos_attrib da;
 
diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c
index 81626d204249..48762f743789 100644
--- a/fs/smb/server/vfs_cache.c
+++ b/fs/smb/server/vfs_cache.c
@@ -788,6 +788,51 @@ bool ksmbd_close_disconnected_durable_delete_on_close(struct dentry *dentry)
 	return closed;
 }
 
+/**
+ * ksmbd_has_disconnected_persistent_handle() - check if a file has a
+ *	disconnected persistent handle that should block new opens (fencing)
+ * @dentry:	dentry of the file being opened
+ * @client_guid: ClientGUID of the requesting client (same client may reconnect)
+ *
+ * Per MS-SMB2 3.3.5.9: when a non-reconnect CREATE arrives for a file with
+ * a disconnected persistent handle, the server SHOULD fail with
+ * STATUS_FILE_NOT_AVAILABLE.  Exception: same ClientGuid with handle-caching
+ * lease or batch oplock may attempt to break the lease.
+ *
+ * Return:	true if a disconnected persistent handle exists from a
+ *		different client.
+ */
+bool ksmbd_has_disconnected_persistent_handle(struct dentry *dentry,
+					      const char *client_guid)
+{
+	struct ksmbd_inode *ci;
+	struct ksmbd_file *fp;
+	bool found = false;
+
+	ci = ksmbd_inode_lookup_lock(dentry);
+	if (!ci)
+		return false;
+
+	down_read(&ci->m_lock);
+	list_for_each_entry(fp, &ci->m_fp_list, node) {
+		if (!fp->is_persistent)
+			continue;
+		if (fp->conn)
+			continue;
+		if (fp->f_state != FP_INITED)
+			continue;
+		/* Same client can reconnect — don't fence it */
+		if (!memcmp(fp->client_guid, client_guid,
+			    SMB2_CLIENT_GUID_SIZE))
+			continue;
+		found = true;
+		break;
+	}
+	up_read(&ci->m_lock);
+	ksmbd_inode_put(ci);
+	return found;
+}
+
 static struct ksmbd_file *ksmbd_fp_get(struct ksmbd_file *fp)
 {
 	if (fp->f_state != FP_INITED)
diff --git a/fs/smb/server/vfs_cache.h b/fs/smb/server/vfs_cache.h
index 502efb16f05f..c562ed1c9ee8 100644
--- a/fs/smb/server/vfs_cache.h
+++ b/fs/smb/server/vfs_cache.h
@@ -207,6 +207,8 @@ void ksmbd_fd_put(struct ksmbd_work *work, struct ksmbd_file *fp);
 struct ksmbd_inode *ksmbd_inode_lookup_lock(struct dentry *d);
 void ksmbd_inode_put(struct ksmbd_inode *ci);
 bool ksmbd_close_disconnected_durable_delete_on_close(struct dentry *dentry);
+bool ksmbd_has_disconnected_persistent_handle(struct dentry *dentry,
+					      const char *client_guid);
 struct ksmbd_file *ksmbd_lookup_global_fd(unsigned long long id);
 struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id);
 void ksmbd_put_durable_fd(struct ksmbd_file *fp);

-- 
2.47.3


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 4/4] ksmbd: enforce write-through on CA share opens
  2026-08-24  0:56 [PATCH 0/4] ksmbd: implement Continuously Available (CA) share support Yunseong Kim
                   ` (2 preceding siblings ...)
  2026-08-24  0:56 ` [PATCH 3/4] ksmbd: add fencing for disconnected persistent handles Yunseong Kim
@ 2026-08-24  0:56 ` Yunseong Kim
  3 siblings, 0 replies; 5+ messages in thread
From: Yunseong Kim @ 2026-08-24  0:56 UTC (permalink / raw)
  To: Namjae Jeon, Sergey Senozhatsky, Tom Talpey, ChenXiaoSong
  Cc: linux-cifs, linux-kernel, Yunseong Kim, ysk

Per MS-SMB2 3.3.5.9, opens on Continuously Available shares MUST have
FILE_WRITE_THROUGH semantics to ensure data is committed to stable
storage before the operation completes. This is required because
persistent handles may need to be recovered after a server failure, and
any data not flushed to disk would be lost.

Force FILE_WRITE_THROUGH_LE in the CreateOptions passed to
ksmbd_vfs_set_fadvise() for files opened on CA shares, which sets
O_SYNC on the underlying file descriptor.

Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
---
 fs/smb/server/smb2pdu.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 36efc3f0bf15..beb5120013ed 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -4681,7 +4681,14 @@ int smb2_open(struct ksmbd_work *work)
 		file_info = FILE_CREATED;
 	}
 
-	ksmbd_vfs_set_fadvise(filp, req->CreateOptions);
+	/*
+	 * MS-SMB2 3.3.5.9: Opens on CA shares MUST have FILE_WRITE_THROUGH
+	 * semantics to ensure data is committed to stable storage.
+	 */
+	if (test_share_config_flag(share, KSMBD_SHARE_FLAG_CONTINUOUS_AVAILABILITY))
+		ksmbd_vfs_set_fadvise(filp, req->CreateOptions | FILE_WRITE_THROUGH_LE);
+	else
+		ksmbd_vfs_set_fadvise(filp, req->CreateOptions);
 
 	/* Obtain Volatile-ID */
 	fp = ksmbd_open_fd(work, filp);

-- 
2.47.3


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-08-24  0:56 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-24  0:56 [PATCH 0/4] ksmbd: implement Continuously Available (CA) share support Yunseong Kim
2026-08-24  0:56 ` [PATCH 1/4] ksmbd: advertise SMB2_GLOBAL_CAP_PERSISTENT_HANDLES Yunseong Kim
2026-08-24  0:56 ` [PATCH 2/4] ksmbd: set SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY in tree connect Yunseong Kim
2026-08-24  0:56 ` [PATCH 3/4] ksmbd: add fencing for disconnected persistent handles Yunseong Kim
2026-08-24  0:56 ` [PATCH 4/4] ksmbd: enforce write-through on CA share opens Yunseong Kim

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®