| From a2bc92362941006830afa3dfad6caec1f99acbf5 Mon Sep 17 00:00:00 2001 |
| From: Miklos Szeredi <mszeredi@redhat.com> |
| Date: Tue, 28 May 2019 13:22:50 +0200 |
| Subject: fuse: fix copy_file_range() in the writeback case |
| |
| From: Miklos Szeredi <mszeredi@redhat.com> |
| |
| commit a2bc92362941006830afa3dfad6caec1f99acbf5 upstream. |
| |
| Prior to sending COPY_FILE_RANGE to userspace filesystem, we must flush all |
| dirty pages in both the source and destination files. |
| |
| This patch adds the missing flush of the source file. |
| |
| Tested on libfuse-3.5.0 with: |
| |
| libfuse/example/passthrough_ll /mnt/fuse/ -o writeback |
| libfuse/test/test_syscalls /mnt/fuse/tmp/test |
| |
| Fixes: 88bc7d5097a1 ("fuse: add support for copy_file_range()") |
| Cc: <stable@vger.kernel.org> # v4.20 |
| Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/fuse/file.c | 12 ++++++++++++ |
| 1 file changed, 12 insertions(+) |
| |
| --- a/fs/fuse/file.c |
| +++ b/fs/fuse/file.c |
| @@ -3098,6 +3098,7 @@ static ssize_t fuse_copy_file_range(stru |
| { |
| struct fuse_file *ff_in = file_in->private_data; |
| struct fuse_file *ff_out = file_out->private_data; |
| + struct inode *inode_in = file_inode(file_in); |
| struct inode *inode_out = file_inode(file_out); |
| struct fuse_inode *fi_out = get_fuse_inode(inode_out); |
| struct fuse_conn *fc = ff_in->fc; |
| @@ -3121,6 +3122,17 @@ static ssize_t fuse_copy_file_range(stru |
| if (fc->no_copy_file_range) |
| return -EOPNOTSUPP; |
| |
| + if (fc->writeback_cache) { |
| + inode_lock(inode_in); |
| + err = filemap_write_and_wait_range(inode_in->i_mapping, |
| + pos_in, pos_in + len); |
| + if (!err) |
| + fuse_sync_writes(inode_in); |
| + inode_unlock(inode_in); |
| + if (err) |
| + return err; |
| + } |
| + |
| inode_lock(inode_out); |
| |
| if (fc->writeback_cache) { |