* [PATCH v2 2/7] cifs: abort open_cached_dir if we don't request leases
2026-04-21 6:39 [PATCH v2 1/7] cifs: change_conf needs to be called for session setup nspmangalore
@ 2026-04-21 6:39 ` nspmangalore
2026-04-21 15:26 ` Bharath SM
2026-04-21 6:39 ` [PATCH v2 3/7] cifs: invalidate cfid on unlink/rename/rmdir nspmangalore
2026-04-21 13:58 ` [PATCH v2 1/7] cifs: change_conf needs to be called for session setup Bharath SM
2 siblings, 1 reply; 5+ messages in thread
From: nspmangalore @ 2026-04-21 6:39 UTC (permalink / raw)
To: linux-cifs, smfrench, pc, bharathsm, dhowells, henrique.carvalho,
ematsumiya
Cc: Shyam Prasad N, stable
From: Shyam Prasad N <sprasad@microsoft.com>
It is possible that SMB2_open_init may not set lease context based
on the requested oplock level. This can happen when leases have been
temporarily or permanently disabled. When this happens, we will have
open_cached_dir making an open without lease context and the response
will anyway be rejected by open_cached_dir (thereby forcing a close to
discard this open). That's unnecessary two round-trips to the server.
This change adds a check before making the open request to the server
to make sure that SMB2_open_init did add the expected lease context
to the open in open_cached_dir.
Cc: <stable@vger.kernel.org>
Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
---
fs/smb/client/cached_dir.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
index 04bb95091f498..e9917e5204b00 100644
--- a/fs/smb/client/cached_dir.c
+++ b/fs/smb/client/cached_dir.c
@@ -286,6 +286,13 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
&rqst[0], &oplock, &oparms, utf16_path);
if (rc)
goto oshr_free;
+
+ if (oplock != SMB2_OPLOCK_LEVEL_II) {
+ rc = -EINVAL;
+ cifs_dbg(FYI, "unexpected oplock level %d for cached directory\n", oplock);
+ goto oshr_free;
+ }
+
smb2_set_next_command(tcon, &rqst[0]);
memset(&qi_iov, 0, sizeof(qi_iov));
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v2 3/7] cifs: invalidate cfid on unlink/rename/rmdir
2026-04-21 6:39 [PATCH v2 1/7] cifs: change_conf needs to be called for session setup nspmangalore
2026-04-21 6:39 ` [PATCH v2 2/7] cifs: abort open_cached_dir if we don't request leases nspmangalore
@ 2026-04-21 6:39 ` nspmangalore
2026-04-21 13:58 ` [PATCH v2 1/7] cifs: change_conf needs to be called for session setup Bharath SM
2 siblings, 0 replies; 5+ messages in thread
From: nspmangalore @ 2026-04-21 6:39 UTC (permalink / raw)
To: linux-cifs, smfrench, pc, bharathsm, dhowells, henrique.carvalho,
ematsumiya
Cc: Shyam Prasad N, stable
From: Shyam Prasad N <sprasad@microsoft.com>
Today we do not invalidate the cached_dirent or the entire
parent cfid when a dentry in a dir has been removed/moved.
This change invalidates the parent cfid so that we don't serve
directory contents from the cache.
Cc: <stable@vger.kernel.org>
Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
---
fs/smb/client/inode.c | 40 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index 888f9e35f14b8..e077df844c819 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -28,6 +28,23 @@
#include "cached_dir.h"
#include "reparse.h"
+static void cifs_invalidate_cached_dir(struct cifs_tcon *tcon,
+ struct dentry *parent)
+{
+ struct cached_fid *parent_cfid = NULL;
+
+ if (!tcon || !parent)
+ return;
+
+ if (!open_cached_dir_by_dentry(tcon, parent, &parent_cfid)) {
+ mutex_lock(&parent_cfid->dirents.de_mutex);
+ parent_cfid->dirents.is_valid = false;
+ parent_cfid->dirents.is_failed = true;
+ mutex_unlock(&parent_cfid->dirents.de_mutex);
+ close_cached_dir(parent_cfid);
+ }
+}
+
/*
* Set parameters for the netfs library
*/
@@ -322,7 +339,7 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
fattr->cf_uid = uid;
}
}
-
+
fattr->cf_gid = cifs_sb->ctx->linux_gid;
if (!(sbflags & CIFS_MOUNT_OVERR_GID)) {
u64 id = le64_to_cpu(info->Gid);
@@ -2067,6 +2084,9 @@ static int __cifs_unlink(struct inode *dir, struct dentry *dentry, bool sillyren
cifs_set_file_info(inode, attrs, xid, full_path, origattr);
out_reval:
+ if (!rc && dentry->d_parent)
+ cifs_invalidate_cached_dir(tcon, dentry->d_parent);
+
if (inode) {
cifs_inode = CIFS_I(inode);
cifs_inode->time = 0; /* will force revalidate to get info
@@ -2378,7 +2398,6 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
}
rc = server->ops->rmdir(xid, tcon, full_path, cifs_sb);
- cifs_put_tlink(tlink);
cifsInode = CIFS_I(d_inode(direntry));
@@ -2388,6 +2407,8 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
i_size_write(d_inode(direntry), 0);
clear_nlink(d_inode(direntry));
spin_unlock(&d_inode(direntry)->i_lock);
+ if (direntry->d_parent)
+ cifs_invalidate_cached_dir(tcon, direntry->d_parent);
}
/* force revalidate to go get info when needed */
@@ -2402,6 +2423,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
inode_set_ctime_current(d_inode(direntry));
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
+ cifs_put_tlink(tlink);
rmdir_exit:
free_dentry_path(page);
@@ -2501,6 +2523,8 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
struct cifs_sb_info *cifs_sb;
struct tcon_link *tlink;
struct cifs_tcon *tcon;
+ struct dentry *source_parent;
+ struct dentry *target_parent;
bool rehash = false;
unsigned int xid;
int rc, tmprc;
@@ -2532,6 +2556,8 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
if (IS_ERR(tlink))
return PTR_ERR(tlink);
tcon = tlink_tcon(tlink);
+ source_parent = source_dentry->d_parent ? dget(source_dentry->d_parent) : NULL;
+ target_parent = target_dentry->d_parent ? dget(target_dentry->d_parent) : NULL;
server = tcon->ses->server;
page1 = alloc_dentry_path();
@@ -2668,11 +2694,21 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
}
/* force revalidate to go get info when needed */
+ if (!rc) {
+ cifs_invalidate_cached_dir(tcon, source_parent);
+ if (target_parent != source_parent)
+ cifs_invalidate_cached_dir(tcon, target_parent);
+ }
+
CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0;
cifs_rename_exit:
if (rehash)
d_rehash(target_dentry);
+ if (target_parent)
+ dput(target_parent);
+ if (source_parent)
+ dput(source_parent);
kfree(info_buf_source);
free_dentry_path(page2);
free_dentry_path(page1);
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH v2 1/7] cifs: change_conf needs to be called for session setup
2026-04-21 6:39 [PATCH v2 1/7] cifs: change_conf needs to be called for session setup nspmangalore
2026-04-21 6:39 ` [PATCH v2 2/7] cifs: abort open_cached_dir if we don't request leases nspmangalore
2026-04-21 6:39 ` [PATCH v2 3/7] cifs: invalidate cfid on unlink/rename/rmdir nspmangalore
@ 2026-04-21 13:58 ` Bharath SM
2 siblings, 0 replies; 5+ messages in thread
From: Bharath SM @ 2026-04-21 13:58 UTC (permalink / raw)
To: nspmangalore
Cc: linux-cifs, smfrench, pc, bharathsm, dhowells, henrique.carvalho,
ematsumiya, Shyam Prasad N, stable
On Mon, Apr 20, 2026 at 11:40 PM <nspmangalore@gmail.com> wrote:
>
> From: Shyam Prasad N <sprasad@microsoft.com>
>
> Today we skip calling change_conf for negotiates and session setup
> requests. This can be a problem for mchan as the immediate next call
> after session setup could be due to an I/O that is made on the
> mount point. For single channel, this is not a problem as
> there will be several calls after setting up session.
>
> This change enforces calling change_conf for the last session setup
> response, so that echoes and oplocks are not disabled before the
> first request to the server. So if that first request is an open,
> it does not need to disable requesting leases.
>
> Cc: <stable@vger.kernel.org>
> Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
> ---
> fs/smb/client/smb2ops.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
> index 509fcea28a429..3625030d1912f 100644
> --- a/fs/smb/client/smb2ops.c
> +++ b/fs/smb/client/smb2ops.c
> @@ -111,10 +111,19 @@ smb2_add_credits(struct TCP_Server_Info *server,
> cifs_trace_rw_credits_zero_in_flight);
> }
> server->in_flight--;
> +
> + /*
> + * Rebalance credits when an op drains in_flight. For session setup,
> + * do this only when the server actually granted positive credits (>2) so a
> + * newly established secondary channel can reserve echo/oplock credits.
> + */
> if (server->in_flight == 0 &&
> ((optype & CIFS_OP_MASK) != CIFS_NEG_OP) &&
> ((optype & CIFS_OP_MASK) != CIFS_SESS_OP))
> rc = change_conf(server);
> + else if (server->in_flight == 0 &&
> + ((optype & CIFS_OP_MASK) == CIFS_SESS_OP) && add > 2)
> + rc = change_conf(server);
> /*
> * Sometimes server returns 0 credits on oplock break ack - we need to
> * rebalance credits in this case.
> --
I think it would be good to add a comment explaining why the ' add >
2' threshold is chosen
here and the assumption that the final session setup response SMB
server returns '>2' credits.
Otherwise, Changes look good to me.
^ permalink raw reply [flat|nested] 5+ messages in thread