On Wed, 2020-05-20 at 09:30 +0800, Zheng Bin wrote: > 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 <zhengbin13@xxxxxxxxxx> > --- > fs/nfs/inode.c | 9 +++++++-- > include/linux/nfs_fs.h | 6 ++++-- > 2 files changed, 11 insertions(+), 4 deletions(-) > > diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c > index b9d0921cb4fe..2d743e42fee1 100644 > --- a/fs/nfs/inode.c > +++ b/fs/nfs/inode.c > @@ -1764,7 +1764,8 @@ int > nfs_post_op_update_inode_force_wcc_locked(struct inode *inode, struct > nfs_fa > 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; > } > > @@ -2033,8 +2034,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 73eda45f1cfd..77efdca12cab 100644 > --- a/include/linux/nfs_fs.h > +++ b/include/linux/nfs_fs.h > @@ -227,14 +227,16 @@ struct nfs4_copy_state { > #define NFS_INO_INVALID_CTIME BIT(9) /* cached > ctime is invalid */ > #define NFS_INO_INVALID_MTIME BIT(10) /* cached > mtime is invalid */ > #define NFS_INO_INVALID_SIZE BIT(11) /* cached size is > invalid */ > -#define NFS_INO_INVALID_OTHER BIT(12) /* other > attrs are invalid */ > +#define NFS_INO_INVALID_BLOCKS BIT(12) /* cached > blocks are invalid */ > +#define NFS_INO_INVALID_OTHER BIT(13) /* other > attrs are invalid */ > #define NFS_INO_DATA_INVAL_DEFER \ > - BIT(13) /* Deferred cache > invalidation */ > + BIT(14) /* Deferred cache > invalidation */ > > #define NFS_INO_INVALID_ATTR (NFS_INO_INVALID_CHANGE \ > | NFS_INO_INVALID_CTIME \ > | NFS_INO_INVALID_MTIME \ > | NFS_INO_INVALID_SIZE \ > + | NFS_INO_INVALID_BLOCKS \ Can we please replace this with an explicit check for STATX_BLOCKS in nfs_getattr()? The above would just mean we always revalidate independently of whether or not the user cares. > | NFS_INO_INVALID_OTHER) /* inode metadata is invalid > */ > > /* > -- > 2.26.0.106.g9fadedd > -- Trond Myklebust Linux NFS client maintainer, Hammerspace trond.myklebust@xxxxxxxxxxxxxxx