diff options
author | Miklos Szeredi <mszeredi@redhat.com> | 2019-05-28 07:22:50 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2019-05-28 07:22:50 -0400 |
commit | a2bc92362941006830afa3dfad6caec1f99acbf5 (patch) | |
tree | 67bfa4c3dd3517520f7edeecdf4ef51e93362429 /fs | |
parent | 4a2abf99f9c2877039006b8dfb3ec4e0d1278fe8 (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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/fuse/file.c | 12 |
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) { |