]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
cifs: invalidate cfid on unlink/rename/rmdir
authorShyam Prasad N <sprasad@microsoft.com>
Thu, 14 May 2026 18:08:07 +0000 (23:38 +0530)
committerSteve French <stfrench@microsoft.com>
Sun, 14 Jun 2026 20:12:23 +0000 (15:12 -0500)
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>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/inode.c

index 9472c0a6c187ccbaab0d7a3c54a38f0eaf3b14f1..0af93e881608a370e3684307057227f0c873762c 100644 (file)
 #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
  */
@@ -2067,6 +2084,9 @@ psx_del_no_retry:
                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);
@@ -2668,6 +2690,12 @@ unlink_target:
        }
 
        /* force revalidate to go get info when needed */
+       if (!rc) {
+               cifs_invalidate_cached_dir(tcon, source_dentry->d_parent);
+               if (target_dentry->d_parent != source_dentry->d_parent)
+                       cifs_invalidate_cached_dir(tcon, target_dentry->d_parent);
+       }
+
        CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0;
 
 cifs_rename_exit: