aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-11-16 19:19:31 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-11-16 19:19:31 -0500
commit1213959d4ad2f523290d0d7c94f712edef63852c (patch)
tree530a5f546b52a5b6e459b8f42d823a3570eb390f /fs/cifs
parent673fdfe3f0630b03f3854d0361b1232f2e5ef7fb (diff)
parent0cbaa53cdd33080c1e2d67ad9295b83c7954f2b3 (diff)
Merge branch 'for-linus' of git://git.samba.org/sfrench/cifs-2.6
Pull CIFS fixes from Steve French: "A set of cifs fixes most important of which is Pavel's fix for some problems with handling Windows reparse points and also the security fix for setfacl over a cifs mount to Samba removing part of the ACL. Both of these fixes are for stable as well. Also added most of copychunk (copy offload) support to cifs although I expect a final patch in that series (to fix handling of larger files) in a few days (had to hold off on that in order to incorporate some additional code review feedback). Also added support for O_DIRECT on forcedirectio mounts (needed in order to run some of the server benchmarks over cifs and smb2/smb3 mounts)" * 'for-linus' of git://git.samba.org/sfrench/cifs-2.6: [CIFS] Warn if SMB3 encryption required by server setfacl removes part of ACL when setting POSIX ACLs to Samba [CIFS] Set copychunk defaults CIFS: SMB2/SMB3 Copy offload support (refcopy) phase 1 cifs: Use data structures to compute NTLMv2 response offsets [CIFS] O_DIRECT opens should work on directio mounts cifs: don't spam the logs on unexpected lookup errors cifs: change ERRnomem error mapping from ENOMEM to EREMOTEIO CIFS: Fix symbolic links usage
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifsencrypt.c40
-rw-r--r--fs/cifs/cifsglob.h8
-rw-r--r--fs/cifs/cifspdu.h8
-rw-r--r--fs/cifs/cifssmb.c8
-rw-r--r--fs/cifs/dir.c2
-rw-r--r--fs/cifs/file.c22
-rw-r--r--fs/cifs/inode.c23
-rw-r--r--fs/cifs/ioctl.c111
-rw-r--r--fs/cifs/netmisc.c2
-rw-r--r--fs/cifs/readdir.c40
-rw-r--r--fs/cifs/smb1ops.c21
-rw-r--r--fs/cifs/smb2inode.c16
-rw-r--r--fs/cifs/smb2maperror.c2
-rw-r--r--fs/cifs/smb2ops.c82
-rw-r--r--fs/cifs/smb2pdu.c12
-rw-r--r--fs/cifs/smb2pdu.h33
-rw-r--r--fs/cifs/smb2proto.h2
17 files changed, 358 insertions, 74 deletions
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index fc6f4f3a1a9d..4934347321d3 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -548,7 +548,13 @@ static int
548CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash) 548CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
549{ 549{
550 int rc; 550 int rc;
551 unsigned int offset = CIFS_SESS_KEY_SIZE + 8; 551 struct ntlmv2_resp *ntlmv2 = (struct ntlmv2_resp *)
552 (ses->auth_key.response + CIFS_SESS_KEY_SIZE);
553 unsigned int hash_len;
554
555 /* The MD5 hash starts at challenge_key.key */
556 hash_len = ses->auth_key.len - (CIFS_SESS_KEY_SIZE +
557 offsetof(struct ntlmv2_resp, challenge.key[0]));
552 558
553 if (!ses->server->secmech.sdeschmacmd5) { 559 if (!ses->server->secmech.sdeschmacmd5) {
554 cifs_dbg(VFS, "%s: can't generate ntlmv2 hash\n", __func__); 560 cifs_dbg(VFS, "%s: can't generate ntlmv2 hash\n", __func__);
@@ -556,7 +562,7 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
556 } 562 }
557 563
558 rc = crypto_shash_setkey(ses->server->secmech.hmacmd5, 564 rc = crypto_shash_setkey(ses->server->secmech.hmacmd5,
559 ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); 565 ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
560 if (rc) { 566 if (rc) {
561 cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n", 567 cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n",
562 __func__); 568 __func__);
@@ -570,20 +576,21 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
570 } 576 }
571 577
572 if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) 578 if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED)
573 memcpy(ses->auth_key.response + offset, 579 memcpy(ntlmv2->challenge.key,
574 ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE); 580 ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
575 else 581 else
576 memcpy(ses->auth_key.response + offset, 582 memcpy(ntlmv2->challenge.key,
577 ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE); 583 ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
578 rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, 584 rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
579 ses->auth_key.response + offset, ses->auth_key.len - offset); 585 ntlmv2->challenge.key, hash_len);
580 if (rc) { 586 if (rc) {
581 cifs_dbg(VFS, "%s: Could not update with response\n", __func__); 587 cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
582 return rc; 588 return rc;
583 } 589 }
584 590
591 /* Note that the MD5 digest over writes anon.challenge_key.key */
585 rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, 592 rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
586 ses->auth_key.response + CIFS_SESS_KEY_SIZE); 593 ntlmv2->ntlmv2_hash);
587 if (rc) 594 if (rc)
588 cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__); 595 cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
589 596
@@ -627,7 +634,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
627 int rc; 634 int rc;
628 int baselen; 635 int baselen;
629 unsigned int tilen; 636 unsigned int tilen;
630 struct ntlmv2_resp *buf; 637 struct ntlmv2_resp *ntlmv2;
631 char ntlmv2_hash[16]; 638 char ntlmv2_hash[16];
632 unsigned char *tiblob = NULL; /* target info blob */ 639 unsigned char *tiblob = NULL; /* target info blob */
633 640
@@ -660,13 +667,14 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
660 } 667 }
661 ses->auth_key.len += baselen; 668 ses->auth_key.len += baselen;
662 669
663 buf = (struct ntlmv2_resp *) 670 ntlmv2 = (struct ntlmv2_resp *)
664 (ses->auth_key.response + CIFS_SESS_KEY_SIZE); 671 (ses->auth_key.response + CIFS_SESS_KEY_SIZE);
665 buf->blob_signature = cpu_to_le32(0x00000101); 672 ntlmv2->blob_signature = cpu_to_le32(0x00000101);
666 buf->reserved = 0; 673 ntlmv2->reserved = 0;
667 buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); 674 /* Must be within 5 minutes of the server */
668 get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); 675 ntlmv2->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
669 buf->reserved2 = 0; 676 get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal));
677 ntlmv2->reserved2 = 0;
670 678
671 memcpy(ses->auth_key.response + baselen, tiblob, tilen); 679 memcpy(ses->auth_key.response + baselen, tiblob, tilen);
672 680
@@ -706,7 +714,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
706 } 714 }
707 715
708 rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, 716 rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
709 ses->auth_key.response + CIFS_SESS_KEY_SIZE, 717 ntlmv2->ntlmv2_hash,
710 CIFS_HMAC_MD5_HASH_SIZE); 718 CIFS_HMAC_MD5_HASH_SIZE);
711 if (rc) { 719 if (rc) {
712 cifs_dbg(VFS, "%s: Could not update with response\n", __func__); 720 cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 26b1c1dc93f6..d9ea7ada1378 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -261,7 +261,7 @@ struct smb_version_operations {
261 /* query path data from the server */ 261 /* query path data from the server */
262 int (*query_path_info)(const unsigned int, struct cifs_tcon *, 262 int (*query_path_info)(const unsigned int, struct cifs_tcon *,
263 struct cifs_sb_info *, const char *, 263 struct cifs_sb_info *, const char *,
264 FILE_ALL_INFO *, bool *); 264 FILE_ALL_INFO *, bool *, bool *);
265 /* query file data from the server */ 265 /* query file data from the server */
266 int (*query_file_info)(const unsigned int, struct cifs_tcon *, 266 int (*query_file_info)(const unsigned int, struct cifs_tcon *,
267 struct cifs_fid *, FILE_ALL_INFO *); 267 struct cifs_fid *, FILE_ALL_INFO *);
@@ -381,6 +381,9 @@ struct smb_version_operations {
381 char * (*create_lease_buf)(u8 *, u8); 381 char * (*create_lease_buf)(u8 *, u8);
382 /* parse lease context buffer and return oplock/epoch info */ 382 /* parse lease context buffer and return oplock/epoch info */
383 __u8 (*parse_lease_buf)(void *, unsigned int *); 383 __u8 (*parse_lease_buf)(void *, unsigned int *);
384 int (*clone_range)(const unsigned int, struct cifsFileInfo *src_file,
385 struct cifsFileInfo *target_file, u64 src_off, u64 len,
386 u64 dest_off);
384}; 387};
385 388
386struct smb_version_values { 389struct smb_version_values {
@@ -855,6 +858,9 @@ struct cifs_tcon {
855 __le64 vol_create_time; 858 __le64 vol_create_time;
856 __u32 ss_flags; /* sector size flags */ 859 __u32 ss_flags; /* sector size flags */
857 __u32 perf_sector_size; /* best sector size for perf */ 860 __u32 perf_sector_size; /* best sector size for perf */
861 __u32 max_chunks;
862 __u32 max_bytes_chunk;
863 __u32 max_bytes_copy;
858#endif /* CONFIG_CIFS_SMB2 */ 864#endif /* CONFIG_CIFS_SMB2 */
859#ifdef CONFIG_CIFS_FSCACHE 865#ifdef CONFIG_CIFS_FSCACHE
860 u64 resource_id; /* server resource id */ 866 u64 resource_id; /* server resource id */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 9e5ee34de986..33df36ef9d52 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -697,7 +697,13 @@ struct ntlmssp2_name {
697} __attribute__((packed)); 697} __attribute__((packed));
698 698
699struct ntlmv2_resp { 699struct ntlmv2_resp {
700 char ntlmv2_hash[CIFS_ENCPWD_SIZE]; 700 union {
701 char ntlmv2_hash[CIFS_ENCPWD_SIZE];
702 struct {
703 __u8 reserved[8];
704 __u8 key[CIFS_SERVER_CHALLENGE_SIZE];
705 } __attribute__((packed)) challenge;
706 } __attribute__((packed));
701 __le32 blob_signature; 707 __le32 blob_signature;
702 __u32 reserved; 708 __u32 reserved;
703 __le64 time; 709 __le64 time;
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 93b29474714a..124aa0230c1b 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -3369,11 +3369,13 @@ static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3369 return 0; 3369 return 0;
3370 } 3370 }
3371 cifs_acl->version = cpu_to_le16(1); 3371 cifs_acl->version = cpu_to_le16(1);
3372 if (acl_type == ACL_TYPE_ACCESS) 3372 if (acl_type == ACL_TYPE_ACCESS) {
3373 cifs_acl->access_entry_count = cpu_to_le16(count); 3373 cifs_acl->access_entry_count = cpu_to_le16(count);
3374 else if (acl_type == ACL_TYPE_DEFAULT) 3374 cifs_acl->default_entry_count = __constant_cpu_to_le16(0xFFFF);
3375 } else if (acl_type == ACL_TYPE_DEFAULT) {
3375 cifs_acl->default_entry_count = cpu_to_le16(count); 3376 cifs_acl->default_entry_count = cpu_to_le16(count);
3376 else { 3377 cifs_acl->access_entry_count = __constant_cpu_to_le16(0xFFFF);
3378 } else {
3377 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type); 3379 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
3378 return 0; 3380 return 0;
3379 } 3381 }
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 5384c2a640ca..11ff5f116b20 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -756,7 +756,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
756 /* if it was once a directory (but how can we tell?) we could do 756 /* if it was once a directory (but how can we tell?) we could do
757 shrink_dcache_parent(direntry); */ 757 shrink_dcache_parent(direntry); */
758 } else if (rc != -EACCES) { 758 } else if (rc != -EACCES) {
759 cifs_dbg(VFS, "Unexpected lookup error %d\n", rc); 759 cifs_dbg(FYI, "Unexpected lookup error %d\n", rc);
760 /* We special case check for Access Denied - since that 760 /* We special case check for Access Denied - since that
761 is a common return code */ 761 is a common return code */
762 } 762 }
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 7ddddf2e2504..5a5a87240fe2 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -3663,6 +3663,27 @@ void cifs_oplock_break(struct work_struct *work)
3663 } 3663 }
3664} 3664}
3665 3665
3666/*
3667 * The presence of cifs_direct_io() in the address space ops vector
3668 * allowes open() O_DIRECT flags which would have failed otherwise.
3669 *
3670 * In the non-cached mode (mount with cache=none), we shunt off direct read and write requests
3671 * so this method should never be called.
3672 *
3673 * Direct IO is not yet supported in the cached mode.
3674 */
3675static ssize_t
3676cifs_direct_io(int rw, struct kiocb *iocb, const struct iovec *iov,
3677 loff_t pos, unsigned long nr_segs)
3678{
3679 /*
3680 * FIXME
3681 * Eventually need to support direct IO for non forcedirectio mounts
3682 */
3683 return -EINVAL;
3684}
3685
3686
3666const struct address_space_operations cifs_addr_ops = { 3687const struct address_space_operations cifs_addr_ops = {
3667 .readpage = cifs_readpage, 3688 .readpage = cifs_readpage,
3668 .readpages = cifs_readpages, 3689 .readpages = cifs_readpages,
@@ -3672,6 +3693,7 @@ const struct address_space_operations cifs_addr_ops = {
3672 .write_end = cifs_write_end, 3693 .write_end = cifs_write_end,
3673 .set_page_dirty = __set_page_dirty_nobuffers, 3694 .set_page_dirty = __set_page_dirty_nobuffers,
3674 .releasepage = cifs_release_page, 3695 .releasepage = cifs_release_page,
3696 .direct_IO = cifs_direct_io,
3675 .invalidatepage = cifs_invalidate_page, 3697 .invalidatepage = cifs_invalidate_page,
3676 .launder_page = cifs_launder_page, 3698 .launder_page = cifs_launder_page,
3677}; 3699};
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 867b7cdc794a..36f9ebb93ceb 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -542,7 +542,8 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
542/* Fill a cifs_fattr struct with info from FILE_ALL_INFO */ 542/* Fill a cifs_fattr struct with info from FILE_ALL_INFO */
543static void 543static void
544cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, 544cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
545 struct cifs_sb_info *cifs_sb, bool adjust_tz) 545 struct cifs_sb_info *cifs_sb, bool adjust_tz,
546 bool symlink)
546{ 547{
547 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 548 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
548 549
@@ -569,7 +570,11 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
569 fattr->cf_createtime = le64_to_cpu(info->CreationTime); 570 fattr->cf_createtime = le64_to_cpu(info->CreationTime);
570 571
571 fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); 572 fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
572 if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { 573
574 if (symlink) {
575 fattr->cf_mode = S_IFLNK;
576 fattr->cf_dtype = DT_LNK;
577 } else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
573 fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; 578 fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
574 fattr->cf_dtype = DT_DIR; 579 fattr->cf_dtype = DT_DIR;
575 /* 580 /*
@@ -578,10 +583,6 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
578 */ 583 */
579 if (!tcon->unix_ext) 584 if (!tcon->unix_ext)
580 fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK; 585 fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
581 } else if (fattr->cf_cifsattrs & ATTR_REPARSE) {
582 fattr->cf_mode = S_IFLNK;
583 fattr->cf_dtype = DT_LNK;
584 fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
585 } else { 586 } else {
586 fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode; 587 fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
587 fattr->cf_dtype = DT_REG; 588 fattr->cf_dtype = DT_REG;
@@ -626,7 +627,8 @@ cifs_get_file_info(struct file *filp)
626 rc = server->ops->query_file_info(xid, tcon, &cfile->fid, &find_data); 627 rc = server->ops->query_file_info(xid, tcon, &cfile->fid, &find_data);
627 switch (rc) { 628 switch (rc) {
628 case 0: 629 case 0:
629 cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false); 630 cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false,
631 false);
630 break; 632 break;
631 case -EREMOTE: 633 case -EREMOTE:
632 cifs_create_dfs_fattr(&fattr, inode->i_sb); 634 cifs_create_dfs_fattr(&fattr, inode->i_sb);
@@ -673,6 +675,7 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
673 bool adjust_tz = false; 675 bool adjust_tz = false;
674 struct cifs_fattr fattr; 676 struct cifs_fattr fattr;
675 struct cifs_search_info *srchinf = NULL; 677 struct cifs_search_info *srchinf = NULL;
678 bool symlink = false;
676 679
677 tlink = cifs_sb_tlink(cifs_sb); 680 tlink = cifs_sb_tlink(cifs_sb);
678 if (IS_ERR(tlink)) 681 if (IS_ERR(tlink))
@@ -702,12 +705,12 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
702 } 705 }
703 data = (FILE_ALL_INFO *)buf; 706 data = (FILE_ALL_INFO *)buf;
704 rc = server->ops->query_path_info(xid, tcon, cifs_sb, full_path, 707 rc = server->ops->query_path_info(xid, tcon, cifs_sb, full_path,
705 data, &adjust_tz); 708 data, &adjust_tz, &symlink);
706 } 709 }
707 710
708 if (!rc) { 711 if (!rc) {
709 cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *)data, cifs_sb, 712 cifs_all_info_to_fattr(&fattr, data, cifs_sb, adjust_tz,
710 adjust_tz); 713 symlink);
711 } else if (rc == -EREMOTE) { 714 } else if (rc == -EREMOTE) {
712 cifs_create_dfs_fattr(&fattr, sb); 715 cifs_create_dfs_fattr(&fattr, sb);
713 rc = 0; 716 rc = 0;
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index ba54bf6ab116..409b45eefe70 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -22,12 +22,120 @@
22 */ 22 */
23 23
24#include <linux/fs.h> 24#include <linux/fs.h>
25#include <linux/file.h>
26#include <linux/mount.h>
27#include <linux/mm.h>
28#include <linux/pagemap.h>
29#include <linux/btrfs.h>
25#include "cifspdu.h" 30#include "cifspdu.h"
26#include "cifsglob.h" 31#include "cifsglob.h"
27#include "cifsproto.h" 32#include "cifsproto.h"
28#include "cifs_debug.h" 33#include "cifs_debug.h"
29#include "cifsfs.h" 34#include "cifsfs.h"
30 35
36static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file,
37 unsigned long srcfd, u64 off, u64 len, u64 destoff)
38{
39 int rc;
40 struct cifsFileInfo *smb_file_target = dst_file->private_data;
41 struct inode *target_inode = file_inode(dst_file);
42 struct cifs_tcon *target_tcon;
43 struct fd src_file;
44 struct cifsFileInfo *smb_file_src;
45 struct inode *src_inode;
46 struct cifs_tcon *src_tcon;
47
48 cifs_dbg(FYI, "ioctl clone range\n");
49 /* the destination must be opened for writing */
50 if (!(dst_file->f_mode & FMODE_WRITE)) {
51 cifs_dbg(FYI, "file target not open for write\n");
52 return -EINVAL;
53 }
54
55 /* check if target volume is readonly and take reference */
56 rc = mnt_want_write_file(dst_file);
57 if (rc) {
58 cifs_dbg(FYI, "mnt_want_write failed with rc %d\n", rc);
59 return rc;
60 }
61
62 src_file = fdget(srcfd);
63 if (!src_file.file) {
64 rc = -EBADF;
65 goto out_drop_write;
66 }
67
68 if ((!src_file.file->private_data) || (!dst_file->private_data)) {
69 rc = -EBADF;
70 cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n");
71 goto out_fput;
72 }
73
74 rc = -EXDEV;
75 smb_file_target = dst_file->private_data;
76 smb_file_src = src_file.file->private_data;
77 src_tcon = tlink_tcon(smb_file_src->tlink);
78 target_tcon = tlink_tcon(smb_file_target->tlink);
79
80 /* check if source and target are on same tree connection */
81 if (src_tcon != target_tcon) {
82 cifs_dbg(VFS, "file copy src and target on different volume\n");
83 goto out_fput;
84 }
85
86 src_inode = src_file.file->f_dentry->d_inode;
87
88 /*
89 * Note: cifs case is easier than btrfs since server responsible for
90 * checks for proper open modes and file type and if it wants
91 * server could even support copy of range where source = target
92 */
93
94 /* so we do not deadlock racing two ioctls on same files */
95 if (target_inode < src_inode) {
96 mutex_lock_nested(&target_inode->i_mutex, I_MUTEX_PARENT);
97 mutex_lock_nested(&src_inode->i_mutex, I_MUTEX_CHILD);
98 } else {
99 mutex_lock_nested(&src_inode->i_mutex, I_MUTEX_PARENT);
100 mutex_lock_nested(&target_inode->i_mutex, I_MUTEX_CHILD);
101 }
102
103 /* determine range to clone */
104 rc = -EINVAL;
105 if (off + len > src_inode->i_size || off + len < off)
106 goto out_unlock;
107 if (len == 0)
108 len = src_inode->i_size - off;
109
110 cifs_dbg(FYI, "about to flush pages\n");
111 /* should we flush first and last page first */
112 truncate_inode_pages_range(&target_inode->i_data, destoff,
113 PAGE_CACHE_ALIGN(destoff + len)-1);
114
115 if (target_tcon->ses->server->ops->clone_range)
116 rc = target_tcon->ses->server->ops->clone_range(xid,
117 smb_file_src, smb_file_target, off, len, destoff);
118
119 /* force revalidate of size and timestamps of target file now
120 that target is updated on the server */
121 CIFS_I(target_inode)->time = 0;
122out_unlock:
123 /* although unlocking in the reverse order from locking is not
124 strictly necessary here it is a little cleaner to be consistent */
125 if (target_inode < src_inode) {
126 mutex_unlock(&src_inode->i_mutex);
127 mutex_unlock(&target_inode->i_mutex);
128 } else {
129 mutex_unlock(&target_inode->i_mutex);
130 mutex_unlock(&src_inode->i_mutex);
131 }
132out_fput:
133 fdput(src_file);
134out_drop_write:
135 mnt_drop_write_file(dst_file);
136 return rc;
137}
138
31long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) 139long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
32{ 140{
33 struct inode *inode = file_inode(filep); 141 struct inode *inode = file_inode(filep);
@@ -105,6 +213,9 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
105 cifs_dbg(FYI, "set compress flag rc %d\n", rc); 213 cifs_dbg(FYI, "set compress flag rc %d\n", rc);
106 } 214 }
107 break; 215 break;
216 case BTRFS_IOC_CLONE:
217 rc = cifs_ioctl_clone(xid, filep, arg, 0, 0, 0);
218 break;
108 default: 219 default:
109 cifs_dbg(FYI, "unsupported ioctl\n"); 220 cifs_dbg(FYI, "unsupported ioctl\n");
110 break; 221 break;
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 651a5279607b..049884552e76 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -51,7 +51,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
51 {ERRnoaccess, -EACCES}, 51 {ERRnoaccess, -EACCES},
52 {ERRbadfid, -EBADF}, 52 {ERRbadfid, -EBADF},
53 {ERRbadmcb, -EIO}, 53 {ERRbadmcb, -EIO},
54 {ERRnomem, -ENOMEM}, 54 {ERRnomem, -EREMOTEIO},
55 {ERRbadmem, -EFAULT}, 55 {ERRbadmem, -EFAULT},
56 {ERRbadenv, -EFAULT}, 56 {ERRbadenv, -EFAULT},
57 {ERRbadformat, -EINVAL}, 57 {ERRbadformat, -EINVAL},
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 53a75f3d0179..5940ecabbe6a 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -134,22 +134,6 @@ out:
134 dput(dentry); 134 dput(dentry);
135} 135}
136 136
137/*
138 * Is it possible that this directory might turn out to be a DFS referral
139 * once we go to try and use it?
140 */
141static bool
142cifs_dfs_is_possible(struct cifs_sb_info *cifs_sb)
143{
144#ifdef CONFIG_CIFS_DFS_UPCALL
145 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
146
147 if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
148 return true;
149#endif
150 return false;
151}
152
153static void 137static void
154cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) 138cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
155{ 139{
@@ -159,27 +143,19 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
159 if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { 143 if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
160 fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; 144 fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
161 fattr->cf_dtype = DT_DIR; 145 fattr->cf_dtype = DT_DIR;
162 /*
163 * Windows CIFS servers generally make DFS referrals look
164 * like directories in FIND_* responses with the reparse
165 * attribute flag also set (since DFS junctions are
166 * reparse points). We must revalidate at least these
167 * directory inodes before trying to use them (if
168 * they are DFS we will get PATH_NOT_COVERED back
169 * when queried directly and can then try to connect
170 * to the DFS target)
171 */
172 if (cifs_dfs_is_possible(cifs_sb) &&
173 (fattr->cf_cifsattrs & ATTR_REPARSE))
174 fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
175 } else if (fattr->cf_cifsattrs & ATTR_REPARSE) {
176 fattr->cf_mode = S_IFLNK;
177 fattr->cf_dtype = DT_LNK;
178 } else { 146 } else {
179 fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode; 147 fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
180 fattr->cf_dtype = DT_REG; 148 fattr->cf_dtype = DT_REG;
181 } 149 }
182 150
151 /*
152 * We need to revalidate it further to make a decision about whether it
153 * is a symbolic link, DFS referral or a reparse point with a direct
154 * access like junctions, deduplicated files, NFS symlinks.
155 */
156 if (fattr->cf_cifsattrs & ATTR_REPARSE)
157 fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
158
183 /* non-unix readdir doesn't provide nlink */ 159 /* non-unix readdir doesn't provide nlink */
184 fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK; 160 fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
185 161
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 384cffe42850..5f5ba0dc2ee1 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -534,10 +534,12 @@ cifs_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
534static int 534static int
535cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, 535cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
536 struct cifs_sb_info *cifs_sb, const char *full_path, 536 struct cifs_sb_info *cifs_sb, const char *full_path,
537 FILE_ALL_INFO *data, bool *adjustTZ) 537 FILE_ALL_INFO *data, bool *adjustTZ, bool *symlink)
538{ 538{
539 int rc; 539 int rc;
540 540
541 *symlink = false;
542
541 /* could do find first instead but this returns more info */ 543 /* could do find first instead but this returns more info */
542 rc = CIFSSMBQPathInfo(xid, tcon, full_path, data, 0 /* not legacy */, 544 rc = CIFSSMBQPathInfo(xid, tcon, full_path, data, 0 /* not legacy */,
543 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 545 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
@@ -554,6 +556,23 @@ cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
554 CIFS_MOUNT_MAP_SPECIAL_CHR); 556 CIFS_MOUNT_MAP_SPECIAL_CHR);
555 *adjustTZ = true; 557 *adjustTZ = true;
556 } 558 }
559
560 if (!rc && (le32_to_cpu(data->Attributes) & ATTR_REPARSE)) {
561 int tmprc;
562 int oplock = 0;
563 __u16 netfid;
564
565 /* Need to check if this is a symbolic link or not */
566 tmprc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
567 FILE_READ_ATTRIBUTES, 0, &netfid, &oplock,
568 NULL, cifs_sb->local_nls,
569 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
570 if (tmprc == -EOPNOTSUPP)
571 *symlink = true;
572 else
573 CIFSSMBClose(xid, tcon, netfid);
574 }
575
557 return rc; 576 return rc;
558} 577}
559 578
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 78ff88c467b9..84c012a6aba0 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -123,12 +123,13 @@ move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src)
123int 123int
124smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, 124smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
125 struct cifs_sb_info *cifs_sb, const char *full_path, 125 struct cifs_sb_info *cifs_sb, const char *full_path,
126 FILE_ALL_INFO *data, bool *adjust_tz) 126 FILE_ALL_INFO *data, bool *adjust_tz, bool *symlink)
127{ 127{
128 int rc; 128 int rc;
129 struct smb2_file_all_info *smb2_data; 129 struct smb2_file_all_info *smb2_data;
130 130
131 *adjust_tz = false; 131 *adjust_tz = false;
132 *symlink = false;
132 133
133 smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2, 134 smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2,
134 GFP_KERNEL); 135 GFP_KERNEL);
@@ -136,9 +137,16 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
136 return -ENOMEM; 137 return -ENOMEM;
137 138
138 rc = smb2_open_op_close(xid, tcon, cifs_sb, full_path, 139 rc = smb2_open_op_close(xid, tcon, cifs_sb, full_path,
139 FILE_READ_ATTRIBUTES, FILE_OPEN, 140 FILE_READ_ATTRIBUTES, FILE_OPEN, 0,
140 OPEN_REPARSE_POINT, smb2_data, 141 smb2_data, SMB2_OP_QUERY_INFO);
141 SMB2_OP_QUERY_INFO); 142 if (rc == -EOPNOTSUPP) {
143 *symlink = true;
144 /* Failed on a symbolic link - query a reparse point info */
145 rc = smb2_open_op_close(xid, tcon, cifs_sb, full_path,
146 FILE_READ_ATTRIBUTES, FILE_OPEN,
147 OPEN_REPARSE_POINT, smb2_data,
148 SMB2_OP_QUERY_INFO);
149 }
142 if (rc) 150 if (rc)
143 goto out; 151 goto out;
144 152
diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c
index 7c2f45c06fc2..94bd4fbb13d3 100644
--- a/fs/cifs/smb2maperror.c
+++ b/fs/cifs/smb2maperror.c
@@ -306,7 +306,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
306 {STATUS_NONEXISTENT_SECTOR, -EIO, "STATUS_NONEXISTENT_SECTOR"}, 306 {STATUS_NONEXISTENT_SECTOR, -EIO, "STATUS_NONEXISTENT_SECTOR"},
307 {STATUS_MORE_PROCESSING_REQUIRED, -EIO, 307 {STATUS_MORE_PROCESSING_REQUIRED, -EIO,
308 "STATUS_MORE_PROCESSING_REQUIRED"}, 308 "STATUS_MORE_PROCESSING_REQUIRED"},
309 {STATUS_NO_MEMORY, -ENOMEM, "STATUS_NO_MEMORY"}, 309 {STATUS_NO_MEMORY, -EREMOTEIO, "STATUS_NO_MEMORY"},
310 {STATUS_CONFLICTING_ADDRESSES, -EADDRINUSE, 310 {STATUS_CONFLICTING_ADDRESSES, -EADDRINUSE,
311 "STATUS_CONFLICTING_ADDRESSES"}, 311 "STATUS_CONFLICTING_ADDRESSES"},
312 {STATUS_NOT_MAPPED_VIEW, -EIO, "STATUS_NOT_MAPPED_VIEW"}, 312 {STATUS_NOT_MAPPED_VIEW, -EIO, "STATUS_NOT_MAPPED_VIEW"},
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index c571be8cb76e..11dde4b24f8a 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -494,6 +494,85 @@ smb2_close_file(const unsigned int xid, struct cifs_tcon *tcon,
494} 494}
495 495
496static int 496static int
497SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon,
498 u64 persistent_fid, u64 volatile_fid,
499 struct copychunk_ioctl *pcchunk)
500{
501 int rc;
502 unsigned int ret_data_len;
503 struct resume_key_req *res_key;
504
505 rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid,
506 FSCTL_SRV_REQUEST_RESUME_KEY, true /* is_fsctl */,
507 NULL, 0 /* no input */,
508 (char **)&res_key, &ret_data_len);
509
510 if (rc) {
511 cifs_dbg(VFS, "refcpy ioctl error %d getting resume key\n", rc);
512 goto req_res_key_exit;
513 }
514 if (ret_data_len < sizeof(struct resume_key_req)) {
515 cifs_dbg(VFS, "Invalid refcopy resume key length\n");
516 rc = -EINVAL;
517 goto req_res_key_exit;
518 }
519 memcpy(pcchunk->SourceKey, res_key->ResumeKey, COPY_CHUNK_RES_KEY_SIZE);
520
521req_res_key_exit:
522 kfree(res_key);
523 return rc;
524}
525
526static int
527smb2_clone_range(const unsigned int xid,
528 struct cifsFileInfo *srcfile,
529 struct cifsFileInfo *trgtfile, u64 src_off,
530 u64 len, u64 dest_off)
531{
532 int rc;
533 unsigned int ret_data_len;
534 struct copychunk_ioctl *pcchunk;
535 char *retbuf = NULL;
536
537 pcchunk = kmalloc(sizeof(struct copychunk_ioctl), GFP_KERNEL);
538
539 if (pcchunk == NULL)
540 return -ENOMEM;
541
542 cifs_dbg(FYI, "in smb2_clone_range - about to call request res key\n");
543 /* Request a key from the server to identify the source of the copy */
544 rc = SMB2_request_res_key(xid, tlink_tcon(srcfile->tlink),
545 srcfile->fid.persistent_fid,
546 srcfile->fid.volatile_fid, pcchunk);
547
548 /* Note: request_res_key sets res_key null only if rc !=0 */
549 if (rc)
550 return rc;
551
552 /* For now array only one chunk long, will make more flexible later */
553 pcchunk->ChunkCount = __constant_cpu_to_le32(1);
554 pcchunk->Reserved = 0;
555 pcchunk->SourceOffset = cpu_to_le64(src_off);
556 pcchunk->TargetOffset = cpu_to_le64(dest_off);
557 pcchunk->Length = cpu_to_le32(len);
558 pcchunk->Reserved2 = 0;
559
560 /* Request that server copy to target from src file identified by key */
561 rc = SMB2_ioctl(xid, tlink_tcon(trgtfile->tlink),
562 trgtfile->fid.persistent_fid,
563 trgtfile->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE,
564 true /* is_fsctl */, (char *)pcchunk,
565 sizeof(struct copychunk_ioctl), &retbuf, &ret_data_len);
566
567 /* BB need to special case rc = EINVAL to alter chunk size */
568
569 cifs_dbg(FYI, "rc %d data length out %d\n", rc, ret_data_len);
570
571 kfree(pcchunk);
572 return rc;
573}
574
575static int
497smb2_flush_file(const unsigned int xid, struct cifs_tcon *tcon, 576smb2_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
498 struct cifs_fid *fid) 577 struct cifs_fid *fid)
499{ 578{
@@ -1017,6 +1096,7 @@ struct smb_version_operations smb20_operations = {
1017 .set_oplock_level = smb2_set_oplock_level, 1096 .set_oplock_level = smb2_set_oplock_level,
1018 .create_lease_buf = smb2_create_lease_buf, 1097 .create_lease_buf = smb2_create_lease_buf,
1019 .parse_lease_buf = smb2_parse_lease_buf, 1098 .parse_lease_buf = smb2_parse_lease_buf,
1099 .clone_range = smb2_clone_range,
1020}; 1100};
1021 1101
1022struct smb_version_operations smb21_operations = { 1102struct smb_version_operations smb21_operations = {
@@ -1090,6 +1170,7 @@ struct smb_version_operations smb21_operations = {
1090 .set_oplock_level = smb21_set_oplock_level, 1170 .set_oplock_level = smb21_set_oplock_level,
1091 .create_lease_buf = smb2_create_lease_buf, 1171 .create_lease_buf = smb2_create_lease_buf,
1092 .parse_lease_buf = smb2_parse_lease_buf, 1172 .parse_lease_buf = smb2_parse_lease_buf,
1173 .clone_range = smb2_clone_range,
1093}; 1174};
1094 1175
1095struct smb_version_operations smb30_operations = { 1176struct smb_version_operations smb30_operations = {
@@ -1165,6 +1246,7 @@ struct smb_version_operations smb30_operations = {
1165 .set_oplock_level = smb3_set_oplock_level, 1246 .set_oplock_level = smb3_set_oplock_level,
1166 .create_lease_buf = smb3_create_lease_buf, 1247 .create_lease_buf = smb3_create_lease_buf,
1167 .parse_lease_buf = smb3_parse_lease_buf, 1248 .parse_lease_buf = smb3_parse_lease_buf,
1249 .clone_range = smb2_clone_range,
1168}; 1250};
1169 1251
1170struct smb_version_values smb20_values = { 1252struct smb_version_values smb20_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 8ab05b0d6778..d65270c290a1 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -630,6 +630,8 @@ ssetup_ntlmssp_authenticate:
630 goto ssetup_exit; 630 goto ssetup_exit;
631 631
632 ses->session_flags = le16_to_cpu(rsp->SessionFlags); 632 ses->session_flags = le16_to_cpu(rsp->SessionFlags);
633 if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA)
634 cifs_dbg(VFS, "SMB3 encryption not supported yet\n");
633ssetup_exit: 635ssetup_exit:
634 free_rsp_buf(resp_buftype, rsp); 636 free_rsp_buf(resp_buftype, rsp);
635 637
@@ -717,6 +719,14 @@ static inline void cifs_stats_fail_inc(struct cifs_tcon *tcon, uint16_t code)
717 719
718#define MAX_SHARENAME_LENGTH (255 /* server */ + 80 /* share */ + 1 /* NULL */) 720#define MAX_SHARENAME_LENGTH (255 /* server */ + 80 /* share */ + 1 /* NULL */)
719 721
722/* These are similar values to what Windows uses */
723static inline void init_copy_chunk_defaults(struct cifs_tcon *tcon)
724{
725 tcon->max_chunks = 256;
726 tcon->max_bytes_chunk = 1048576;
727 tcon->max_bytes_copy = 16777216;
728}
729
720int 730int
721SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, 731SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
722 struct cifs_tcon *tcon, const struct nls_table *cp) 732 struct cifs_tcon *tcon, const struct nls_table *cp)
@@ -818,7 +828,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
818 if ((rsp->Capabilities & SMB2_SHARE_CAP_DFS) && 828 if ((rsp->Capabilities & SMB2_SHARE_CAP_DFS) &&
819 ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0)) 829 ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0))
820 cifs_dbg(VFS, "DFS capability contradicts DFS flag\n"); 830 cifs_dbg(VFS, "DFS capability contradicts DFS flag\n");
821 831 init_copy_chunk_defaults(tcon);
822tcon_exit: 832tcon_exit:
823 free_rsp_buf(resp_buftype, rsp); 833 free_rsp_buf(resp_buftype, rsp);
824 kfree(unc_path); 834 kfree(unc_path);
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 6183b1b7550f..f88320bbb477 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -122,6 +122,23 @@ struct smb2_pdu {
122 __le16 StructureSize2; /* size of wct area (varies, request specific) */ 122 __le16 StructureSize2; /* size of wct area (varies, request specific) */
123} __packed; 123} __packed;
124 124
125struct smb2_transform_hdr {
126 __be32 smb2_buf_length; /* big endian on wire */
127 /* length is only two or three bytes - with
128 one or two byte type preceding it that MBZ */
129 __u8 ProtocolId[4]; /* 0xFD 'S' 'M' 'B' */
130 __u8 Signature[16];
131 __u8 Nonce[11];
132 __u8 Reserved[5];
133 __le32 OriginalMessageSize;
134 __u16 Reserved1;
135 __le16 EncryptionAlgorithm;
136 __u64 SessionId;
137} __packed;
138
139/* Encryption Algorithms */
140#define SMB2_ENCRYPTION_AES128_CCM __constant_cpu_to_le16(0x0001)
141
125/* 142/*
126 * SMB2 flag definitions 143 * SMB2 flag definitions
127 */ 144 */
@@ -237,6 +254,7 @@ struct smb2_sess_setup_req {
237/* Currently defined SessionFlags */ 254/* Currently defined SessionFlags */
238#define SMB2_SESSION_FLAG_IS_GUEST 0x0001 255#define SMB2_SESSION_FLAG_IS_GUEST 0x0001
239#define SMB2_SESSION_FLAG_IS_NULL 0x0002 256#define SMB2_SESSION_FLAG_IS_NULL 0x0002
257#define SMB2_SESSION_FLAG_ENCRYPT_DATA 0x0004
240struct smb2_sess_setup_rsp { 258struct smb2_sess_setup_rsp {
241 struct smb2_hdr hdr; 259 struct smb2_hdr hdr;
242 __le16 StructureSize; /* Must be 9 */ 260 __le16 StructureSize; /* Must be 9 */
@@ -534,9 +552,16 @@ struct create_durable {
534 } Data; 552 } Data;
535} __packed; 553} __packed;
536 554
555#define COPY_CHUNK_RES_KEY_SIZE 24
556struct resume_key_req {
557 char ResumeKey[COPY_CHUNK_RES_KEY_SIZE];
558 __le32 ContextLength; /* MBZ */
559 char Context[0]; /* ignored, Windows sets to 4 bytes of zero */
560} __packed;
561
537/* this goes in the ioctl buffer when doing a copychunk request */ 562/* this goes in the ioctl buffer when doing a copychunk request */
538struct copychunk_ioctl { 563struct copychunk_ioctl {
539 char SourceKey[24]; 564 char SourceKey[COPY_CHUNK_RES_KEY_SIZE];
540 __le32 ChunkCount; /* we are only sending 1 */ 565 __le32 ChunkCount; /* we are only sending 1 */
541 __le32 Reserved; 566 __le32 Reserved;
542 /* array will only be one chunk long for us */ 567 /* array will only be one chunk long for us */
@@ -546,6 +571,12 @@ struct copychunk_ioctl {
546 __u32 Reserved2; 571 __u32 Reserved2;
547} __packed; 572} __packed;
548 573
574struct copychunk_ioctl_rsp {
575 __le32 ChunksWritten;
576 __le32 ChunkBytesWritten;
577 __le32 TotalBytesWritten;
578} __packed;
579
549/* Response and Request are the same format */ 580/* Response and Request are the same format */
550struct validate_negotiate_info { 581struct validate_negotiate_info {
551 __le32 Capabilities; 582 __le32 Capabilities;
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 313813e4c19b..b4eea105b08c 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -61,7 +61,7 @@ extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
61extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, 61extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
62 struct cifs_sb_info *cifs_sb, 62 struct cifs_sb_info *cifs_sb,
63 const char *full_path, FILE_ALL_INFO *data, 63 const char *full_path, FILE_ALL_INFO *data,
64 bool *adjust_tz); 64 bool *adjust_tz, bool *symlink);
65extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon, 65extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
66 const char *full_path, __u64 size, 66 const char *full_path, __u64 size,
67 struct cifs_sb_info *cifs_sb, bool set_alloc); 67 struct cifs_sb_info *cifs_sb, bool set_alloc);