From patchwork Sat Oct 24 23:17:09 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peng Tao X-Patchwork-Id: 7480641 Return-Path: X-Original-To: patchwork-linux-fsdevel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 09602BEEA4 for ; Sat, 24 Oct 2015 15:30:16 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id CE7A42070B for ; Sat, 24 Oct 2015 15:30:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 96350206EF for ; Sat, 24 Oct 2015 15:30:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752499AbbJXP3Z (ORCPT ); Sat, 24 Oct 2015 11:29:25 -0400 Received: from mail-pa0-f50.google.com ([209.85.220.50]:36118 "EHLO mail-pa0-f50.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752512AbbJXP3B (ORCPT ); Sat, 24 Oct 2015 11:29:01 -0400 Received: by pacfv9 with SMTP id fv9so151042619pac.3 for ; Sat, 24 Oct 2015 08:29:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=primarydata_com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=cDux/JojxYIqP/Lg9eRAi915TiD2qTX/wwYRakRFTY8=; b=N0hlHY91+sSk8NrVngPkqCrX2ly1eNTdGMK4gr6rMB0ToUSoXTD78rPyysbUBPnUen rDHK2PXyiwOavwg/hmP0LoUCc9UGqOKQq7GxMYy5PxtD3YkLTVXkyxrIAEoRYP1f5pM0 dywSNC1VixXc+ONlyOJTnkYqkzqtUmOlzSWcGYOgUrzPP+uaplNIYYypY1eowJMSwKh9 TUxSJOhIdWKMgfnKvo540+AIUvRQowOBjseYQEG1mEDKLhGB1dPKoxkEkuGT8Z8fhfHv h9Jfc/BdhfzLuYAffRCPWGFpMj6atQ0HQITgMbMCU4PgQBmq2mUHizCQTqV8oCKELa9h BbVw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=cDux/JojxYIqP/Lg9eRAi915TiD2qTX/wwYRakRFTY8=; b=RYwNd4C4RBKokCSnOPd68LQAEqM3N3WPNDTi4Bvg9Sqgl3VAPXmE5EUOSf2WTLMAf7 mgae8RjOMDYgNCUd2uhqbaADUo6kLZawwS0/0oML9YHwiFuMroLB7gfVKY5tADF25O7k l3a9pjtjwMU+Wa5rC+DpqN+jCtQwaeUrYr4GsNG/bSlNW2XskoVqVDMyNG9Za8LCs1Vy JZV7cj5Q/1KlcvQ/otmW8Ce+eOa7LqoY5XaO68AnR4TcI18PS20epifYacbHd9ZAJZw3 D/Ea1DCjDhLgOESe+F83J6xTYX3Wya/CHqsRM0Epb6F+8WQQPvG/bG4+rKi+vXCDmeYC 7I4g== X-Gm-Message-State: ALoCoQkly5UlbMeL0S2lCyUqEl9GZEi9TwqZhnaauM9B0XN/tUMOaOCzJIQ8h0DS0IdnxTo/BzaV X-Received: by 10.68.135.161 with SMTP id pt1mr11888176pbb.80.1445700540556; Sat, 24 Oct 2015 08:29:00 -0700 (PDT) Received: from lear.localdomain (ec2-54-65-164-9.ap-northeast-1.compute.amazonaws.com. [54.65.164.9]) by smtp.gmail.com with ESMTPSA id nj1sm24764918pbc.2.2015.10.24.08.28.52 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 24 Oct 2015 08:29:00 -0700 (PDT) From: Peng Tao To: linux-fsdevel@vger.kernel.org Cc: Trond Myklebust , Anna Schumaker , Christoph Hellwig , Zach Brown , Darren Hart , Jeff Layton , bfields@fieldses.org, "Darrick J. Wong" , viro@zeniv.linux.org.uk, linux-nfs@vger.kernel.org, linux-btrfs@vger.kernel.org, linux-cifs@vger.kernel.org, Steve French , Peng Tao Subject: [PATCH 2/9] cifs: add .copy_file_range file operation Date: Sun, 25 Oct 2015 07:17:09 +0800 Message-Id: <1445728636-10109-3-git-send-email-tao.peng@primarydata.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1445728636-10109-1-git-send-email-tao.peng@primarydata.com> References: <1445728636-10109-1-git-send-email-tao.peng@primarydata.com> Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Spam-Status: No, score=-4.8 required=5.0 tests=BAYES_00, DATE_IN_FUTURE_06_12, DKIM_SIGNED, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=ham 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 Signed-off-by: Peng Tao --- fs/cifs/cifsfs.c | 22 ++++++++++++ fs/cifs/cifsfs.h | 4 ++- fs/cifs/ioctl.c | 100 +++++++++++++++++++++++++++++++------------------------ 3 files changed, 82 insertions(+), 44 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index e739950..6ef7c3c 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -910,6 +910,22 @@ const struct inode_operations cifs_symlink_inode_ops = { #endif }; +#ifdef CONFIG_CIFS_POSIX +ssize_t cifs_file_copy_range(struct file *file_in, loff_t pos_in, + struct file *file_out, loff_t pos_out, + size_t len, unsigned int flags) +{ + unsigned int xid; + int rc; + + xid = get_xid(); + rc = cifs_file_clone_range(xid, file_in, file_out, pos_in, + len, pos_out, true); + free_xid(xid); + return rc < 0 ? rc : len; +} +#endif + const struct file_operations cifs_file_ops = { .read_iter = cifs_loose_read_iter, .write_iter = cifs_file_write_iter, @@ -923,6 +939,7 @@ const struct file_operations cifs_file_ops = { .llseek = cifs_llseek, #ifdef CONFIG_CIFS_POSIX .unlocked_ioctl = cifs_ioctl, + .copy_file_range = cifs_file_copy_range, #endif /* CONFIG_CIFS_POSIX */ .setlease = cifs_setlease, .fallocate = cifs_fallocate, @@ -941,6 +958,7 @@ const struct file_operations cifs_file_strict_ops = { .llseek = cifs_llseek, #ifdef CONFIG_CIFS_POSIX .unlocked_ioctl = cifs_ioctl, + .copy_file_range = cifs_file_copy_range, #endif /* CONFIG_CIFS_POSIX */ .setlease = cifs_setlease, .fallocate = cifs_fallocate, @@ -959,6 +977,7 @@ const struct file_operations cifs_file_direct_ops = { .splice_read = generic_file_splice_read, #ifdef CONFIG_CIFS_POSIX .unlocked_ioctl = cifs_ioctl, + .copy_file_range = cifs_file_copy_range, #endif /* CONFIG_CIFS_POSIX */ .llseek = cifs_llseek, .setlease = cifs_setlease, @@ -977,6 +996,7 @@ const struct file_operations cifs_file_nobrl_ops = { .llseek = cifs_llseek, #ifdef CONFIG_CIFS_POSIX .unlocked_ioctl = cifs_ioctl, + .copy_file_range = cifs_file_copy_range, #endif /* CONFIG_CIFS_POSIX */ .setlease = cifs_setlease, .fallocate = cifs_fallocate, @@ -994,6 +1014,7 @@ const struct file_operations cifs_file_strict_nobrl_ops = { .llseek = cifs_llseek, #ifdef CONFIG_CIFS_POSIX .unlocked_ioctl = cifs_ioctl, + .copy_file_range = cifs_file_copy_range, #endif /* CONFIG_CIFS_POSIX */ .setlease = cifs_setlease, .fallocate = cifs_fallocate, @@ -1011,6 +1032,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = { .splice_read = generic_file_splice_read, #ifdef CONFIG_CIFS_POSIX .unlocked_ioctl = cifs_ioctl, + .copy_file_range = cifs_file_copy_range, #endif /* CONFIG_CIFS_POSIX */ .llseek = cifs_llseek, .setlease = cifs_setlease, diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index c3cc160..797439b 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -131,7 +131,9 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *, extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); - +extern int cifs_file_clone_range(unsigned int xid, struct file *src_file, + struct file *dst_file, u64 off, u64 len, + u64 destoff, bool dup_extents); #ifdef CONFIG_CIFS_NFSD_EXPORT extern const struct export_operations cifs_export_ops; #endif /* CONFIG_CIFS_NFSD_EXPORT */ diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index 28a77bf..bbab940 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c @@ -34,68 +34,36 @@ #include "cifs_ioctl.h" #include -static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file, - unsigned long srcfd, u64 off, u64 len, u64 destoff, - bool dup_extents) +int cifs_file_clone_range(unsigned int xid, struct file *src_file, + struct file *dst_file, u64 off, u64 len, + u64 destoff, bool dup_extents) { - int rc; - struct cifsFileInfo *smb_file_target = dst_file->private_data; + struct inode *src_inode = file_inode(src_file); struct inode *target_inode = file_inode(dst_file); - struct cifs_tcon *target_tcon; - struct fd src_file; struct cifsFileInfo *smb_file_src; - struct inode *src_inode; + struct cifsFileInfo *smb_file_target; struct cifs_tcon *src_tcon; + struct cifs_tcon *target_tcon; + int rc; - cifs_dbg(FYI, "ioctl clone range\n"); - /* the destination must be opened for writing */ - if (!(dst_file->f_mode & FMODE_WRITE)) { - cifs_dbg(FYI, "file target not open for write\n"); - return -EINVAL; - } - - /* check if target volume is readonly and take reference */ - rc = mnt_want_write_file(dst_file); - if (rc) { - cifs_dbg(FYI, "mnt_want_write failed with rc %d\n", rc); - return rc; - } - - src_file = fdget(srcfd); - if (!src_file.file) { - rc = -EBADF; - goto out_drop_write; - } - - if (src_file.file->f_op->unlocked_ioctl != cifs_ioctl) { - rc = -EBADF; - cifs_dbg(VFS, "src file seems to be from a different filesystem type\n"); - goto out_fput; - } - - if ((!src_file.file->private_data) || (!dst_file->private_data)) { + if ((!src_file->private_data) || (!dst_file->private_data)) { rc = -EBADF; cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n"); - goto out_fput; + goto out; } rc = -EXDEV; smb_file_target = dst_file->private_data; - smb_file_src = src_file.file->private_data; + smb_file_src = src_file->private_data; src_tcon = tlink_tcon(smb_file_src->tlink); target_tcon = tlink_tcon(smb_file_target->tlink); /* check if source and target are on same tree connection */ if (src_tcon != target_tcon) { cifs_dbg(VFS, "file copy src and target on different volume\n"); - goto out_fput; + goto out; } - src_inode = file_inode(src_file.file); - rc = -EINVAL; - if (S_ISDIR(src_inode->i_mode)) - goto out_fput; - /* * Note: cifs case is easier than btrfs since server responsible for * checks for proper open modes and file type and if it wants @@ -131,6 +99,52 @@ out_unlock: /* although unlocking in the reverse order from locking is not strictly necessary here it is a little cleaner to be consistent */ unlock_two_nondirectories(src_inode, target_inode); +out: + return rc; +} + +static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file, + unsigned long srcfd, u64 off, u64 len, u64 destoff, + bool dup_extents) +{ + int rc; + struct fd src_file; + struct inode *src_inode; + + cifs_dbg(FYI, "ioctl clone range\n"); + /* the destination must be opened for writing */ + if (!(dst_file->f_mode & FMODE_WRITE)) { + cifs_dbg(FYI, "file target not open for write\n"); + return -EINVAL; + } + + /* check if target volume is readonly and take reference */ + rc = mnt_want_write_file(dst_file); + if (rc) { + cifs_dbg(FYI, "mnt_want_write failed with rc %d\n", rc); + return rc; + } + + src_file = fdget(srcfd); + if (!src_file.file) { + rc = -EBADF; + goto out_drop_write; + } + + if (src_file.file->f_op->unlocked_ioctl != cifs_ioctl) { + rc = -EBADF; + cifs_dbg(VFS, "src file seems to be from a different filesystem type\n"); + goto out_fput; + } + + src_inode = file_inode(src_file.file); + rc = -EINVAL; + if (S_ISDIR(src_inode->i_mode)) + goto out_fput; + + rc = cifs_file_clone_range(xid, src_file.file, dst_file, off, len, + destoff, dup_extents); + out_fput: fdput(src_file); out_drop_write: