summaryrefslogtreecommitdiffstats
path: root/fs/fuse
diff options
context:
space:
mode:
authorEryu Guan <eguan@linux.alibaba.com>2020-05-12 04:29:04 +0200
committerMiklos Szeredi <mszeredi@redhat.com>2020-05-19 14:50:37 +0200
commitcf576c58b3a283333fc6e9a7c1c8e5342fa59b97 (patch)
treecf40e681c75c775c5bf0705a2966a01c75428098 /fs/fuse
parentfuse: Update stale comment in queue_interrupt() (diff)
downloadlinux-cf576c58b3a283333fc6e9a7c1c8e5342fa59b97.tar.xz
linux-cf576c58b3a283333fc6e9a7c1c8e5342fa59b97.zip
fuse: invalidate inode attr in writeback cache mode
Under writeback mode, inode->i_blocks is not updated, making utils du read st.blocks as 0. For example, when using virtiofs (cache=always & nondax mode) with writeback_cache enabled, writing a new file and check its disk usage with du, du reports 0 usage. # uname -r 5.6.0-rc6+ # mount -t virtiofs virtiofs /mnt/virtiofs # rm -f /mnt/virtiofs/testfile # create new file and do extend write # xfs_io -fc "pwrite 0 4k" /mnt/virtiofs/testfile wrote 4096/4096 bytes at offset 0 4 KiB, 1 ops; 0.0001 sec (28.103 MiB/sec and 7194.2446 ops/sec) # du -k /mnt/virtiofs/testfile 0 <==== disk usage is 0 # stat -c %s,%b /mnt/virtiofs/testfile 4096,0 <==== i_size is correct, but st_blocks is 0 Fix it by invalidating attr in fuse_flush(), so we get up-to-date attr from server on next getattr. Signed-off-by: Eryu Guan <eguan@linux.alibaba.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs/fuse')
-rw-r--r--fs/fuse/file.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index d400b71b98d5..262c5e20f324 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -445,8 +445,9 @@ static int fuse_flush(struct file *file, fl_owner_t id)
if (is_bad_inode(inode))
return -EIO;
+ err = 0;
if (fc->no_flush)
- return 0;
+ goto inval_attr_out;
err = write_inode_now(inode, 1);
if (err)
@@ -475,6 +476,14 @@ static int fuse_flush(struct file *file, fl_owner_t id)
fc->no_flush = 1;
err = 0;
}
+
+inval_attr_out:
+ /*
+ * In memory i_blocks is not maintained by fuse, if writeback cache is
+ * enabled, i_blocks from cached attr may not be accurate.
+ */
+ if (!err && fc->writeback_cache)
+ fuse_invalidate_attr(inode);
return err;
}