]> www.infradead.org Git - users/hch/misc.git/commitdiff
fs/9p: Refresh metadata in d_revalidate for uncached mode too
authorTingmao Wang <m@maowtm.org>
Sun, 6 Apr 2025 16:18:42 +0000 (17:18 +0100)
committerDominique Martinet <asmadeus@codewreck.org>
Sat, 23 Aug 2025 06:34:46 +0000 (15:34 +0900)
Currently if another process keeps a file open, due to existing dentry in
the dcache, other processes will not see updated metadata of that file if
it is changed on the server, even in uncached mode.

This can also manifest as -ENODATA when reading a file that has shrunk on
the server (even if it's re-opened in another process), or -ENOTSUPP if
the file has changed type (e.g. regular file to directory) on the server.
We can end up in a situation where both `readdir` or `read` fails until
the file is closed by all processes using it.

This commit fixes that, and invalidates the dentry altogether if the inode
type is changed (for uncached mode).

Signed-off-by: Tingmao Wang <m@maowtm.org>
Message-ID: <bfac417f65cc1d6812be822f8913f0d4ba0c1052.1743956147.git.m@maowtm.org>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
fs/9p/vfs_dentry.c
fs/9p/vfs_inode.c
fs/9p/vfs_inode_dotl.c

index 04795508a7957125f89b5587bd9f8c71f6da276c..ffa45ee38f83e35ebc6059815e1424139efc9b11 100644 (file)
@@ -66,6 +66,7 @@ static int __v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
        struct p9_fid *fid;
        struct inode *inode;
        struct v9fs_inode *v9inode;
+       unsigned int cached;
 
        if (flags & LOOKUP_RCU)
                return -ECHILD;
@@ -75,7 +76,11 @@ static int __v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
                goto out_valid;
 
        v9inode = V9FS_I(inode);
-       if (v9inode->cache_validity & V9FS_INO_INVALID_ATTR) {
+       struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
+
+       cached = v9ses->cache & (CACHE_META | CACHE_LOOSE);
+
+       if (!cached || v9inode->cache_validity & V9FS_INO_INVALID_ATTR) {
                int retval;
                struct v9fs_session_info *v9ses;
 
@@ -92,6 +97,8 @@ static int __v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 
                if (retval == -ENOENT)
                        return 0;
+               if (!cached && v9inode->cache_validity & V9FS_INO_INVALID_ATTR)
+                       return 0;
                if (retval < 0)
                        return retval;
        }
@@ -127,6 +134,8 @@ const struct dentry_operations v9fs_cached_dentry_operations = {
 };
 
 const struct dentry_operations v9fs_dentry_operations = {
+       .d_revalidate = v9fs_lookup_revalidate,
+       .d_weak_revalidate = __v9fs_lookup_revalidate,
        .d_release = v9fs_dentry_release,
        .d_unalias_trylock = v9fs_dentry_unalias_trylock,
        .d_unalias_unlock = v9fs_dentry_unalias_unlock,
index 399d455d50d626f300ad9b3e4a13aadbaf37e550..caff65d8b2bbf80d9b9e6cb0cfc26d4b391370a8 100644 (file)
@@ -1349,8 +1349,14 @@ int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode)
         * Don't update inode if the file type is different
         */
        umode = p9mode2unixmode(v9ses, st, &rdev);
-       if (inode_wrong_type(inode, umode))
+       if (inode_wrong_type(inode, umode)) {
+               /*
+                * Do this as a way of letting the caller know the inode should not
+                * be reused
+                */
+               v9fs_invalidate_inode_attr(inode);
                goto out;
+       }
 
        /*
         * We don't want to refresh inode->i_size,
index 5b5fda617b805a87153ad51f23a23efc7f355454..0fafc603b64a43cb0f46ae07f48aabe1151c5911 100644 (file)
@@ -902,8 +902,14 @@ int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
        /*
         * Don't update inode if the file type is different
         */
-       if (inode_wrong_type(inode, st->st_mode))
+       if (inode_wrong_type(inode, st->st_mode)) {
+               /*
+                * Do this as a way of letting the caller know the inode should not
+                * be reused
+                */
+               v9fs_invalidate_inode_attr(inode);
                goto out;
+       }
 
        /*
         * We don't want to refresh inode->i_size,