Skip to contentSkip to conversation

Add SMB3.11 mount option synonym for new dialect

PATCH New Steve French 2 participants 5 messages Jun 28, 2015 1 message not in the archive

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/5 Add SMB3.11 mount option synonym for new dialect

From: Steve French <[email protected]>

Most people think of SMB 3.1.1 as SMB version 3.11 so add synonym for "vers=3.1.1" of "vers=3.11" on mount.

Also make sure that unlike SMB3.0 and 3.02 we don't send validate negotiate on mount (it is handled by negotiate contexts) - add list of SMB3.11 specific functions (distinct from 3.0 dialect).

---
 fs/cifs/cifsglob.h |  3 +-
 fs/cifs/connect.c  |  3 +-
 fs/cifs/smb2ops.c  | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 90 insertions(+), 2 deletions(-)
fs/cifs/cifsglob.h +2 -1
index 71bf86e..a0212ec 100644
@@ -1622,6 +1622,7 @@ extern struct smb_version_values smb30_values;
 /*extern struct smb_version_operations smb302_operations;*/ /* not needed yet */
 extern struct smb_version_values smb302_values;
 #define SMB311_VERSION_STRING	"3.1.1"
-/*extern struct smb_version_operations smb311_operations;*/ /* not needed yet */
+#define ALT_SMB311_VERSION_STRING "3.11"
+extern struct smb_version_operations smb311_operations;
 extern struct smb_version_values smb311_values;
 #endif	/* _CIFS_GLOB_H */
fs/cifs/connect.c +2 -1
index 9300b98..247f4dd 100644
@@ -282,6 +282,7 @@ static const match_table_t cifs_smb_version_tokens = {
 	{ Smb_302, SMB302_VERSION_STRING },
 #ifdef CONFIG_CIFS_SMB311
 	{ Smb_311, SMB311_VERSION_STRING },
+	{ Smb_311, ALT_SMB311_VERSION_STRING },
 #endif /* SMB311 */
 	{ Smb_version_err, NULL }
 };
@@ -1139,7 +1140,7 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol)
 		break;
 #ifdef CONFIG_CIFS_SMB311
 	case Smb_311:
-		vol->ops = &smb30_operations; /* currently identical with 3.0 */
+		vol->ops = &smb311_operations;
 		vol->vals = &smb311_values;
 		break;
 #endif /* SMB311 */
fs/cifs/smb2ops.c +86 -0

92 lines not on this page · raw message

Signature · 1 line
2.1.4

A message that is not in the archive (sent off-list or not yet received): 1435534570-10864-1-git-send-email-steve.french-7I+n7zu2hftEKMMhf/[email protected]

#2 lore raw

PATCH 2/5 Add reflink copy over SMB3.11 with new FSCTL_DUPLICATE_EXTENTS

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.

---
 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(-)
fs/cifs/cifsglob.h +3 -0
index a0212ec..81194e6 100644
@@ -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 *,
fs/cifs/cifspdu.h +2 -0
index 998a66f..47b030d 100644
@@ -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
fs/cifs/ioctl.c +13 -3
index 8b7898b..7843b19 100644
@@ -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);
 			break;
 		default:
 			cifs_dbg(FYI, "unsupported ioctl\n");
fs/cifs/smb2ops.c +48 -0

60 lines not on this page · raw message

fs/cifs/smb2pdu.h +8 -0
index 725283a..8e7bbe5 100644
@@ -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 */
fs/cifs/smbfsctl.h +1 -0
index 83efa59..d098da6 100644
@@ -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 */
Signature · 1 line
2.1.4
#3 lore raw

PATCH 4/5 Add ioctl to set integrity

In reply to a message not in the archive

From: Steve French <[email protected]>

set integrity increases reliability of files stored on SMB3 servers. Add ioctl to allow setting this on files on SMB3 and later mounts.

---
 fs/cifs/cifsglob.h |  2 ++
 fs/cifs/ioctl.c    | 11 +++++++++++
 fs/cifs/smb2ops.c  | 24 ++++++++++++++++++++++++
 fs/cifs/smb2pdu.h  |  1 +
 4 files changed, 38 insertions(+)
fs/cifs/cifsglob.h +2 -0
index 81194e6..b406a32 100644
@@ -372,6 +372,8 @@ struct smb_version_operations {
 	void (*new_lease_key)(struct cifs_fid *);
 	int (*generate_signingkey)(struct cifs_ses *);
 	int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *);
+	int (*set_integrity)(const unsigned int, struct cifs_tcon *tcon,
+			     struct cifsFileInfo *src_file);
 	int (*query_mf_symlink)(unsigned int, struct cifs_tcon *,
 				struct cifs_sb_info *, const unsigned char *,
 				char *, unsigned int *);
fs/cifs/ioctl.c +11 -0
index 7843b19..49b8b6e 100644
@@ -35,6 +35,7 @@
 
 #define CIFS_IOCTL_MAGIC	0xCF
 #define CIFS_IOC_COPYCHUNK_FILE	_IOW(CIFS_IOCTL_MAGIC, 3, int)
+#define CIFS_IOC_SET_INTEGRITY  _IO(CIFS_IOCTL_MAGIC, 4)
 
 static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file,
 			unsigned long srcfd, u64 off, u64 len, u64 destoff,
@@ -217,6 +218,16 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
 		case BTRFS_IOC_CLONE:
 			rc = cifs_ioctl_clone(xid, filep, arg, 0, 0, 0, true);
 			break;
+		case CIFS_IOC_SET_INTEGRITY:
+			if (pSMBFile == NULL)
+				break;
+			tcon = tlink_tcon(pSMBFile->tlink);
+			if (tcon->ses->server->ops->set_integrity)
+				rc = tcon->ses->server->ops->set_integrity(xid,
+						tcon, pSMBFile);
+			else
+				rc = -EOPNOTSUPP;
+			break;
 		default:
 			cifs_dbg(FYI, "unsupported ioctl\n");
 			break;
fs/cifs/smb2ops.c +24 -0
index d8a124c..f92960b 100644
@@ -862,6 +862,28 @@ smb2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
 }
 
 static int
+smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon,
+		   struct cifsFileInfo *cfile)
+{
+	struct fsctl_set_integrity_information_req integr_info;
+	char *retbuf = NULL;
+	unsigned int ret_data_len;
+
+	integr_info.ChecksumAlgorithm = cpu_to_le16(CHECKSUM_TYPE_UNCHANGED);
+	integr_info.Flags = 0;
+	integr_info.Reserved = 0;
+
+	return SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
+			cfile->fid.volatile_fid,
+			FSCTL_SET_INTEGRITY_INFORMATION,
+			true /* is_fsctl */, (char *)&integr_info,
+			sizeof(struct fsctl_set_integrity_information_req),
+			(char **)&retbuf,
+			&ret_data_len);
+
+}
+
+static int
 smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
 		     const char *path, struct cifs_sb_info *cifs_sb,
 		     struct cifs_fid *fid, __u16 search_flags,
@@ -1671,6 +1693,7 @@ struct smb_version_operations smb30_operations = {
 	.new_lease_key = smb2_new_lease_key,
 	.generate_signingkey = generate_smb3signingkey,
 	.calc_signature = smb3_calc_signature,
+	.set_integrity  = smb3_set_integrity,
 	.is_read_op = smb21_is_read_op,
 	.set_oplock_level = smb3_set_oplock_level,
 	.create_lease_buf = smb3_create_lease_buf,
@@ -1756,6 +1779,7 @@ struct smb_version_operations smb311_operations = {
 	.new_lease_key = smb2_new_lease_key,
 	.generate_signingkey = generate_smb3signingkey,
 	.calc_signature = smb3_calc_signature,
+	.set_integrity  = smb3_set_integrity,
 	.is_read_op = smb21_is_read_op,
 	.set_oplock_level = smb3_set_oplock_level,
 	.create_lease_buf = smb3_create_lease_buf,
fs/cifs/smb2pdu.h +1 -0
index c302e82..2d91c2a 100644
@@ -638,6 +638,7 @@ struct fsctl_get_integrity_information_rsp {
 /* Integrity ChecksumAlgorithm choices for above */
 #define	CHECKSUM_TYPE_NONE	0x0000
 #define	CHECKSUM_TYPE_CRC64	0x0002
+#define CHECKSUM_TYPE_UNCHANGED	0xFFFF	/* set only */
 
 /* Integrity flags for above */
 #define FSCTL_INTEGRITY_FLAG_CHECKSUM_ENFORCEMENT_OFF	0x00000001
Signature · 1 line
2.1.4
#4 lore raw

PATCH 5/5 Update negotiate protocol for SMB3.11 dialect

In reply to a message not in the archive

From: Steve French <[email protected]>

Send negotiate contexts when SMB3.11 dialect is negotiated (ie the preauth and the encryption contexts) and Initialize SMB3.11 preauth negotiate context salt to random bytes

Followon patch will update session setup and tree connect

---
 fs/cifs/smb2pdu.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 fs/cifs/smb2pdu.h |  6 +++---
 2 files changed, 60 insertions(+), 5 deletions(-)
fs/cifs/smb2pdu.c +57 -2
index 0479e3c..b8b4f08 100644
@@ -304,6 +304,59 @@ small_smb2_init(__le16 smb2_command, struct cifs_tcon *tcon,
 	return rc;
 }
 
+#ifdef CONFIG_CIFS_SMB311
+/* offset is sizeof smb2_negotiate_req - 4 but rounded up to 8 bytes */
+#define OFFSET_OF_NEG_CONTEXT 0x68  /* sizeof(struct smb2_negotiate_req) - 4 */
+
+
+#define SMB2_PREAUTH_INTEGRITY_CAPABILITIES	cpu_to_le16(1)
+#define SMB2_ENCRYPTION_CAPABILITIES		cpu_to_le16(2)
+
+static void
+build_preauth_ctxt(struct smb2_preauth_neg_context *pneg_ctxt)
+{
+	pneg_ctxt->ContextType = SMB2_PREAUTH_INTEGRITY_CAPABILITIES;
+	pneg_ctxt->DataLength = cpu_to_le16(38);
+	pneg_ctxt->HashAlgorithmCount = cpu_to_le16(1);
+	pneg_ctxt->SaltLength = cpu_to_le16(SMB311_SALT_SIZE);
+	get_random_bytes(pneg_ctxt->Salt, SMB311_SALT_SIZE);
+	pneg_ctxt->HashAlgorithms = SMB2_PREAUTH_INTEGRITY_SHA512;
+}
+
+static void
+build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt)
+{
+	pneg_ctxt->ContextType = SMB2_ENCRYPTION_CAPABILITIES;
+	pneg_ctxt->DataLength = cpu_to_le16(6);
+	pneg_ctxt->CipherCount = cpu_to_le16(2);
+	pneg_ctxt->Ciphers[0] = SMB2_ENCRYPTION_AES128_GCM;
+	pneg_ctxt->Ciphers[1] = SMB2_ENCRYPTION_AES128_CCM;
+}
+
+static void
+assemble_neg_contexts(struct smb2_negotiate_req *req)
+{
+
+	/* +4 is to account for the RFC1001 len field */
+	char *pneg_ctxt = (char *)req + OFFSET_OF_NEG_CONTEXT + 4;
+
+	build_preauth_ctxt((struct smb2_preauth_neg_context *)pneg_ctxt);
+	/* Add 2 to size to round to 8 byte boundary */
+	pneg_ctxt += 2 + sizeof(struct smb2_preauth_neg_context);
+	build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt);
+	req->NegotiateContextOffset = cpu_to_le32(OFFSET_OF_NEG_CONTEXT);
+	req->NegotiateContextCount = cpu_to_le16(2);
+	inc_rfc1001_len(req, 4 + sizeof(struct smb2_preauth_neg_context) + 2
+			+ sizeof(struct smb2_encryption_neg_context)); /* calculate hash */
+}
+#else
+static void assemble_neg_contexts(struct smb2_negotiate_req *req)
+{
+	return;
+}
+#endif /* SMB311 */
+
+
 /*
  *
  *	SMB2 Worker functions follow:
@@ -363,10 +416,12 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
 	/* ClientGUID must be zero for SMB2.02 dialect */
 	if (ses->server->vals->protocol_id == SMB20_PROT_ID)
 		memset(req->ClientGUID, 0, SMB2_CLIENT_GUID_SIZE);
-	else
+	else {
 		memcpy(req->ClientGUID, server->client_guid,
 			SMB2_CLIENT_GUID_SIZE);
-
+		if (ses->server->vals->protocol_id == SMB311_PROT_ID)
+			assemble_neg_contexts(req);
+	}
 	iov[0].iov_base = (char *)req;
 	/* 4 for rfc1002 length field */
 	iov[0].iov_len = get_rfc1002_length(req) + 4;
fs/cifs/smb2pdu.h +3 -3
index 2d91c2a..4511082 100644
@@ -220,7 +220,7 @@ struct smb2_negotiate_req {
 
 #define SMB311_SALT_SIZE			32
 /* Hash Algorithm Types */
-#define SMB2_PREAUTH_INTEGRITY_SHA512	0x0001
+#define SMB2_PREAUTH_INTEGRITY_SHA512	cpu_to_le16(0x0001)
 
 struct smb2_preauth_neg_context {
 	__le16	ContextType; /* 1 */
@@ -240,8 +240,8 @@ struct smb2_encryption_neg_context {
 	__le16	ContextType; /* 2 */
 	__le16	DataLength;
 	__le32	Reserved;
-	__le16	CipherCount; /* 1 for time being, only AES-128-CCM */
-	__le16	Ciphers; /* Ciphers[0] since only one used now */
+	__le16	CipherCount; /* AES-128-GCM and AES-128-CCM */
+	__le16	Ciphers[2]; /* Ciphers[0] since only one used now */
 } __packed;
 
 struct smb2_negotiate_rsp {
Signature · 1 line
2.1.4
#5 lore raw

PATCH 3/5 Add Get/Set Integrity Information structure definitions

In reply to Steve French

From: Steve French <[email protected]>

---
 fs/cifs/smb2pdu.h  | 22 ++++++++++++++++++++++
 fs/cifs/smbfsctl.h |  2 ++
 2 files changed, 24 insertions(+)
fs/cifs/smb2pdu.h +22 -0
index 8e7bbe5..c302e82 100644
@@ -621,6 +621,28 @@ struct copychunk_ioctl_rsp {
 	__le32 TotalBytesWritten;
 } __packed;
 
+struct fsctl_set_integrity_information_req {
+	__le16	ChecksumAlgorithm;
+	__le16	Reserved;
+	__le32	Flags;
+} __packed;
+
+struct fsctl_get_integrity_information_rsp {
+	__le16	ChecksumAlgorithm;
+	__le16	Reserved;
+	__le32	Flags;
+	__le32	ChecksumChunkSizeInBytes;
+	__le32	ClusterSizeInBytes;
+} __packed;
+
+/* Integrity ChecksumAlgorithm choices for above */
+#define	CHECKSUM_TYPE_NONE	0x0000
+#define	CHECKSUM_TYPE_CRC64	0x0002
+
+/* Integrity flags for above */
+#define FSCTL_INTEGRITY_FLAG_CHECKSUM_ENFORCEMENT_OFF	0x00000001
+
+
 struct validate_negotiate_info_req {
 	__le32 Capabilities;
 	__u8   Guid[SMB2_CLIENT_GUID_SIZE];
fs/cifs/smbfsctl.h +2 -0
index d098da6..a639d0d 100644
@@ -75,11 +75,13 @@
 #define FSCTL_QUERY_SPARING_INFO     0x00090138 /* BB add struct */
 #define FSCTL_SET_ZERO_ON_DEALLOC    0x00090194 /* BB add struct */
 #define FSCTL_SET_SHORT_NAME_BEHAVIOR 0x000901B4 /* BB add struct */
+#define FSCTL_GET_INTEGRITY_INFORMATION 0x0009027C
 #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_SET_INTEGRITY_INFORMATION 0x0009C280
 #define FSCTL_PIPE_PEEK              0x0011400C /* BB add struct */
 #define FSCTL_PIPE_TRANSCEIVE        0x0011C017 /* BB add struct */
 /* strange that the number for this op is not sequential with previous op */
Signature · 1 line
2.1.4