aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse
diff options
context:
space:
mode:
authorNiels de Vos <ndevos@redhat.com>2018-08-21 08:36:31 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2018-09-28 10:43:22 -0400
commit88bc7d5097a11d9bdcf08ecf85c81ba998353437 (patch)
tree40bceda7dc1db073a51d8ed34675073fbf70dfd0 /fs/fuse
parent908a572b80f6e9577b45e81b3dfe2e22111286b8 (diff)
fuse: add support for copy_file_range()
There are several FUSE filesystems that can implement server-side copy or other efficient copy/duplication/clone methods. The copy_file_range() syscall is the standard interface that users have access to while not depending on external libraries that bypass FUSE. Signed-off-by: Niels de Vos <ndevos@redhat.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs/fuse')
-rw-r--r--fs/fuse/file.c77
-rw-r--r--fs/fuse/fuse_i.h3
2 files changed, 80 insertions, 0 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 32d0b883e74f..63136a2c23ab 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -3011,6 +3011,82 @@ out:
3011 return err; 3011 return err;
3012} 3012}
3013 3013
3014static ssize_t fuse_copy_file_range(struct file *file_in, loff_t pos_in,
3015 struct file *file_out, loff_t pos_out,
3016 size_t len, unsigned int flags)
3017{
3018 struct fuse_file *ff_in = file_in->private_data;
3019 struct fuse_file *ff_out = file_out->private_data;
3020 struct inode *inode_out = file_inode(file_out);
3021 struct fuse_inode *fi_out = get_fuse_inode(inode_out);
3022 struct fuse_conn *fc = ff_in->fc;
3023 FUSE_ARGS(args);
3024 struct fuse_copy_file_range_in inarg = {
3025 .fh_in = ff_in->fh,
3026 .off_in = pos_in,
3027 .nodeid_out = ff_out->nodeid,
3028 .fh_out = ff_out->fh,
3029 .off_out = pos_out,
3030 .len = len,
3031 .flags = flags
3032 };
3033 struct fuse_write_out outarg;
3034 ssize_t err;
3035 /* mark unstable when write-back is not used, and file_out gets
3036 * extended */
3037 bool is_unstable = (!fc->writeback_cache) &&
3038 ((pos_out + len) > inode_out->i_size);
3039
3040 if (fc->no_copy_file_range)
3041 return -EOPNOTSUPP;
3042
3043 inode_lock(inode_out);
3044
3045 if (fc->writeback_cache) {
3046 err = filemap_write_and_wait_range(inode_out->i_mapping,
3047 pos_out, pos_out + len);
3048 if (err)
3049 goto out;
3050
3051 fuse_sync_writes(inode_out);
3052 }
3053
3054 if (is_unstable)
3055 set_bit(FUSE_I_SIZE_UNSTABLE, &fi_out->state);
3056
3057 args.in.h.opcode = FUSE_COPY_FILE_RANGE;
3058 args.in.h.nodeid = ff_in->nodeid;
3059 args.in.numargs = 1;
3060 args.in.args[0].size = sizeof(inarg);
3061 args.in.args[0].value = &inarg;
3062 args.out.numargs = 1;
3063 args.out.args[0].size = sizeof(outarg);
3064 args.out.args[0].value = &outarg;
3065 err = fuse_simple_request(fc, &args);
3066 if (err == -ENOSYS) {
3067 fc->no_copy_file_range = 1;
3068 err = -EOPNOTSUPP;
3069 }
3070 if (err)
3071 goto out;
3072
3073 if (fc->writeback_cache) {
3074 fuse_write_update_size(inode_out, pos_out + outarg.size);
3075 file_update_time(file_out);
3076 }
3077
3078 fuse_invalidate_attr(inode_out);
3079
3080 err = outarg.size;
3081out:
3082 if (is_unstable)
3083 clear_bit(FUSE_I_SIZE_UNSTABLE, &fi_out->state);
3084
3085 inode_unlock(inode_out);
3086
3087 return err;
3088}
3089
3014static const struct file_operations fuse_file_operations = { 3090static const struct file_operations fuse_file_operations = {
3015 .llseek = fuse_file_llseek, 3091 .llseek = fuse_file_llseek,
3016 .read_iter = fuse_file_read_iter, 3092 .read_iter = fuse_file_read_iter,
@@ -3027,6 +3103,7 @@ static const struct file_operations fuse_file_operations = {
3027 .compat_ioctl = fuse_file_compat_ioctl, 3103 .compat_ioctl = fuse_file_compat_ioctl,
3028 .poll = fuse_file_poll, 3104 .poll = fuse_file_poll,
3029 .fallocate = fuse_file_fallocate, 3105 .fallocate = fuse_file_fallocate,
3106 .copy_file_range = fuse_copy_file_range,
3030}; 3107};
3031 3108
3032static const struct file_operations fuse_direct_io_file_operations = { 3109static const struct file_operations fuse_direct_io_file_operations = {
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index f78e9614bb5f..3e45d408a644 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -637,6 +637,9 @@ struct fuse_conn {
637 /** Allow other than the mounter user to access the filesystem ? */ 637 /** Allow other than the mounter user to access the filesystem ? */
638 unsigned allow_other:1; 638 unsigned allow_other:1;
639 639
640 /** Does the filesystem support copy_file_range? */
641 unsigned no_copy_file_range:1;
642
640 /** The number of requests waiting for completion */ 643 /** The number of requests waiting for completion */
641 atomic_t num_waiting; 644 atomic_t num_waiting;
642 645