Received: by 2002:ac0:a581:0:0:0:0:0 with SMTP id m1-v6csp6037459imm; Wed, 27 Jun 2018 00:47:22 -0700 (PDT) X-Google-Smtp-Source: ADUXVKIiYO3t8BEF1Wz4BWRFjIvvNSXWp9z7Y+C3oAVSgcDned1kNKL2ltnQ8bg+2hss0gf8Pdfi X-Received: by 2002:a17:902:43a4:: with SMTP id j33-v6mr5059482pld.118.1530085642912; Wed, 27 Jun 2018 00:47:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1530085642; cv=none; d=google.com; s=arc-20160816; b=zyFE6ZOEajaHzgkLt0bO6eUXNqCVzkrzB5abuFZYWOWEhsHHrV/ZHD5upt2guTi61Q FSVnYJxvpm7nR+kczf4oYw8do0Rr9dUPL05IhkXfSEsP62HvvFl8V/wYBhmU1cNcMxS+ ukgopd8YSbvQnnmh9taCUVRs9gTF8Nq0nG95r13rpFQS1NbkDnaqk7lFkNwhcQLQzSTH Xg+jl8TW9zskP3QwxRtbFEsROKxXe/rQ/i/5k4ipjeABn+lb3yO1zvHwLYWO1mPa5DdI dK4VKEL4CZhxdioRLydVVaU/jeE+wUxdUqYfbtPUqsxwJVFltUK8oPPci+9nyj3j43tk txNQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :arc-authentication-results; bh=Yb3/Qtadga+kyO3lK7rnYYrTR9YjU8QGL43CYbYO34o=; b=lO+jt+4Ea3ojxCyyWGksJJDoO83Ol0qwJO6z1fiwiwp1N50Z4lwdsLpepx/I8wnDCn 3+dLLHsfQYk8tw1MMAt1IBMUXLEYroPyhEu7IyZzBpS9i2+dtS48x2q4z0mlVQLGtQOE QM83DB4yAjZBIODtik70/t7z1ACHyJF9ixbfAy2lMEWWz9sx5k+50Wnz8+i0K+eApM2Y ejTGyq69NmH2vRnksdbuxaF1pZU+pgnXUFX7lC+BUdAkLuLrhs184yv+pVPyeqh3rphZ N1soym2zJxl8uOazWG7bBFlyY8Ve53ZYo045fALBPr6teJ2H28+JbNXkeuK/rhoRgS1P KLVw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id a23-v6si3243700plm.305.2018.06.27.00.47.04; Wed, 27 Jun 2018 00:47:22 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932864AbeF0HqG (ORCPT + 99 others); Wed, 27 Jun 2018 03:46:06 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:47912 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S932186AbeF0HqF (ORCPT ); Wed, 27 Jun 2018 03:46:05 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 7A492400B45D; Wed, 27 Jun 2018 07:46:04 +0000 (UTC) Received: from localhost (ovpn-116-71.ams2.redhat.com [10.36.116.71]) by smtp.corp.redhat.com (Postfix) with ESMTPS id D8EC91C5B3; Wed, 27 Jun 2018 07:46:02 +0000 (UTC) From: Niels de Vos To: Miklos Szeredi , linux-fsdevel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Niels de Vos Subject: [PATCH] fuse: add support for copy_file_range() Date: Wed, 27 Jun 2018 09:45:34 +0200 Message-Id: <20180627074534.7307-1-ndevos@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Wed, 27 Jun 2018 07:46:04 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Wed, 27 Jun 2018 07:46:04 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'ndevos@redhat.com' RCPT:'' Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 --- fs/fuse/file.c | 65 +++++++++++++++++++++++ fs/fuse/fuse_i.h | 3 ++ include/uapi/linux/fuse.h | 106 ++++++++++++++++++++++---------------- 3 files changed, 130 insertions(+), 44 deletions(-) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index a201fb0ac64f..ffc6c294a639 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -3009,6 +3009,70 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset, return err; } +static long fuse_copy_file_range(struct file *file_in, loff_t pos_in, + struct file *file_out, loff_t pos_out, + size_t len, unsigned int flags) +{ + struct fuse_file *ff_in = file_in->private_data; + struct fuse_file *ff_out = file_out->private_data; + 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; + FUSE_ARGS(args); + struct fuse_copy_file_range_in inarg = { + .fh_in = ff_in->fh, + .off_in = pos_in, + .fh_out = ff_out->fh, + .off_out = pos_out, + .len = len, + .flags = flags + }; + struct fuse_copy_file_range_out outarg; + long err; + + if (fc->no_copy_file_range) + return -EOPNOTSUPP; + + inode_lock(inode_out); + set_bit(FUSE_I_SIZE_UNSTABLE, &fi_out->state); + + args.in.h.opcode = FUSE_COPY_FILE_RANGE; + args.in.h.nodeid = ff_in->nodeid; + args.in.numargs = 1; + args.in.args[0].size = sizeof(inarg); + args.in.args[0].value = &inarg; + args.out.numargs = 1; + args.out.args[0].size = sizeof(outarg); + args.out.args[0].value = &outarg; + err = fuse_simple_request(fc, &args); + if (err == -ENOSYS) { + fc->no_copy_file_range = 1; + err = -EOPNOTSUPP; + } + if (err) + goto out; + + /* we might have extended the file */ + if (outarg.size > 0) { + /* Size of inode_out may not have changed in case of + * overwrites, oh well. */ + bool changed = fuse_write_update_size(inode_out, + pos_out + outarg.size); + + if (changed && fc->writeback_cache) + file_update_time(file_out); + } + + fuse_invalidate_attr(inode_out); + + err = outarg.size; +out: + clear_bit(FUSE_I_SIZE_UNSTABLE, &fi_out->state); + inode_unlock(inode_out); + + return err; +} + static const struct file_operations fuse_file_operations = { .llseek = fuse_file_llseek, .read_iter = fuse_file_read_iter, @@ -3025,6 +3089,7 @@ static const struct file_operations fuse_file_operations = { .compat_ioctl = fuse_file_compat_ioctl, .poll = fuse_file_poll, .fallocate = fuse_file_fallocate, + .copy_file_range = fuse_copy_file_range, }; static const struct file_operations fuse_direct_io_file_operations = { diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 5256ad333b05..ea848bb7d9e2 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -637,6 +637,9 @@ struct fuse_conn { /** Allow other than the mounter user to access the filesystem ? */ unsigned allow_other:1; + /** Does the filesystem support copy_file_range? */ + unsigned no_copy_file_range:1; + /** The number of requests waiting for completion */ atomic_t num_waiting; diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index 92fa24c24c92..77330fa510f1 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -116,6 +116,9 @@ * * 7.27 * - add FUSE_ABORT_ERROR + * + * 7.28 + * - add FUSE_COPY_FILE_RANGE */ #ifndef _LINUX_FUSE_H @@ -337,50 +340,51 @@ struct fuse_file_lock { #define FUSE_POLL_SCHEDULE_NOTIFY (1 << 0) enum fuse_opcode { - FUSE_LOOKUP = 1, - FUSE_FORGET = 2, /* no reply */ - FUSE_GETATTR = 3, - FUSE_SETATTR = 4, - FUSE_READLINK = 5, - FUSE_SYMLINK = 6, - FUSE_MKNOD = 8, - FUSE_MKDIR = 9, - FUSE_UNLINK = 10, - FUSE_RMDIR = 11, - FUSE_RENAME = 12, - FUSE_LINK = 13, - FUSE_OPEN = 14, - FUSE_READ = 15, - FUSE_WRITE = 16, - FUSE_STATFS = 17, - FUSE_RELEASE = 18, - FUSE_FSYNC = 20, - FUSE_SETXATTR = 21, - FUSE_GETXATTR = 22, - FUSE_LISTXATTR = 23, - FUSE_REMOVEXATTR = 24, - FUSE_FLUSH = 25, - FUSE_INIT = 26, - FUSE_OPENDIR = 27, - FUSE_READDIR = 28, - FUSE_RELEASEDIR = 29, - FUSE_FSYNCDIR = 30, - FUSE_GETLK = 31, - FUSE_SETLK = 32, - FUSE_SETLKW = 33, - FUSE_ACCESS = 34, - FUSE_CREATE = 35, - FUSE_INTERRUPT = 36, - FUSE_BMAP = 37, - FUSE_DESTROY = 38, - FUSE_IOCTL = 39, - FUSE_POLL = 40, - FUSE_NOTIFY_REPLY = 41, - FUSE_BATCH_FORGET = 42, - FUSE_FALLOCATE = 43, - FUSE_READDIRPLUS = 44, - FUSE_RENAME2 = 45, - FUSE_LSEEK = 46, + FUSE_LOOKUP = 1, + FUSE_FORGET = 2, /* no reply */ + FUSE_GETATTR = 3, + FUSE_SETATTR = 4, + FUSE_READLINK = 5, + FUSE_SYMLINK = 6, + FUSE_MKNOD = 8, + FUSE_MKDIR = 9, + FUSE_UNLINK = 10, + FUSE_RMDIR = 11, + FUSE_RENAME = 12, + FUSE_LINK = 13, + FUSE_OPEN = 14, + FUSE_READ = 15, + FUSE_WRITE = 16, + FUSE_STATFS = 17, + FUSE_RELEASE = 18, + FUSE_FSYNC = 20, + FUSE_SETXATTR = 21, + FUSE_GETXATTR = 22, + FUSE_LISTXATTR = 23, + FUSE_REMOVEXATTR = 24, + FUSE_FLUSH = 25, + FUSE_INIT = 26, + FUSE_OPENDIR = 27, + FUSE_READDIR = 28, + FUSE_RELEASEDIR = 29, + FUSE_FSYNCDIR = 30, + FUSE_GETLK = 31, + FUSE_SETLK = 32, + FUSE_SETLKW = 33, + FUSE_ACCESS = 34, + FUSE_CREATE = 35, + FUSE_INTERRUPT = 36, + FUSE_BMAP = 37, + FUSE_DESTROY = 38, + FUSE_IOCTL = 39, + FUSE_POLL = 40, + FUSE_NOTIFY_REPLY = 41, + FUSE_BATCH_FORGET = 42, + FUSE_FALLOCATE = 43, + FUSE_READDIRPLUS = 44, + FUSE_RENAME2 = 45, + FUSE_LSEEK = 46, + FUSE_COPY_FILE_RANGE = 47, /* CUSE specific operations */ CUSE_INIT = 4096, @@ -792,4 +796,18 @@ struct fuse_lseek_out { uint64_t offset; }; +struct fuse_copy_file_range_in { + uint64_t fh_in; + uint64_t off_in; + uint64_t fh_out; + uint64_t off_out; + uint64_t len; + uint32_t flags; +}; + +struct fuse_copy_file_range_out { + uint32_t size; + uint32_t padding; +}; + #endif /* _LINUX_FUSE_H */ -- 2.17.1