diff options
| author | Shyam Prasad N <sprasad@microsoft.com> | 2026-05-14 23:38:07 +0530 |
|---|---|---|
| committer | Steve French <stfrench@microsoft.com> | 2026-05-27 17:16:20 -0500 |
| commit | 3608379bf0982e84e8f415a6c21f324bcbdc6a38 (patch) | |
| tree | 2ffbda4f5876115b30d8ca078c287d4fb00eb191 /fs | |
| parent | 9d2491197a00acf8c423512078458c2855102b66 (diff) | |
| download | linux-next-history-3608379bf0982e84e8f415a6c21f324bcbdc6a38.tar.gz | |
cifs: invalidate cfid on unlink/rename/rmdir
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>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/smb/client/inode.c | 30 |
1 files changed, 29 insertions, 1 deletions
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c index 9472c0a6c187c..0af93e881608a 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 */ @@ -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: |
