Support statx() mask and query flags parameters
authorTrond Myklebust <trond.myklebust@primarydata.com>
Thu, 4 Jan 2018 22:46:09 +0000 (17:46 -0500)
committerTrond Myklebust <trond.myklebust@primarydata.com>
Mon, 15 Jan 2018 04:06:29 +0000 (23:06 -0500)
Support the query flags AT_STATX_FORCE_SYNC by forcing an attribute
revalidation, and AT_STATX_DONT_SYNC by returning cached attributes
only.

Use the mask to optimise away server revalidation for attributes
that are not being requested by the user.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
fs/nfs/inode.c

index b992d23..deeb7d1 100644 (file)
@@ -735,12 +735,20 @@ int nfs_getattr(const struct path *path, struct kstat *stat,
                u32 request_mask, unsigned int query_flags)
 {
        struct inode *inode = d_inode(path->dentry);
-       int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME;
+       struct nfs_server *server = NFS_SERVER(inode);
+       unsigned long cache_validity;
        int err = 0;
+       bool force_sync = query_flags & AT_STATX_FORCE_SYNC;
+       bool do_update = false;
 
        trace_nfs_getattr_enter(inode);
+
+       if ((query_flags & AT_STATX_DONT_SYNC) && !force_sync)
+               goto out_no_update;
+
        /* Flush out writes to the server in order to update c/mtime.  */
-       if (S_ISREG(inode->i_mode)) {
+       if ((request_mask & (STATX_CTIME|STATX_MTIME)) &&
+                       S_ISREG(inode->i_mode)) {
                err = filemap_write_and_wait(inode->i_mapping);
                if (err)
                        goto out;
@@ -757,24 +765,42 @@ int nfs_getattr(const struct path *path, struct kstat *stat,
         */
        if ((path->mnt->mnt_flags & MNT_NOATIME) ||
            ((path->mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)))
-               need_atime = 0;
-
-       if (need_atime || nfs_need_revalidate_inode(inode)) {
-               struct nfs_server *server = NFS_SERVER(inode);
-
+               request_mask &= ~STATX_ATIME;
+
+       /* Is the user requesting attributes that might need revalidation? */
+       if (!(request_mask & (STATX_MODE|STATX_NLINK|STATX_ATIME|STATX_CTIME|
+                                       STATX_MTIME|STATX_UID|STATX_GID|
+                                       STATX_SIZE|STATX_BLOCKS)))
+               goto out_no_revalidate;
+
+       /* Check whether the cached attributes are stale */
+       do_update |= force_sync || nfs_attribute_cache_expired(inode);
+       cache_validity = READ_ONCE(NFS_I(inode)->cache_validity);
+       do_update |= cache_validity &
+               (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL);
+       if (request_mask & STATX_ATIME)
+               do_update |= cache_validity & NFS_INO_INVALID_ATIME;
+       if (request_mask & (STATX_CTIME|STATX_MTIME))
+               do_update |= cache_validity & NFS_INO_REVAL_PAGECACHE;
+       if (do_update) {
+               /* Update the attribute cache */
                if (!(server->flags & NFS_MOUNT_NOAC))
                        nfs_readdirplus_parent_cache_miss(path->dentry);
                else
                        nfs_readdirplus_parent_cache_hit(path->dentry);
                err = __nfs_revalidate_inode(server, inode);
+               if (err)
+                       goto out;
        } else
                nfs_readdirplus_parent_cache_hit(path->dentry);
-       if (!err) {
-               generic_fillattr(inode, stat);
-               stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode));
-               if (S_ISDIR(inode->i_mode))
-                       stat->blksize = NFS_SERVER(inode)->dtsize;
-       }
+out_no_revalidate:
+       /* Only return attributes that were revalidated. */
+       stat->result_mask &= request_mask;
+out_no_update:
+       generic_fillattr(inode, stat);
+       stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode));
+       if (S_ISDIR(inode->i_mode))
+               stat->blksize = NFS_SERVER(inode)->dtsize;
 out:
        trace_nfs_getattr_exit(inode, err);
        return err;