NFS: Fix up statx() results
If statx has valid attributes available that weren't asked for, then return them and set the result mask appropriately. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
@@ -806,6 +806,28 @@ static bool nfs_need_revalidate_inode(struct inode *inode)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 nfs_get_valid_attrmask(struct inode *inode)
|
||||||
|
{
|
||||||
|
unsigned long cache_validity = READ_ONCE(NFS_I(inode)->cache_validity);
|
||||||
|
u32 reply_mask = STATX_INO | STATX_TYPE;
|
||||||
|
|
||||||
|
if (!(cache_validity & NFS_INO_INVALID_ATIME))
|
||||||
|
reply_mask |= STATX_ATIME;
|
||||||
|
if (!(cache_validity & NFS_INO_REVAL_PAGECACHE)) {
|
||||||
|
if (!(cache_validity & NFS_INO_INVALID_CTIME))
|
||||||
|
reply_mask |= STATX_CTIME;
|
||||||
|
if (!(cache_validity & NFS_INO_INVALID_MTIME))
|
||||||
|
reply_mask |= STATX_MTIME;
|
||||||
|
if (!(cache_validity & NFS_INO_INVALID_SIZE))
|
||||||
|
reply_mask |= STATX_SIZE;
|
||||||
|
}
|
||||||
|
if (!(cache_validity & NFS_INO_INVALID_OTHER))
|
||||||
|
reply_mask |= STATX_UID | STATX_GID | STATX_MODE | STATX_NLINK;
|
||||||
|
if (!(cache_validity & NFS_INO_INVALID_BLOCKS))
|
||||||
|
reply_mask |= STATX_BLOCKS;
|
||||||
|
return reply_mask;
|
||||||
|
}
|
||||||
|
|
||||||
int nfs_getattr(struct user_namespace *mnt_userns, const struct path *path,
|
int nfs_getattr(struct user_namespace *mnt_userns, const struct path *path,
|
||||||
struct kstat *stat, u32 request_mask, unsigned int query_flags)
|
struct kstat *stat, u32 request_mask, unsigned int query_flags)
|
||||||
{
|
{
|
||||||
@@ -824,7 +846,7 @@ int nfs_getattr(struct user_namespace *mnt_userns, const struct path *path,
|
|||||||
|
|
||||||
if ((query_flags & AT_STATX_DONT_SYNC) && !force_sync) {
|
if ((query_flags & AT_STATX_DONT_SYNC) && !force_sync) {
|
||||||
nfs_readdirplus_parent_cache_hit(path->dentry);
|
nfs_readdirplus_parent_cache_hit(path->dentry);
|
||||||
goto out_no_update;
|
goto out_no_revalidate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Flush out writes to the server in order to update c/mtime. */
|
/* Flush out writes to the server in order to update c/mtime. */
|
||||||
@@ -870,6 +892,7 @@ int nfs_getattr(struct user_namespace *mnt_userns, const struct path *path,
|
|||||||
do_update |= cache_validity & NFS_INO_INVALID_OTHER;
|
do_update |= cache_validity & NFS_INO_INVALID_OTHER;
|
||||||
if (request_mask & STATX_BLOCKS)
|
if (request_mask & STATX_BLOCKS)
|
||||||
do_update |= cache_validity & NFS_INO_INVALID_BLOCKS;
|
do_update |= cache_validity & NFS_INO_INVALID_BLOCKS;
|
||||||
|
|
||||||
if (do_update) {
|
if (do_update) {
|
||||||
/* Update the attribute cache */
|
/* Update the attribute cache */
|
||||||
if (!(server->flags & NFS_MOUNT_NOAC))
|
if (!(server->flags & NFS_MOUNT_NOAC))
|
||||||
@@ -883,8 +906,8 @@ int nfs_getattr(struct user_namespace *mnt_userns, const struct path *path,
|
|||||||
nfs_readdirplus_parent_cache_hit(path->dentry);
|
nfs_readdirplus_parent_cache_hit(path->dentry);
|
||||||
out_no_revalidate:
|
out_no_revalidate:
|
||||||
/* Only return attributes that were revalidated. */
|
/* Only return attributes that were revalidated. */
|
||||||
stat->result_mask &= request_mask;
|
stat->result_mask = nfs_get_valid_attrmask(inode) | request_mask;
|
||||||
out_no_update:
|
|
||||||
generic_fillattr(&init_user_ns, inode, stat);
|
generic_fillattr(&init_user_ns, inode, stat);
|
||||||
stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode));
|
stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode));
|
||||||
if (S_ISDIR(inode->i_mode))
|
if (S_ISDIR(inode->i_mode))
|
||||||
|
|||||||
Reference in New Issue
Block a user