On Sun, Jun 28, 2015 at 09:21:05PM -0500, Steve French wrote: > Update the patch to correct target file size. > > 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 <steve.french@xxxxxxxxxxxxxxx> > --- > 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 <linux/btrfs.h> > > #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); Any interest in supporting BTRFS_IOC_CLONE_RANGE or BTRFS_IOC_EXTENT_SAME? It looks like you could easily support the former, and the latter would enable things like duperemove. I've been working on a pile of xfstests to exercise these three ioctls, will post them later today, I hope. --D > break; > default: > cifs_dbg(FYI, "unsupported ioctl\n"); > diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c > index c7d228c..b1e9c0f 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, dest_off + 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 */ > -- > 2.1.4 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html