From patchwork Sun Jun 28 23:36:07 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steve French X-Patchwork-Id: 6686811 Return-Path: X-Original-To: patchwork-cifs-client@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id D6DE69F380 for ; Sun, 28 Jun 2015 23:36:36 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id B71DC20544 for ; Sun, 28 Jun 2015 23:36:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 7ABEB20524 for ; Sun, 28 Jun 2015 23:36:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752450AbbF1Xgd (ORCPT ); Sun, 28 Jun 2015 19:36:33 -0400 Received: from mail-yk0-f175.google.com ([209.85.160.175]:35807 "EHLO mail-yk0-f175.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752713AbbF1Xg2 (ORCPT ); Sun, 28 Jun 2015 19:36:28 -0400 Received: by ykdy1 with SMTP id y1so101251404ykd.2; Sun, 28 Jun 2015 16:36:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=rqXN1NlibuLxqypG817D22KkUppz6ix4i5VGVaNESDI=; b=eFl3Liy6Gdm8a8qhEc+zHC4O6S5Kqz0pU+wKZxTiI0a7QDa6zPf8ibA7UzVXBAmovw NnOau3HEaaEt5rDMUc1e9I7dZDYjjvHPWA/Rz1MFiU4MqyjBwFJ6CX6YMHlCWrPkra62 7svqhBDRR/F7QqHpySSqm0sXqULevdSfQaCIoeBb5acpS/zIppH/G1twV9YE0fqzOEJm ecxEul8v9PVn0+yEND7f2R6PRUBC27ntpAGrSOIgSzOizOC3jcPXUdaWEHFASP3m+jyH UqVCu7ePSzszzvx1UyAryvfmSGag1MpM7ki8R0mR/GyQULgvYTfwQZ7ITJxZznuFONwp uZ5A== X-Received: by 10.170.218.86 with SMTP id k83mr15610674ykf.6.1435534586708; Sun, 28 Jun 2015 16:36:26 -0700 (PDT) Received: from ubuntu.localdomain (cpe-68-203-16-26.austin.res.rr.com. [68.203.16.26]) by mx.google.com with ESMTPSA id q67sm35224189ywe.54.2015.06.28.16.36.24 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 28 Jun 2015 16:36:25 -0700 (PDT) From: Steve French X-Google-Original-From: Steve French To: linux-cifs@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org, Steve French Subject: [PATCH 2/5] Add reflink copy over SMB3.11 with new FSCTL_DUPLICATE_EXTENTS Date: Sun, 28 Jun 2015 18:36:07 -0500 Message-Id: <1435534570-10864-2-git-send-email-steve.french@primarydata.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1435534570-10864-1-git-send-email-steve.french@primarydata.com> References: <1435534570-10864-1-git-send-email-steve.french@primarydata.com> Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org X-Spam-Status: No, score=-7.4 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, 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 Getting fantastic copy performance with cp --reflink over SMB3.11 using the new FSCTL_DUPLICATE_EXTENTS. This FSCTL was added in the SMB3.11 dialect (testing was against REFS file system) so have put it as a 3.11 protocol specific operation ("vers=3.1.1" on the mount). Tested at the SMB3 plugfest in Redmond. It depends on the new FS Attribute (BLOCK_REFCOUNTING) which is used to advertise support for the ability to do this ioctl (if you can support multiple files pointing to the same block than this refcounting ability or equivalent is needed to support the new reflink-like duplicate extent SMB3 ioctl. Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 3 +++ fs/cifs/cifspdu.h | 2 ++ fs/cifs/ioctl.c | 16 +++++++++++++--- fs/cifs/smb2ops.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/smb2pdu.h | 8 ++++++++ fs/cifs/smbfsctl.h | 1 + 6 files changed, 75 insertions(+), 3 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index a0212ec..81194e6 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -390,6 +390,9 @@ struct smb_version_operations { int (*clone_range)(const unsigned int, struct cifsFileInfo *src_file, struct cifsFileInfo *target_file, u64 src_off, u64 len, u64 dest_off); + int (*duplicate_extents)(const unsigned int, struct cifsFileInfo *src, + struct cifsFileInfo *target_file, u64 src_off, u64 len, + u64 dest_off); int (*validate_negotiate)(const unsigned int, struct cifs_tcon *); ssize_t (*query_all_EAs)(const unsigned int, struct cifs_tcon *, const unsigned char *, const unsigned char *, char *, diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 998a66f..47b030d 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -2255,6 +2255,8 @@ typedef struct { /* List of FileSystemAttributes - see 2.5.1 of MS-FSCC */ +#define FILE_SUPPORTS_SPARSE_VDL 0x10000000 /* faster nonsparse extend */ +#define FILE_SUPPORTS_BLOCK_REFCOUNTING 0x08000000 /* allow ioctl dup extents */ #define FILE_SUPPORT_INTEGRITY_STREAMS 0x04000000 #define FILE_SUPPORTS_USN_JOURNAL 0x02000000 #define FILE_SUPPORTS_OPEN_BY_FILE_ID 0x01000000 diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index 8b7898b..7843b19 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c @@ -31,12 +31,14 @@ #include "cifsproto.h" #include "cifs_debug.h" #include "cifsfs.h" +#include #define CIFS_IOCTL_MAGIC 0xCF #define CIFS_IOC_COPYCHUNK_FILE _IOW(CIFS_IOCTL_MAGIC, 3, int) static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file, - unsigned long srcfd, u64 off, u64 len, u64 destoff) + unsigned long srcfd, u64 off, u64 len, u64 destoff, + bool dup_extents) { int rc; struct cifsFileInfo *smb_file_target = dst_file->private_data; @@ -109,9 +111,14 @@ static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file, truncate_inode_pages_range(&target_inode->i_data, destoff, PAGE_CACHE_ALIGN(destoff + len)-1); - if (target_tcon->ses->server->ops->clone_range) + if (dup_extents && target_tcon->ses->server->ops->duplicate_extents) + rc = target_tcon->ses->server->ops->duplicate_extents(xid, + smb_file_src, smb_file_target, off, len, destoff); + else if (!dup_extents && target_tcon->ses->server->ops->clone_range) rc = target_tcon->ses->server->ops->clone_range(xid, smb_file_src, smb_file_target, off, len, destoff); + else + rc = -EOPNOTSUPP; /* force revalidate of size and timestamps of target file now that target is updated on the server */ @@ -205,7 +212,10 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) } break; case CIFS_IOC_COPYCHUNK_FILE: - rc = cifs_ioctl_clone(xid, filep, arg, 0, 0, 0); + rc = cifs_ioctl_clone(xid, filep, arg, 0, 0, 0, false); + break; + case BTRFS_IOC_CLONE: + rc = cifs_ioctl_clone(xid, filep, arg, 0, 0, 0, true); break; default: cifs_dbg(FYI, "unsupported ioctl\n"); diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index c7d228c..d8a124c 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -806,6 +806,53 @@ smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon, cfile->fid.volatile_fid, cfile->pid, &eof, false); } +#ifdef CONFIG_CIFS_SMB311 +static int +smb2_duplicate_extents(const unsigned int xid, + struct cifsFileInfo *srcfile, + struct cifsFileInfo *trgtfile, u64 src_off, + u64 len, u64 dest_off) +{ + int rc; + unsigned int ret_data_len; + char *retbuf = NULL; + struct duplicate_extents_to_file dup_ext_buf; + struct cifs_tcon *tcon = tlink_tcon(trgtfile->tlink); + + /* server fileays advertise duplicate extent support with this flag */ + if ((le32_to_cpu(tcon->fsAttrInfo.Attributes) & + FILE_SUPPORTS_BLOCK_REFCOUNTING) == 0) + return -EOPNOTSUPP; + + dup_ext_buf.VolatileFileHandle = srcfile->fid.volatile_fid; + dup_ext_buf.PersistentFileHandle = srcfile->fid.persistent_fid; + dup_ext_buf.SourceFileOffset = cpu_to_le64(src_off); + dup_ext_buf.TargetFileOffset = cpu_to_le64(dest_off); + dup_ext_buf.ByteCount = cpu_to_le64(len); + cifs_dbg(FYI, "duplicate extents: src off %lld dst off %lld len %lld", + src_off, dest_off, len); + + rc = smb2_set_file_size(xid, tcon, trgtfile, len, false); + if (rc) + goto duplicate_extents_out; + + rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid, + trgtfile->fid.volatile_fid, + FSCTL_DUPLICATE_EXTENTS_TO_FILE, + true /* is_fsctl */, (char *)&dup_ext_buf, + sizeof(struct duplicate_extents_to_file), + (char **)&retbuf, + &ret_data_len); + + if (ret_data_len > 0) + cifs_dbg(FYI, "non-zero response length in duplicate extents"); + +duplicate_extents_out: + return rc; +} +#endif /* CONFIG_CIFS_SMB311 */ + + static int smb2_set_compression(const unsigned int xid, struct cifs_tcon *tcon, struct cifsFileInfo *cfile) @@ -1714,6 +1761,7 @@ struct smb_version_operations smb311_operations = { .create_lease_buf = smb3_create_lease_buf, .parse_lease_buf = smb3_parse_lease_buf, .clone_range = smb2_clone_range, + .duplicate_extents = smb2_duplicate_extents, /* .validate_negotiate = smb3_validate_negotiate, */ /* not used in 3.11 */ .wp_retry_size = smb2_wp_retry_size, .dir_needs_close = smb2_dir_needs_close, diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index 725283a..8e7bbe5 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -654,6 +654,14 @@ struct compress_ioctl { __le16 CompressionState; /* See cifspdu.h for possible flag values */ } __packed; +struct duplicate_extents_to_file { + __u64 PersistentFileHandle; /* source file handle, opaque endianness */ + __u64 VolatileFileHandle; + __le64 SourceFileOffset; + __le64 TargetFileOffset; + __le64 ByteCount; /* Bytes to be copied */ +} __packed; + struct smb2_ioctl_req { struct smb2_hdr hdr; __le16 StructureSize; /* Must be 57 */ diff --git a/fs/cifs/smbfsctl.h b/fs/cifs/smbfsctl.h index 83efa59..d098da6 100644 --- a/fs/cifs/smbfsctl.h +++ b/fs/cifs/smbfsctl.h @@ -78,6 +78,7 @@ #define FSCTL_QUERY_ALLOCATED_RANGES 0x000940CF /* BB add struct */ #define FSCTL_SET_DEFECT_MANAGEMENT 0x00098134 /* BB add struct */ #define FSCTL_FILE_LEVEL_TRIM 0x00098208 /* BB add struct */ +#define FSCTL_DUPLICATE_EXTENTS_TO_FILE 0x00098344 #define FSCTL_SIS_LINK_FILES 0x0009C104 #define FSCTL_PIPE_PEEK 0x0011400C /* BB add struct */ #define FSCTL_PIPE_TRANSCEIVE 0x0011C017 /* BB add struct */