Re: [PATCH] fuse: update inode size after extending passthrough write

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Oct 11, 2024 at 03:53:26PM +0200, Amir Goldstein wrote:
> yangyun reported that libfuse test test_copy_file_range() copies zero
> bytes from a newly written file when fuse passthrough is enabled.
> 
> The reason is that extending passthrough write is not updating the fuse
> inode size and when vfs_copy_file_range() observes a zero size inode,
> it returns without calling the filesystem copy_file_range() method.
> 
> Extend the fuse inode size to the size of the backing inode after every
> passthrough write if the backing inode size is larger.
> 
> This does not yet provide cache coherency of fuse inode attributes and
> backing inode attributes, but it should prevent situations where fuse
> inode size is too small, causing read/copy to be wrongly shortened.
> 
> Reported-by: yangyun <yangyun50@xxxxxxxxxx>
> Closes: https://github.com/libfuse/libfuse/issues/1048
> Fixes: 57e1176e6086 ("fuse: implement read/write passthrough")
> Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx>
> ---
> 
> Doh! force of habbit - fixed subject s/ovl/fuse
> 
> Thanks,
> Amir.
> 
>  fs/fuse/passthrough.c | 13 +++++++++++--
>  1 file changed, 11 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
> index ba3207f6c4ce..d3047a4bc40e 100644
> --- a/fs/fuse/passthrough.c
> +++ b/fs/fuse/passthrough.c
> @@ -20,9 +20,18 @@ static void fuse_file_accessed(struct file *file)
>  
>  static void fuse_file_modified(struct file *file)
>  {
> +	struct fuse_file *ff = file->private_data;
> +	struct file *backing_file = fuse_file_passthrough(ff);
>  	struct inode *inode = file_inode(file);
> -
> -	fuse_invalidate_attr_mask(inode, FUSE_STATX_MODSIZE);
> +	loff_t size = i_size_read(file_inode(backing_file));
> +
> +	/*
> +	 * Most of the time we will be holding inode_lock(), but even if we are
> +	 * called from async io completion without inode_lock(), the last write
> +	 * will update fuse inode size to the size of the backing inode, even if
> +	 * the last write was not the extending write.
> +	 */
> +	fuse_write_update_attr(inode, size, size);
>  }
>  
>  ssize_t fuse_passthrough_read_iter(struct kiocb *iocb, struct iov_iter *iter)
> -- 
> 2.34.1

Sorry for a late reply. Because I have spent some time on figuring out whether we 
need some FUSE_I_SIZE_UNSTABLE bit operations before and after the write which are
provided in your v14 patch of fuse passthrough, just like in fuse_perform_write.

The conclusion is not, IMO. The FUSE_I_SIZE_UNSTABLE bit is provided in
commit 06a7c3c2781(fuse: hotfix truncate_pagecache() issue) for the
races between i_size updates and truncate_pagecache() in
fuse_change_attributes. Because the pagecache operations of fuse inode
is not allowed in fuse passthrough mode, this FUSE_I_SIZE_UNSTABLE bit is useless.
And we just need the minimum fix for extending writes by now.

I have also tested this patch with xfstests (using ./check -fuse -b) and libfuse 
test. In xfstest, this patch does not import new failed tests compared with pre-this
patch. And in libfuse test, this patch can solve the problem test_copy_file_range(). 




[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux