aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2019-05-28 07:22:50 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2019-05-28 07:22:50 -0400
commita2bc92362941006830afa3dfad6caec1f99acbf5 (patch)
tree67bfa4c3dd3517520f7edeecdf4ef51e93362429
parent4a2abf99f9c2877039006b8dfb3ec4e0d1278fe8 (diff)
fuse: fix copy_file_range() in the writeback case
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>
-rw-r--r--fs/fuse/file.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index c1064866c402..4141d94de4ff 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -3110,6 +3110,7 @@ static ssize_t fuse_copy_file_range(struct file *file_in, loff_t pos_in,
3110{ 3110{
3111 struct fuse_file *ff_in = file_in->private_data; 3111 struct fuse_file *ff_in = file_in->private_data;
3112 struct fuse_file *ff_out = file_out->private_data; 3112 struct fuse_file *ff_out = file_out->private_data;
3113 struct inode *inode_in = file_inode(file_in);
3113 struct inode *inode_out = file_inode(file_out); 3114 struct inode *inode_out = file_inode(file_out);
3114 struct fuse_inode *fi_out = get_fuse_inode(inode_out); 3115 struct fuse_inode *fi_out = get_fuse_inode(inode_out);
3115 struct fuse_conn *fc = ff_in->fc; 3116 struct fuse_conn *fc = ff_in->fc;
@@ -3133,6 +3134,17 @@ static ssize_t fuse_copy_file_range(struct file *file_in, loff_t pos_in,
3133 if (fc->no_copy_file_range) 3134 if (fc->no_copy_file_range)
3134 return -EOPNOTSUPP; 3135 return -EOPNOTSUPP;
3135 3136
3137 if (fc->writeback_cache) {
3138 inode_lock(inode_in);
3139 err = filemap_write_and_wait_range(inode_in->i_mapping,
3140 pos_in, pos_in + len);
3141 if (!err)
3142 fuse_sync_writes(inode_in);
3143 inode_unlock(inode_in);
3144 if (err)
3145 return err;
3146 }
3147
3136 inode_lock(inode_out); 3148 inode_lock(inode_out);
3137 3149
3138 if (fc->writeback_cache) { 3150 if (fc->writeback_cache) {