[PATCH 2/3] fs: ensure that ->getattr() honors AT_STATX_CACHED
From: Jens Axboe <axboe@kernel.dk>
Date: 2021-01-25 21:56:24
Also in:
io-uring
Subsystem:
9p file system, afs filesystem, ceph distributed file system client (ceph), coda file system, ecrypt file system, filesystems (vfs and infrastructure), fuse filesystem [core], gfs2 file system, kernfs, nfs, sunrpc, and lockd clients, oracle cluster filesystem 2 (ocfs2), orangefs filesystem, the rest, ubi file system (ubifs), udf filesystem, virtual box shared folder vfs driver · Maintainers:
Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet, David Howells, Marc Dionne, Ilya Dryomov, Alex Markuze, Viacheslav Dubeyko, Jan Harkes, Tyler Hicks, Alexander Viro, Christian Brauner, Miklos Szeredi, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo, Trond Myklebust, Anna Schumaker, Mark Fasheh, Joel Becker, Joseph Qi, Mike Marshall, Linus Torvalds, Richard Weinberger, Jan Kara, Jori Koolstra
For filesystems that provide a private ->getattr() implementation, some of them need to do IO to satisfy the request. If we need to block off ->getattr() and AT_STATX_CACHED is set, then return -EAGAIN and have the caller retry. Signed-off-by: Jens Axboe <axboe@kernel.dk> --- fs/9p/vfs_inode.c | 2 ++ fs/afs/inode.c | 3 +++ fs/ceph/inode.c | 2 ++ fs/cifs/inode.c | 3 +++ fs/coda/inode.c | 7 ++++++- fs/ecryptfs/inode.c | 3 +++ fs/fuse/dir.c | 2 ++ fs/gfs2/inode.c | 2 ++ fs/kernfs/inode.c | 8 +++++++- fs/nfs/inode.c | 3 +++ fs/ocfs2/file.c | 3 +++ fs/orangefs/inode.c | 3 +++ fs/ubifs/dir.c | 7 ++++++- fs/udf/symlink.c | 3 +++ fs/vboxsf/utils.c | 4 ++++ 15 files changed, 52 insertions(+), 3 deletions(-)
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 4a937fac1acb..291d74bcf582 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c@@ -1030,6 +1030,8 @@ v9fs_vfs_getattr(const struct path *path, struct kstat *stat, generic_fillattr(d_inode(dentry), stat); return 0; } + if (flags & AT_STATX_CACHED) + return -EAGAIN; fid = v9fs_fid_lookup(dentry); if (IS_ERR(fid)) return PTR_ERR(fid);
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index b0d7b892090d..19ba728ff18f 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c@@ -743,6 +743,9 @@ int afs_getattr(const struct path *path, struct kstat *stat, _enter("{ ino=%lu v=%u }", inode->i_ino, inode->i_generation); + if (query_flags & AT_STATX_CACHED) + return -EAGAIN; + do { read_seqbegin_or_lock(&vnode->cb_lock, &seq); generic_fillattr(inode, stat);
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index adc8fc3c5d85..997f380646fd 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c@@ -2378,6 +2378,8 @@ int ceph_getattr(const struct path *path, struct kstat *stat, /* Skip the getattr altogether if we're asked not to sync */ if (!(flags & AT_STATX_DONT_SYNC)) { + if (flags & AT_STATX_CACHED) + return -EAGAIN; err = ceph_do_getattr(inode, statx_to_caps(request_mask, inode->i_mode), flags & AT_STATX_FORCE_SYNC);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index a83b3a8ffaac..1f8007caa27c 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c@@ -2379,6 +2379,9 @@ int cifs_getattr(const struct path *path, struct kstat *stat, struct inode *inode = d_inode(dentry); int rc; + if (flags & AT_STATX_CACHED) + return -EAGAIN; + /* * We need to be sure that all dirty pages are written and the server * has actual ctime, mtime and file length.
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index b1c70e2b9b1e..444f1ef97b08 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c@@ -254,7 +254,12 @@ static void coda_evict_inode(struct inode *inode) int coda_getattr(const struct path *path, struct kstat *stat, u32 request_mask, unsigned int flags) { - int err = coda_revalidate_inode(d_inode(path->dentry)); + int err; + + if (flags & AT_STATX_CACHED) + return -EAGAIN; + + err = coda_revalidate_inode(d_inode(path->dentry)); if (!err) generic_fillattr(d_inode(path->dentry), stat); return err;
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index e23752d9a79f..61fdb5a0dbdc 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c@@ -980,6 +980,9 @@ static int ecryptfs_getattr_link(const struct path *path, struct kstat *stat, char *target; size_t targetsiz; + if (flags & AT_STATX_CACHED) + return -EAGAIN; + target = ecryptfs_readlink_lower(dentry, &targetsiz); if (!IS_ERR(target)) { kfree(target);
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 78f9f209078c..638722d3c1ed 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c@@ -1084,6 +1084,8 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file, sync = time_before64(fi->i_time, get_jiffies_64()); if (sync) { + if (flags & AT_STATX_CACHED) + return -EAGAIN; forget_all_cached_acls(inode); err = fuse_do_getattr(inode, stat, file); } else if (stat) {
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index c1b77e8d6b1c..3d485d9f1afe 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c@@ -2032,6 +2032,8 @@ static int gfs2_getattr(const struct path *path, struct kstat *stat, gfs2_holder_mark_uninitialized(&gh); if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { + if (flags & AT_STATX_CACHED) + return -EAGAIN; error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); if (error) return error;
diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c
index fc2469a20fed..2193b3c0b9cd 100644
--- a/fs/kernfs/inode.c
+++ b/fs/kernfs/inode.c@@ -189,7 +189,13 @@ int kernfs_iop_getattr(const struct path *path, struct kstat *stat, struct inode *inode = d_inode(path->dentry); struct kernfs_node *kn = inode->i_private; - mutex_lock(&kernfs_mutex); + if (query_flags & AT_STATX_CACHED) { + if (!mutex_trylock(&kernfs_mutex)) + return -EAGAIN; + } else { + mutex_lock(&kernfs_mutex); + } + kernfs_refresh_inode(kn, inode); mutex_unlock(&kernfs_mutex);
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 522aa10a1a3e..1eb167c14884 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c@@ -799,6 +799,9 @@ int nfs_getattr(const struct path *path, struct kstat *stat, trace_nfs_getattr_enter(inode); + if (query_flags & AT_STATX_CACHED) + return -EAGAIN; + if ((query_flags & AT_STATX_DONT_SYNC) && !force_sync) { nfs_readdirplus_parent_cache_hit(path->dentry); goto out_no_update;
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 85979e2214b3..e48d0c33fb46 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c@@ -1306,6 +1306,9 @@ int ocfs2_getattr(const struct path *path, struct kstat *stat, struct ocfs2_super *osb = sb->s_fs_info; int err; + if (flags & AT_STATX_CACHED) + return -EAGAIN; + err = ocfs2_inode_revalidate(path->dentry); if (err) { if (err != -ENOENT)
diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
index 48f0547d4850..4864334e40e8 100644
--- a/fs/orangefs/inode.c
+++ b/fs/orangefs/inode.c@@ -900,6 +900,9 @@ int orangefs_getattr(const struct path *path, struct kstat *stat, "orangefs_getattr: called on %pd mask %u\n", path->dentry, request_mask); + if (flags & AT_STATX_CACHED) + return -EAGAIN; + ret = orangefs_inode_getattr(inode, request_mask & STATX_SIZE ? ORANGEFS_GETATTR_SIZE : 0); if (ret == 0) {
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 9a6b8660425a..c199b260c50c 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c@@ -1573,7 +1573,12 @@ int ubifs_getattr(const struct path *path, struct kstat *stat, struct inode *inode = d_inode(path->dentry); struct ubifs_inode *ui = ubifs_inode(inode); - mutex_lock(&ui->ui_mutex); + if (flags & AT_STATX_CACHED) { + if (!mutex_trylock(&ui->ui_mutex)) + return -EAGAIN; + } else { + mutex_lock(&ui->ui_mutex); + } if (ui->flags & UBIFS_APPEND_FL) stat->attributes |= STATX_ATTR_APPEND;
diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c
index c973db239604..0edd973b8a43 100644
--- a/fs/udf/symlink.c
+++ b/fs/udf/symlink.c@@ -159,6 +159,9 @@ static int udf_symlink_getattr(const struct path *path, struct kstat *stat, struct inode *inode = d_backing_inode(dentry); struct page *page; + if (flags & AT_STATX_CACHED) + return -EAGAIN; + generic_fillattr(inode, stat); page = read_mapping_page(inode->i_mapping, 0, NULL); if (IS_ERR(page))
diff --git a/fs/vboxsf/utils.c b/fs/vboxsf/utils.c
index 018057546067..dc93cd59290d 100644
--- a/fs/vboxsf/utils.c
+++ b/fs/vboxsf/utils.c@@ -228,6 +228,10 @@ int vboxsf_getattr(const struct path *path, struct kstat *kstat, sf_i->force_restat = 1; fallthrough; default: + if (flags & AT_STATX_CACHED) { + err = -EAGAIN; + break; + } err = vboxsf_inode_revalidate(dentry); } if (err)
--
2.30.0