From: Zheng Bin <zhengbi...@huawei.com>

[ Upstream commit 3a39e778690500066b31fe982d18e2e394d3bce2 ]

Use the following command to test nfsv4(size of file1M is 1MB):
mount -t nfs -o vers=4.0,actimeo=60 127.0.0.1/dir1 /mnt
cp file1M /mnt
du -h /mnt/file1M  -->0 within 60s, then 1M

When write is done(cp file1M /mnt), will call this:
nfs_writeback_done
  nfs4_write_done
    nfs4_write_done_cb
      nfs_writeback_update_inode
        nfs_post_op_update_inode_force_wcc_locked(change, ctime, mtime
nfs_post_op_update_inode_force_wcc_locked
   nfs_set_cache_invalid
   nfs_refresh_inode_locked
     nfs_update_inode

nfsd write response contains change, ctime, mtime, the flag will be
clear after nfs_update_inode. Howerver, write response does not contain
space_used, previous open response contains space_used whose value is 0,
so inode->i_blocks is still 0.

nfs_getattr  -->called by "du -h"
  do_update |= force_sync || nfs_attribute_cache_expired -->false in 60s
  cache_validity = READ_ONCE(NFS_I(inode)->cache_validity)
  do_update |= cache_validity & (NFS_INO_INVALID_ATTR    -->false
  if (do_update) {
        __nfs_revalidate_inode
  }

Within 60s, does not send getattr request to nfsd, thus "du -h /mnt/file1M"
is 0.

Add a NFS_INO_INVALID_BLOCKS flag, set it when nfsv4 write is done.

Fixes: 16e143751727 ("NFS: More fine grained attribute tracking")
Signed-off-by: Zheng Bin <zhengbi...@huawei.com>
Signed-off-by: Anna Schumaker <anna.schuma...@netapp.com>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 fs/nfs/inode.c         | 14 +++++++++++---
 include/linux/nfs_fs.h |  1 +
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 3802c88e83720..6de41f7412808 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -826,6 +826,8 @@ int nfs_getattr(const struct path *path, struct kstat *stat,
                do_update |= cache_validity & NFS_INO_INVALID_ATIME;
        if (request_mask & (STATX_CTIME|STATX_MTIME))
                do_update |= cache_validity & NFS_INO_REVAL_PAGECACHE;
+       if (request_mask & STATX_BLOCKS)
+               do_update |= cache_validity & NFS_INO_INVALID_BLOCKS;
        if (do_update) {
                /* Update the attribute cache */
                if (!(server->flags & NFS_MOUNT_NOAC))
@@ -1750,7 +1752,8 @@ out_noforce:
        status = nfs_post_op_update_inode_locked(inode, fattr,
                        NFS_INO_INVALID_CHANGE
                        | NFS_INO_INVALID_CTIME
-                       | NFS_INO_INVALID_MTIME);
+                       | NFS_INO_INVALID_MTIME
+                       | NFS_INO_INVALID_BLOCKS);
        return status;
 }
 
@@ -1857,7 +1860,8 @@ static int nfs_update_inode(struct inode *inode, struct 
nfs_fattr *fattr)
        nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR
                        | NFS_INO_INVALID_ATIME
                        | NFS_INO_REVAL_FORCED
-                       | NFS_INO_REVAL_PAGECACHE);
+                       | NFS_INO_REVAL_PAGECACHE
+                       | NFS_INO_INVALID_BLOCKS);
 
        /* Do atomic weak cache consistency updates */
        nfs_wcc_update_inode(inode, fattr);
@@ -2019,8 +2023,12 @@ static int nfs_update_inode(struct inode *inode, struct 
nfs_fattr *fattr)
                inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
        } else if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
                inode->i_blocks = fattr->du.nfs2.blocks;
-       else
+       else {
+               nfsi->cache_validity |= save_cache_validity &
+                               (NFS_INO_INVALID_BLOCKS
+                               | NFS_INO_REVAL_FORCED);
                cache_revalidated = false;
+       }
 
        /* Update attrtimeo value if we're out of the unstable period */
        if (attr_changed) {
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 570a60c2f4f48..ad09c0cc54645 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -225,6 +225,7 @@ struct nfs4_copy_state {
 #define NFS_INO_INVALID_OTHER  BIT(12)         /* other attrs are invalid */
 #define NFS_INO_DATA_INVAL_DEFER       \
                                BIT(13)         /* Deferred cache invalidation 
*/
+#define NFS_INO_INVALID_BLOCKS BIT(14)         /* cached blocks are invalid */
 
 #define NFS_INO_INVALID_ATTR   (NFS_INO_INVALID_CHANGE \
                | NFS_INO_INVALID_CTIME \
-- 
2.25.1



Reply via email to