Skip to content

Commit 9b46418

Browse files
author
Miklos Szeredi
committed
fuse: copy_file_range should truncate cache
After the copy operation completes the cache is not up-to-date. Truncate all pages in the interval that has successfully been copied. Truncating completely copied dirty pages is okay, since the data has been overwritten anyway. Truncating partially copied dirty pages is not okay; add a comment for now. Fixes: 88bc7d5 ("fuse: add support for copy_file_range()") Signed-off-by: Miklos Szeredi <[email protected]>
1 parent 2c4656d commit 9b46418

File tree

1 file changed

+22
-0
lines changed

1 file changed

+22
-0
lines changed

fs/fuse/file.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3337,6 +3337,24 @@ static ssize_t __fuse_copy_file_range(struct file *file_in, loff_t pos_in,
33373337
if (err)
33383338
goto out;
33393339

3340+
/*
3341+
* Write out dirty pages in the destination file before sending the COPY
3342+
* request to userspace. After the request is completed, truncate off
3343+
* pages (including partial ones) from the cache that have been copied,
3344+
* since these contain stale data at that point.
3345+
*
3346+
* This should be mostly correct, but if the COPY writes to partial
3347+
* pages (at the start or end) and the parts not covered by the COPY are
3348+
* written through a memory map after calling fuse_writeback_range(),
3349+
* then these partial page modifications will be lost on truncation.
3350+
*
3351+
* It is unlikely that someone would rely on such mixed style
3352+
* modifications. Yet this does give less guarantees than if the
3353+
* copying was performed with write(2).
3354+
*
3355+
* To fix this a i_mmap_sem style lock could be used to prevent new
3356+
* faults while the copy is ongoing.
3357+
*/
33403358
err = fuse_writeback_range(inode_out, pos_out, pos_out + len - 1);
33413359
if (err)
33423360
goto out;
@@ -3360,6 +3378,10 @@ static ssize_t __fuse_copy_file_range(struct file *file_in, loff_t pos_in,
33603378
if (err)
33613379
goto out;
33623380

3381+
truncate_inode_pages_range(inode_out->i_mapping,
3382+
ALIGN_DOWN(pos_out, PAGE_SIZE),
3383+
ALIGN(pos_out + outarg.size, PAGE_SIZE) - 1);
3384+
33633385
if (fc->writeback_cache) {
33643386
fuse_write_update_size(inode_out, pos_out + outarg.size);
33653387
file_update_time(file_out);

0 commit comments

Comments
 (0)