From: rajasimandalos@gmail.com
To: linux-cifs@vger.kernel.org
Cc: bharathsm@microsoft.com, msetiya@microsoft.com,
smfrench@gmail.com, sfrench@samba.org, stfrench@microsoft.com,
Rajasi Mandal <rajasimandal@microsoft.com>
Subject: [PATCH 7/9] smb: client: allow nolease option to be reconfigured on remount
Date: Thu, 2 Jul 2026 11:35:33 +0000 [thread overview]
Message-ID: <20260702113535.4044308-8-rajasimandalos@gmail.com> (raw)
In-Reply-To: <20260702113535.4044308-1-rajasimandalos@gmail.com>
From: Rajasi Mandal <rajasimandal@microsoft.com>
Changing nolease via remount is silently accepted but has no effect:
the value is not propagated to the live tcons, and stale lease-bearing
state from before the switch keeps using the old behavior.
Make nolease take effect on remount:
- Add smb3_sync_tcon_opts() which walks the tlink_tree under
tlink_tree_lock and propagates ctx->no_lease to tcon->no_lease for
every tcon under this superblock so future opens honor the new
setting. Call it from smb3_reconfigure() after the context has
been updated.
- On switch to nolease, drop deferred file handles via
cifs_close_all_deferred_files_sb() (each holds an active lease).
- On switch to nolease, evict cached directory fids via the new
invalidate_all_cached_dirs_sb() helper (each holds a directory
lease).
invalidate_all_cached_dirs_sb() mirrors cifs_close_all_deferred_files_sb():
take tc_count refs on every tcon under tlink_tree_lock, drop the lock,
then call invalidate_all_cached_dirs() per tcon (it can sleep). Two
new tcon_ref trace tags are added for the audit trail.
Move tcon->no_lease out of the bitfield word into a plain bool. As a
runtime writer it now shares storage with need_reconnect/need_reopen_files,
which the reconnect/reopen paths update locklessly; a bitfield write is a
read-modify-write of the whole word and could clobber a concurrent
need_reconnect update. Its own memory location removes that race.
Existing open handles keep their leases until the server breaks them
or userspace closes the file -- nolease only governs new opens.
Signed-off-by: Rajasi Mandal <rajasimandal@microsoft.com>
Reviewed-by: Bharath SM <bharathsm@microsoft.com>
---
fs/smb/client/cached_dir.c | 44 ++++++++++++++++++++++++++++++++++++++
fs/smb/client/cached_dir.h | 1 +
fs/smb/client/cifsglob.h | 2 +-
fs/smb/client/fs_context.c | 40 ++++++++++++++++++++++++++++++++++
fs/smb/client/trace.h | 2 ++
5 files changed, 88 insertions(+), 1 deletion(-)
diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
index 88d5e9a32f28..58d68a8f4d41 100644
--- a/fs/smb/client/cached_dir.c
+++ b/fs/smb/client/cached_dir.c
@@ -637,6 +637,50 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon, bool sync)
flush_delayed_work(&cfids->laundromat_work);
}
+/*
+ * Invalidate cached directory entries across all tcons under a
+ * superblock. Collect references on each tcon under tlink_tree_lock,
+ * then call invalidate_all_cached_dirs() outside the spinlock since it
+ * can sleep. Holding a tc_count reference prevents the tcon from being
+ * freed by tlink_expire_delayed() between dropping the spinlock and
+ * the call.
+ */
+void invalidate_all_cached_dirs_sb(struct cifs_sb_info *cifs_sb)
+{
+ struct rb_root *root = &cifs_sb->tlink_tree;
+ struct rb_node *node;
+ struct cifs_tcon *tcon;
+ struct tcon_link *tlink;
+ struct tcon_list *tmp_list, *q;
+ LIST_HEAD(tcon_head);
+
+ spin_lock(&cifs_sb->tlink_tree_lock);
+ for (node = rb_first(root); node; node = rb_next(node)) {
+ tlink = rb_entry(node, struct tcon_link, tl_rbnode);
+ tcon = tlink_tcon(tlink);
+ if (IS_ERR(tcon))
+ continue;
+ tmp_list = kmalloc_obj(struct tcon_list, GFP_ATOMIC);
+ if (!tmp_list)
+ break;
+ tmp_list->tcon = tcon;
+ spin_lock(&tcon->tc_lock);
+ ++tcon->tc_count;
+ trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
+ netfs_trace_tcon_ref_get_cached_inval_sb);
+ spin_unlock(&tcon->tc_lock);
+ list_add_tail(&tmp_list->entry, &tcon_head);
+ }
+ spin_unlock(&cifs_sb->tlink_tree_lock);
+
+ list_for_each_entry_safe(tmp_list, q, &tcon_head, entry) {
+ invalidate_all_cached_dirs(tmp_list->tcon, true);
+ list_del(&tmp_list->entry);
+ cifs_put_tcon(tmp_list->tcon, netfs_trace_tcon_ref_put_cached_inval_sb);
+ kfree(tmp_list);
+ }
+}
+
static void
cached_dir_offload_close(struct work_struct *work)
{
diff --git a/fs/smb/client/cached_dir.h b/fs/smb/client/cached_dir.h
index fc756836da95..606ba2a0b64f 100644
--- a/fs/smb/client/cached_dir.h
+++ b/fs/smb/client/cached_dir.h
@@ -90,6 +90,7 @@ void close_cached_dir(struct cached_fid *cfid);
void drop_cached_dir_by_name(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, struct cifs_sb_info *cifs_sb);
void close_all_cached_dirs(struct cifs_sb_info *cifs_sb);
+void invalidate_all_cached_dirs_sb(struct cifs_sb_info *cifs_sb);
void invalidate_all_cached_dirs(struct cifs_tcon *tcon, bool sync);
bool cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]);
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 38e27ba6d8f6..713ca152b0ea 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -1262,9 +1262,9 @@ struct cifs_tcon {
bool need_reopen_files:1; /* need to reopen tcon file handles */
bool use_resilient:1; /* use resilient instead of durable handles */
bool use_persistent:1; /* use persistent instead of durable handles */
- bool no_lease:1; /* Do not request leases on files or directories */
bool use_witness:1; /* use witness protocol */
bool dummy:1; /* dummy tcon used for reconnecting channels */
+ bool no_lease; /* Do not request leases on files or directories */
__le32 capabilities;
__u32 share_flags;
__u32 maximal_access;
diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c
index 0a72e1089ff7..53f986d8e9e0 100644
--- a/fs/smb/client/fs_context.c
+++ b/fs/smb/client/fs_context.c
@@ -35,6 +35,7 @@
#include "nterr.h"
#include "rfc1002pdu.h"
#include "fs_context.h"
+#include "cached_dir.h"
DEFINE_MUTEX(cifs_mount_mutex);
@@ -1287,6 +1288,43 @@ static void smb3_sync_ses_chan_max(struct cifs_ses *ses, size_t max_channels)
spin_unlock(&ses->chan_lock);
}
+/*
+ * Propagate ctx->no_lease to every tcon under this superblock so future
+ * opens honor the new setting after a remount. When switching to nolease,
+ * also drop deferred file handles and invalidate cached directory fids,
+ * since each holds an active lease from before the switch.
+ *
+ * Existing open handles keep their leases until the server breaks them
+ * or userspace closes the file -- nolease only governs new opens.
+ */
+static void smb3_sync_tcon_opts(struct cifs_sb_info *cifs_sb,
+ struct smb3_fs_context *ctx)
+{
+ struct tcon_link *tlink;
+ struct cifs_tcon *tcon;
+ struct rb_node *node;
+
+ spin_lock(&cifs_sb->tlink_tree_lock);
+ for (node = rb_first(&cifs_sb->tlink_tree); node; node = rb_next(node)) {
+ tlink = rb_entry(node, struct tcon_link, tl_rbnode);
+ tcon = tlink_tcon(tlink);
+ if (IS_ERR(tcon))
+ continue;
+ tcon->no_lease = ctx->no_lease;
+ }
+ spin_unlock(&cifs_sb->tlink_tree_lock);
+
+ /*
+ * Both _sb() helpers iterate all tcons internally and handle
+ * their own locking. They can sleep, so they must be called
+ * outside tlink_tree_lock.
+ */
+ if (ctx->no_lease) {
+ cifs_close_all_deferred_files_sb(cifs_sb);
+ invalidate_all_cached_dirs_sb(cifs_sb);
+ }
+}
+
/*
* Synchronize server-level options that are stored on TCP_Server_Info
* at mount time. These fields are consulted at runtime (retry logic)
@@ -1483,6 +1521,8 @@ static int smb3_reconfigure(struct fs_context *fc)
#endif
if (!rc)
smb3_sync_server_opts(cifs_sb);
+ if (!rc)
+ smb3_sync_tcon_opts(cifs_sb, cifs_sb->ctx);
return rc;
diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h
index 5b21ad3c15fb..1e61a36759ed 100644
--- a/fs/smb/client/trace.h
+++ b/fs/smb/client/trace.h
@@ -173,6 +173,7 @@
EM(netfs_trace_tcon_ref_free_ipc, "FRE Ipc ") \
EM(netfs_trace_tcon_ref_free_ipc_fail, "FRE Ipc-F ") \
EM(netfs_trace_tcon_ref_free_reconnect_server, "FRE Reconn") \
+ EM(netfs_trace_tcon_ref_get_cached_inval_sb, "GET Ch-IvS") \
EM(netfs_trace_tcon_ref_get_cached_laundromat, "GET Ch-Lau") \
EM(netfs_trace_tcon_ref_get_cached_lease_break, "GET Ch-Lea") \
EM(netfs_trace_tcon_ref_get_cancelled_close, "GET Cn-Cls") \
@@ -186,6 +187,7 @@
EM(netfs_trace_tcon_ref_new_ipc, "NEW Ipc ") \
EM(netfs_trace_tcon_ref_new_reconnect_server, "NEW Reconn") \
EM(netfs_trace_tcon_ref_put_cached_close, "PUT Ch-Cls") \
+ EM(netfs_trace_tcon_ref_put_cached_inval_sb, "PUT Ch-IvS") \
EM(netfs_trace_tcon_ref_put_cancelled_close, "PUT Cn-Cls") \
EM(netfs_trace_tcon_ref_put_cancelled_close_fid, "PUT Cn-Fid") \
EM(netfs_trace_tcon_ref_put_cancelled_mid, "PUT Cn-Mid") \
--
2.43.0
next prev parent reply other threads:[~2026-07-02 11:36 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-02 11:35 [PATCH RESEND 0/9] smb: client: remount reconfigure option fixes rajasimandalos
2026-07-02 11:35 ` [PATCH 1/9] smb: client: sync runtime state into ctx on reconfigure rajasimandalos
2026-07-02 11:35 ` [PATCH 2/9] smb: client: block non-reconfigurable option changes on remount rajasimandalos
2026-07-02 11:35 ` [PATCH 3/9] smb: client: sync retrans " rajasimandalos
2026-07-02 11:35 ` [PATCH 4/9] smb: client: block cache=ro and cache=singleclient " rajasimandalos
2026-07-02 11:35 ` [PATCH 5/9] smb: client: apply rasize " rajasimandalos
2026-07-02 11:35 ` [PATCH 6/9] smb: client: move struct tcon_list to cifsglob.h rajasimandalos
2026-07-02 11:35 ` rajasimandalos [this message]
2026-07-02 11:35 ` [PATCH 8/9] smb: client: review fixes for remount ctx/retrans sync (patches 1-4) rajasimandalos
2026-07-02 11:35 ` [PATCH 9/9] smb: client: review fixes for nolease remount (patch 7) rajasimandalos
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=20260702113535.4044308-8-rajasimandalos@gmail.com \
--to=rajasimandalos@gmail.com \
--cc=bharathsm@microsoft.com \
--cc=linux-cifs@vger.kernel.org \
--cc=msetiya@microsoft.com \
--cc=rajasimandal@microsoft.com \
--cc=sfrench@samba.org \
--cc=smfrench@gmail.com \
--cc=stfrench@microsoft.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.