From patchwork Wed Sep 11 17:06:50 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zach Brown X-Patchwork-Id: 2873981 Return-Path: X-Original-To: patchwork-linux-nfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id CB2C5BF43F for ; Wed, 11 Sep 2013 17:35:31 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C392420268 for ; Wed, 11 Sep 2013 17:35:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id E43E9201B8 for ; Wed, 11 Sep 2013 17:35:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755582Ab3IKRQp (ORCPT ); Wed, 11 Sep 2013 13:16:45 -0400 Received: from mx1.redhat.com ([209.132.183.28]:41776 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754053Ab3IKRQp (ORCPT ); Wed, 11 Sep 2013 13:16:45 -0400 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r8BH7kFF027724 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 11 Sep 2013 13:07:46 -0400 Received: from lenny.home.zabbo.net (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id r8BH7aup006954; Wed, 11 Sep 2013 13:07:45 -0400 From: Zach Brown To: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-nfs@vger.kernel.org, Trond Myklebust , Bryan Schumaker , "Martin K. Petersen" , Jens Axboe , Mark Fasheh , Joel Becker , Eric Wong Subject: [PATCH 3/3] btrfs: implement .splice_direct extent copying Date: Wed, 11 Sep 2013 10:06:50 -0700 Message-Id: <1378919210-10372-4-git-send-email-zab@redhat.com> In-Reply-To: <1378919210-10372-1-git-send-email-zab@redhat.com> References: <1378919210-10372-1-git-send-email-zab@redhat.com> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org X-Spam-Status: No, score=-7.7 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch re-uses the existing btrfs file cloning ioctl code to implement the .splice_direct copy offloading file operation. The existing extent item copying btrfs_ioctl_clone() is renamed to a shared btrfs_clone_extents(). The ioctl specific code (mostly simple entry-point stuff that splice() already does elsewhere) is moved to a new much smaller btrfs_ioctl_clone(). btrfs_splice_direct() thus inherits the conservative limitations of the btrfs clone ioctl: it only allows block-aligned copies between files on the same snapshot. Signed-off-by: Zach Brown --- fs/btrfs/ctree.h | 2 ++ fs/btrfs/file.c | 11 ++++++++++ fs/btrfs/ioctl.c | 64 +++++++++++++++++++++++++++++++------------------------- 3 files changed, 48 insertions(+), 29 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index e795bf1..f73830e 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3648,6 +3648,8 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, u64 newer_than, unsigned long max_pages); void btrfs_get_block_group_info(struct list_head *groups_list, struct btrfs_ioctl_space_info *space); +long btrfs_clone_extents(struct file *file, struct file *src_file, u64 off, + u64 olen, u64 destoff); /* file.c */ int btrfs_auto_defrag_init(void); diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 4d2eb64..82aec93 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2557,6 +2557,16 @@ out: return offset; } +static long btrfs_splice_direct(struct file *in, loff_t in_pos, + struct file *out, loff_t out_pos, size_t len, + unsigned int flags) +{ + int ret = btrfs_clone_extents(out, in, in_pos, len, out_pos); + if (ret == 0) + ret = len; + return ret; +} + const struct file_operations btrfs_file_operations = { .llseek = btrfs_file_llseek, .read = do_sync_read, @@ -2573,6 +2583,7 @@ const struct file_operations btrfs_file_operations = { #ifdef CONFIG_COMPAT .compat_ioctl = btrfs_ioctl, #endif + .splice_direct = btrfs_splice_direct, }; void btrfs_auto_defrag_exit(void) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 238a055..cddf6ef 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -2469,13 +2469,12 @@ out: return ret; } -static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, - u64 off, u64 olen, u64 destoff) +long btrfs_clone_extents(struct file *file, struct file *src_file, u64 off, + u64 olen, u64 destoff) { struct inode *inode = file_inode(file); + struct inode *src = file_inode(src_file); struct btrfs_root *root = BTRFS_I(inode)->root; - struct fd src_file; - struct inode *src; struct btrfs_trans_handle *trans; struct btrfs_path *path; struct extent_buffer *leaf; @@ -2498,10 +2497,6 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, * they don't overlap)? */ - /* the destination must be opened for writing */ - if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND)) - return -EINVAL; - if (btrfs_root_readonly(root)) return -EROFS; @@ -2509,48 +2504,36 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, if (ret) return ret; - src_file = fdget(srcfd); - if (!src_file.file) { - ret = -EBADF; - goto out_drop_write; - } - ret = -EXDEV; - if (src_file.file->f_path.mnt != file->f_path.mnt) - goto out_fput; - - src = file_inode(src_file.file); + if (src_file->f_path.mnt != file->f_path.mnt) + goto out_drop_write; ret = -EINVAL; if (src == inode) same_inode = 1; - /* the src must be open for reading */ - if (!(src_file.file->f_mode & FMODE_READ)) - goto out_fput; - /* don't make the dst file partly checksummed */ if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) != (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) - goto out_fput; + goto out_drop_write; ret = -EISDIR; if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode)) - goto out_fput; + goto out_drop_write; ret = -EXDEV; if (src->i_sb != inode->i_sb) - goto out_fput; + goto out_drop_write; ret = -ENOMEM; buf = vmalloc(btrfs_level_size(root, 0)); if (!buf) - goto out_fput; + goto out_drop_write; path = btrfs_alloc_path(); if (!path) { vfree(buf); - goto out_fput; + goto out_drop_write; } path->reada = 2; @@ -2867,13 +2850,36 @@ out_unlock: mutex_unlock(&inode->i_mutex); vfree(buf); btrfs_free_path(path); -out_fput: - fdput(src_file); out_drop_write: mnt_drop_write_file(file); return ret; } +static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, + u64 off, u64 olen, u64 destoff) +{ + struct fd src_file; + int ret; + + /* the destination must be opened for writing */ + if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND)) + return -EINVAL; + + src_file = fdget(srcfd); + if (!src_file.file) + return -EBADF; + + /* the src must be open for reading */ + if (!(src_file.file->f_mode & FMODE_READ)) + ret = -EINVAL; + else + ret = btrfs_clone_extents(file, src_file.file, off, olen, + destoff); + + fdput(src_file); + return ret; +} + static long btrfs_ioctl_clone_range(struct file *file, void __user *argp) { struct btrfs_ioctl_clone_range_args args;