aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-07-13 14:20:49 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-13 14:20:49 -0400
commitf1c410885288e0042099960ee9e0c260dfea4cfb (patch)
treefeaffacdd4f7a6e98ecb0996c0f447f6d01387c3 /fs
parent9903883f1dd6e86f286b7bfa6e4b423f98c1cd9e (diff)
parent689c3db4d57a73bee6c5ad7797fce7b54d32a87c (diff)
Merge branch 'for-linus' of git://git.samba.org/sfrench/cifs-2.6
Pull cifs fixes from Steve French: "Fixes for 4 cifs bugs, including a reconnect problem, a problem parsing responses to SMB2 open request, and setting nlink incorrectly to some servers which don't report it properly on the wire. Also improves data integrity on reconnect with series from Pavel which adds durable handle support for SMB2." * 'for-linus' of git://git.samba.org/sfrench/cifs-2.6: CIFS: Fix a deadlock when a file is reopened CIFS: Reopen the file if reconnect durable handle failed [CIFS] Fix minor endian error in durable handle patch series CIFS: Reconnect durable handles for SMB2 CIFS: Make SMB2_open use cifs_open_parms struct CIFS: Introduce cifs_open_parms struct CIFS: Request durable open for SMB2 opens CIFS: Simplify SMB2 create context handling CIFS: Simplify SMB2_open code path CIFS: Respect create_options in smb2_open_file CIFS: Fix lease context buffer parsing [CIFS] use sensible file nlink values if unprovided Limit allocation of crypto mechanisms to dialect which requires
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/cifsencrypt.c195
-rw-r--r--fs/cifs/cifsglob.h17
-rw-r--r--fs/cifs/cifsproto.h1
-rw-r--r--fs/cifs/connect.c6
-rw-r--r--fs/cifs/dir.c14
-rw-r--r--fs/cifs/file.c54
-rw-r--r--fs/cifs/inode.c5
-rw-r--r--fs/cifs/smb1ops.c29
-rw-r--r--fs/cifs/smb2file.c24
-rw-r--r--fs/cifs/smb2inode.c57
-rw-r--r--fs/cifs/smb2ops.c54
-rw-r--r--fs/cifs/smb2pdu.c220
-rw-r--r--fs/cifs/smb2pdu.h14
-rw-r--r--fs/cifs/smb2proto.h16
-rw-r--r--fs/cifs/smb2transport.c90
15 files changed, 515 insertions, 281 deletions
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 3d8bf941d126..45e57cc38200 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * fs/cifs/cifsencrypt.c 2 * fs/cifs/cifsencrypt.c
3 * 3 *
4 * Copyright (C) International Business Machines Corp., 2005,2006 4 * Copyright (C) International Business Machines Corp., 2005,2013
5 * Author(s): Steve French (sfrench@us.ibm.com) 5 * Author(s): Steve French (sfrench@us.ibm.com)
6 * 6 *
7 * This library is free software; you can redistribute it and/or modify 7 * This library is free software; you can redistribute it and/or modify
@@ -31,6 +31,36 @@
31#include <linux/random.h> 31#include <linux/random.h>
32#include <linux/highmem.h> 32#include <linux/highmem.h>
33 33
34static int
35cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
36{
37 int rc;
38 unsigned int size;
39
40 if (server->secmech.sdescmd5 != NULL)
41 return 0; /* already allocated */
42
43 server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
44 if (IS_ERR(server->secmech.md5)) {
45 cifs_dbg(VFS, "could not allocate crypto md5\n");
46 return PTR_ERR(server->secmech.md5);
47 }
48
49 size = sizeof(struct shash_desc) +
50 crypto_shash_descsize(server->secmech.md5);
51 server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
52 if (!server->secmech.sdescmd5) {
53 rc = -ENOMEM;
54 crypto_free_shash(server->secmech.md5);
55 server->secmech.md5 = NULL;
56 return rc;
57 }
58 server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
59 server->secmech.sdescmd5->shash.flags = 0x0;
60
61 return 0;
62}
63
34/* 64/*
35 * Calculate and return the CIFS signature based on the mac key and SMB PDU. 65 * Calculate and return the CIFS signature based on the mac key and SMB PDU.
36 * The 16 byte signature must be allocated by the caller. Note we only use the 66 * The 16 byte signature must be allocated by the caller. Note we only use the
@@ -50,8 +80,11 @@ static int cifs_calc_signature(struct smb_rqst *rqst,
50 return -EINVAL; 80 return -EINVAL;
51 81
52 if (!server->secmech.sdescmd5) { 82 if (!server->secmech.sdescmd5) {
53 cifs_dbg(VFS, "%s: Can't generate signature\n", __func__); 83 rc = cifs_crypto_shash_md5_allocate(server);
54 return -1; 84 if (rc) {
85 cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__);
86 return -1;
87 }
55 } 88 }
56 89
57 rc = crypto_shash_init(&server->secmech.sdescmd5->shash); 90 rc = crypto_shash_init(&server->secmech.sdescmd5->shash);
@@ -556,6 +589,33 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
556 return rc; 589 return rc;
557} 590}
558 591
592static int crypto_hmacmd5_alloc(struct TCP_Server_Info *server)
593{
594 unsigned int size;
595
596 /* check if already allocated */
597 if (server->secmech.sdeschmacmd5)
598 return 0;
599
600 server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
601 if (IS_ERR(server->secmech.hmacmd5)) {
602 cifs_dbg(VFS, "could not allocate crypto hmacmd5\n");
603 return PTR_ERR(server->secmech.hmacmd5);
604 }
605
606 size = sizeof(struct shash_desc) +
607 crypto_shash_descsize(server->secmech.hmacmd5);
608 server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
609 if (!server->secmech.sdeschmacmd5) {
610 crypto_free_shash(server->secmech.hmacmd5);
611 server->secmech.hmacmd5 = NULL;
612 return -ENOMEM;
613 }
614 server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
615 server->secmech.sdeschmacmd5->shash.flags = 0x0;
616
617 return 0;
618}
559 619
560int 620int
561setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) 621setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
@@ -606,6 +666,12 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
606 666
607 memcpy(ses->auth_key.response + baselen, tiblob, tilen); 667 memcpy(ses->auth_key.response + baselen, tiblob, tilen);
608 668
669 rc = crypto_hmacmd5_alloc(ses->server);
670 if (rc) {
671 cifs_dbg(VFS, "could not crypto alloc hmacmd5 rc %d\n", rc);
672 goto setup_ntlmv2_rsp_ret;
673 }
674
609 /* calculate ntlmv2_hash */ 675 /* calculate ntlmv2_hash */
610 rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp); 676 rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp);
611 if (rc) { 677 if (rc) {
@@ -705,123 +771,32 @@ calc_seckey(struct cifs_ses *ses)
705void 771void
706cifs_crypto_shash_release(struct TCP_Server_Info *server) 772cifs_crypto_shash_release(struct TCP_Server_Info *server)
707{ 773{
708 if (server->secmech.cmacaes) 774 if (server->secmech.cmacaes) {
709 crypto_free_shash(server->secmech.cmacaes); 775 crypto_free_shash(server->secmech.cmacaes);
776 server->secmech.cmacaes = NULL;
777 }
710 778
711 if (server->secmech.hmacsha256) 779 if (server->secmech.hmacsha256) {
712 crypto_free_shash(server->secmech.hmacsha256); 780 crypto_free_shash(server->secmech.hmacsha256);
781 server->secmech.hmacsha256 = NULL;
782 }
713 783
714 if (server->secmech.md5) 784 if (server->secmech.md5) {
715 crypto_free_shash(server->secmech.md5); 785 crypto_free_shash(server->secmech.md5);
786 server->secmech.md5 = NULL;
787 }
716 788
717 if (server->secmech.hmacmd5) 789 if (server->secmech.hmacmd5) {
718 crypto_free_shash(server->secmech.hmacmd5); 790 crypto_free_shash(server->secmech.hmacmd5);
791 server->secmech.hmacmd5 = NULL;
792 }
719 793
720 kfree(server->secmech.sdesccmacaes); 794 kfree(server->secmech.sdesccmacaes);
721 795 server->secmech.sdesccmacaes = NULL;
722 kfree(server->secmech.sdeschmacsha256); 796 kfree(server->secmech.sdeschmacsha256);
723 797 server->secmech.sdeschmacsha256 = NULL;
724 kfree(server->secmech.sdeschmacmd5); 798 kfree(server->secmech.sdeschmacmd5);
725 799 server->secmech.sdeschmacmd5 = NULL;
726 kfree(server->secmech.sdescmd5); 800 kfree(server->secmech.sdescmd5);
727} 801 server->secmech.sdescmd5 = NULL;
728
729int
730cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
731{
732 int rc;
733 unsigned int size;
734
735 server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
736 if (IS_ERR(server->secmech.hmacmd5)) {
737 cifs_dbg(VFS, "could not allocate crypto hmacmd5\n");
738 return PTR_ERR(server->secmech.hmacmd5);
739 }
740
741 server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
742 if (IS_ERR(server->secmech.md5)) {
743 cifs_dbg(VFS, "could not allocate crypto md5\n");
744 rc = PTR_ERR(server->secmech.md5);
745 goto crypto_allocate_md5_fail;
746 }
747
748 server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
749 if (IS_ERR(server->secmech.hmacsha256)) {
750 cifs_dbg(VFS, "could not allocate crypto hmacsha256\n");
751 rc = PTR_ERR(server->secmech.hmacsha256);
752 goto crypto_allocate_hmacsha256_fail;
753 }
754
755 server->secmech.cmacaes = crypto_alloc_shash("cmac(aes)", 0, 0);
756 if (IS_ERR(server->secmech.cmacaes)) {
757 cifs_dbg(VFS, "could not allocate crypto cmac-aes");
758 rc = PTR_ERR(server->secmech.cmacaes);
759 goto crypto_allocate_cmacaes_fail;
760 }
761
762 size = sizeof(struct shash_desc) +
763 crypto_shash_descsize(server->secmech.hmacmd5);
764 server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
765 if (!server->secmech.sdeschmacmd5) {
766 rc = -ENOMEM;
767 goto crypto_allocate_hmacmd5_sdesc_fail;
768 }
769 server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
770 server->secmech.sdeschmacmd5->shash.flags = 0x0;
771
772 size = sizeof(struct shash_desc) +
773 crypto_shash_descsize(server->secmech.md5);
774 server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
775 if (!server->secmech.sdescmd5) {
776 rc = -ENOMEM;
777 goto crypto_allocate_md5_sdesc_fail;
778 }
779 server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
780 server->secmech.sdescmd5->shash.flags = 0x0;
781
782 size = sizeof(struct shash_desc) +
783 crypto_shash_descsize(server->secmech.hmacsha256);
784 server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL);
785 if (!server->secmech.sdeschmacsha256) {
786 rc = -ENOMEM;
787 goto crypto_allocate_hmacsha256_sdesc_fail;
788 }
789 server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
790 server->secmech.sdeschmacsha256->shash.flags = 0x0;
791
792 size = sizeof(struct shash_desc) +
793 crypto_shash_descsize(server->secmech.cmacaes);
794 server->secmech.sdesccmacaes = kmalloc(size, GFP_KERNEL);
795 if (!server->secmech.sdesccmacaes) {
796 cifs_dbg(VFS, "%s: Can't alloc cmacaes\n", __func__);
797 rc = -ENOMEM;
798 goto crypto_allocate_cmacaes_sdesc_fail;
799 }
800 server->secmech.sdesccmacaes->shash.tfm = server->secmech.cmacaes;
801 server->secmech.sdesccmacaes->shash.flags = 0x0;
802
803 return 0;
804
805crypto_allocate_cmacaes_sdesc_fail:
806 kfree(server->secmech.sdeschmacsha256);
807
808crypto_allocate_hmacsha256_sdesc_fail:
809 kfree(server->secmech.sdescmd5);
810
811crypto_allocate_md5_sdesc_fail:
812 kfree(server->secmech.sdeschmacmd5);
813
814crypto_allocate_hmacmd5_sdesc_fail:
815 crypto_free_shash(server->secmech.cmacaes);
816
817crypto_allocate_cmacaes_fail:
818 crypto_free_shash(server->secmech.hmacsha256);
819
820crypto_allocate_hmacsha256_fail:
821 crypto_free_shash(server->secmech.md5);
822
823crypto_allocate_md5_fail:
824 crypto_free_shash(server->secmech.hmacmd5);
825
826 return rc;
827} 802}
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index e66b08882548..1fdc37041057 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -194,6 +194,7 @@ struct cifs_writedata;
194struct cifs_io_parms; 194struct cifs_io_parms;
195struct cifs_search_info; 195struct cifs_search_info;
196struct cifsInodeInfo; 196struct cifsInodeInfo;
197struct cifs_open_parms;
197 198
198struct smb_version_operations { 199struct smb_version_operations {
199 int (*send_cancel)(struct TCP_Server_Info *, void *, 200 int (*send_cancel)(struct TCP_Server_Info *, void *,
@@ -307,9 +308,8 @@ struct smb_version_operations {
307 const char *, const char *, 308 const char *, const char *,
308 struct cifs_sb_info *); 309 struct cifs_sb_info *);
309 /* open a file for non-posix mounts */ 310 /* open a file for non-posix mounts */
310 int (*open)(const unsigned int, struct cifs_tcon *, const char *, int, 311 int (*open)(const unsigned int, struct cifs_open_parms *,
311 int, int, struct cifs_fid *, __u32 *, FILE_ALL_INFO *, 312 __u32 *, FILE_ALL_INFO *);
312 struct cifs_sb_info *);
313 /* set fid protocol-specific info */ 313 /* set fid protocol-specific info */
314 void (*set_fid)(struct cifsFileInfo *, struct cifs_fid *, __u32); 314 void (*set_fid)(struct cifsFileInfo *, struct cifs_fid *, __u32);
315 /* close a file */ 315 /* close a file */
@@ -912,6 +912,17 @@ struct cifs_search_info {
912 bool smallBuf:1; /* so we know which buf_release function to call */ 912 bool smallBuf:1; /* so we know which buf_release function to call */
913}; 913};
914 914
915struct cifs_open_parms {
916 struct cifs_tcon *tcon;
917 struct cifs_sb_info *cifs_sb;
918 int disposition;
919 int desired_access;
920 int create_options;
921 const char *path;
922 struct cifs_fid *fid;
923 bool reconnect:1;
924};
925
915struct cifs_fid { 926struct cifs_fid {
916 __u16 netfid; 927 __u16 netfid;
917#ifdef CONFIG_CIFS_SMB2 928#ifdef CONFIG_CIFS_SMB2
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index c8ff018fae68..f7e584d047e2 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -433,7 +433,6 @@ extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *,
433 const struct nls_table *); 433 const struct nls_table *);
434extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *); 434extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *);
435extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *); 435extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
436extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *);
437extern void cifs_crypto_shash_release(struct TCP_Server_Info *); 436extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
438extern int calc_seckey(struct cifs_ses *); 437extern int calc_seckey(struct cifs_ses *);
439extern void generate_smb3signingkey(struct TCP_Server_Info *); 438extern void generate_smb3signingkey(struct TCP_Server_Info *);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index afcb8a1a33b7..fa68813396b5 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -2108,12 +2108,6 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
2108 goto out_err; 2108 goto out_err;
2109 } 2109 }
2110 2110
2111 rc = cifs_crypto_shash_allocate(tcp_ses);
2112 if (rc) {
2113 cifs_dbg(VFS, "could not setup hash structures rc %d\n", rc);
2114 goto out_err;
2115 }
2116
2117 tcp_ses->ops = volume_info->ops; 2111 tcp_ses->ops = volume_info->ops;
2118 tcp_ses->vals = volume_info->vals; 2112 tcp_ses->vals = volume_info->vals;
2119 cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns)); 2113 cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns));
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 5175aebf6737..d62ce0d48141 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -204,6 +204,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
204 struct inode *newinode = NULL; 204 struct inode *newinode = NULL;
205 int disposition; 205 int disposition;
206 struct TCP_Server_Info *server = tcon->ses->server; 206 struct TCP_Server_Info *server = tcon->ses->server;
207 struct cifs_open_parms oparms;
207 208
208 *oplock = 0; 209 *oplock = 0;
209 if (tcon->ses->server->oplocks) 210 if (tcon->ses->server->oplocks)
@@ -319,9 +320,16 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
319 if (backup_cred(cifs_sb)) 320 if (backup_cred(cifs_sb))
320 create_options |= CREATE_OPEN_BACKUP_INTENT; 321 create_options |= CREATE_OPEN_BACKUP_INTENT;
321 322
322 rc = server->ops->open(xid, tcon, full_path, disposition, 323 oparms.tcon = tcon;
323 desired_access, create_options, fid, oplock, 324 oparms.cifs_sb = cifs_sb;
324 buf, cifs_sb); 325 oparms.desired_access = desired_access;
326 oparms.create_options = create_options;
327 oparms.disposition = disposition;
328 oparms.path = full_path;
329 oparms.fid = fid;
330 oparms.reconnect = false;
331
332 rc = server->ops->open(xid, &oparms, oplock, buf);
325 if (rc) { 333 if (rc) {
326 cifs_dbg(FYI, "cifs_create returned 0x%x\n", rc); 334 cifs_dbg(FYI, "cifs_create returned 0x%x\n", rc);
327 goto out; 335 goto out;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 91d8629e69a2..1e57f36ea1b2 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -183,6 +183,7 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
183 int create_options = CREATE_NOT_DIR; 183 int create_options = CREATE_NOT_DIR;
184 FILE_ALL_INFO *buf; 184 FILE_ALL_INFO *buf;
185 struct TCP_Server_Info *server = tcon->ses->server; 185 struct TCP_Server_Info *server = tcon->ses->server;
186 struct cifs_open_parms oparms;
186 187
187 if (!server->ops->open) 188 if (!server->ops->open)
188 return -ENOSYS; 189 return -ENOSYS;
@@ -224,9 +225,16 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
224 if (backup_cred(cifs_sb)) 225 if (backup_cred(cifs_sb))
225 create_options |= CREATE_OPEN_BACKUP_INTENT; 226 create_options |= CREATE_OPEN_BACKUP_INTENT;
226 227
227 rc = server->ops->open(xid, tcon, full_path, disposition, 228 oparms.tcon = tcon;
228 desired_access, create_options, fid, oplock, buf, 229 oparms.cifs_sb = cifs_sb;
229 cifs_sb); 230 oparms.desired_access = desired_access;
231 oparms.create_options = create_options;
232 oparms.disposition = disposition;
233 oparms.path = full_path;
234 oparms.fid = fid;
235 oparms.reconnect = false;
236
237 rc = server->ops->open(xid, &oparms, oplock, buf);
230 238
231 if (rc) 239 if (rc)
232 goto out; 240 goto out;
@@ -553,11 +561,10 @@ cifs_relock_file(struct cifsFileInfo *cfile)
553 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 561 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
554 int rc = 0; 562 int rc = 0;
555 563
556 /* we are going to update can_cache_brlcks here - need a write access */ 564 down_read(&cinode->lock_sem);
557 down_write(&cinode->lock_sem);
558 if (cinode->can_cache_brlcks) { 565 if (cinode->can_cache_brlcks) {
559 /* can cache locks - no need to push them */ 566 /* can cache locks - no need to relock */
560 up_write(&cinode->lock_sem); 567 up_read(&cinode->lock_sem);
561 return rc; 568 return rc;
562 } 569 }
563 570
@@ -568,7 +575,7 @@ cifs_relock_file(struct cifsFileInfo *cfile)
568 else 575 else
569 rc = tcon->ses->server->ops->push_mand_locks(cfile); 576 rc = tcon->ses->server->ops->push_mand_locks(cfile);
570 577
571 up_write(&cinode->lock_sem); 578 up_read(&cinode->lock_sem);
572 return rc; 579 return rc;
573} 580}
574 581
@@ -587,7 +594,7 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
587 int desired_access; 594 int desired_access;
588 int disposition = FILE_OPEN; 595 int disposition = FILE_OPEN;
589 int create_options = CREATE_NOT_DIR; 596 int create_options = CREATE_NOT_DIR;
590 struct cifs_fid fid; 597 struct cifs_open_parms oparms;
591 598
592 xid = get_xid(); 599 xid = get_xid();
593 mutex_lock(&cfile->fh_mutex); 600 mutex_lock(&cfile->fh_mutex);
@@ -637,7 +644,7 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
637 644
638 rc = cifs_posix_open(full_path, NULL, inode->i_sb, 645 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
639 cifs_sb->mnt_file_mode /* ignored */, 646 cifs_sb->mnt_file_mode /* ignored */,
640 oflags, &oplock, &fid.netfid, xid); 647 oflags, &oplock, &cfile->fid.netfid, xid);
641 if (rc == 0) { 648 if (rc == 0) {
642 cifs_dbg(FYI, "posix reopen succeeded\n"); 649 cifs_dbg(FYI, "posix reopen succeeded\n");
643 goto reopen_success; 650 goto reopen_success;
@@ -654,7 +661,16 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
654 create_options |= CREATE_OPEN_BACKUP_INTENT; 661 create_options |= CREATE_OPEN_BACKUP_INTENT;
655 662
656 if (server->ops->get_lease_key) 663 if (server->ops->get_lease_key)
657 server->ops->get_lease_key(inode, &fid); 664 server->ops->get_lease_key(inode, &cfile->fid);
665
666 oparms.tcon = tcon;
667 oparms.cifs_sb = cifs_sb;
668 oparms.desired_access = desired_access;
669 oparms.create_options = create_options;
670 oparms.disposition = disposition;
671 oparms.path = full_path;
672 oparms.fid = &cfile->fid;
673 oparms.reconnect = true;
658 674
659 /* 675 /*
660 * Can not refresh inode by passing in file_info buf to be returned by 676 * Can not refresh inode by passing in file_info buf to be returned by
@@ -663,9 +679,14 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
663 * version of file size can be stale. If we knew for sure that inode was 679 * version of file size can be stale. If we knew for sure that inode was
664 * not dirty locally we could do this. 680 * not dirty locally we could do this.
665 */ 681 */
666 rc = server->ops->open(xid, tcon, full_path, disposition, 682 rc = server->ops->open(xid, &oparms, &oplock, NULL);
667 desired_access, create_options, &fid, &oplock, 683 if (rc == -ENOENT && oparms.reconnect == false) {
668 NULL, cifs_sb); 684 /* durable handle timeout is expired - open the file again */
685 rc = server->ops->open(xid, &oparms, &oplock, NULL);
686 /* indicate that we need to relock the file */
687 oparms.reconnect = true;
688 }
689
669 if (rc) { 690 if (rc) {
670 mutex_unlock(&cfile->fh_mutex); 691 mutex_unlock(&cfile->fh_mutex);
671 cifs_dbg(FYI, "cifs_reopen returned 0x%x\n", rc); 692 cifs_dbg(FYI, "cifs_reopen returned 0x%x\n", rc);
@@ -696,8 +717,9 @@ reopen_success:
696 * to the server to get the new inode info. 717 * to the server to get the new inode info.
697 */ 718 */
698 719
699 server->ops->set_fid(cfile, &fid, oplock); 720 server->ops->set_fid(cfile, &cfile->fid, oplock);
700 cifs_relock_file(cfile); 721 if (oparms.reconnect)
722 cifs_relock_file(cfile);
701 723
702reopen_error_exit: 724reopen_error_exit:
703 kfree(full_path); 725 kfree(full_path);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 20efd81266c6..449b6cf09b09 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -558,6 +558,11 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
558 fattr->cf_mode &= ~(S_IWUGO); 558 fattr->cf_mode &= ~(S_IWUGO);
559 559
560 fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); 560 fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
561 if (fattr->cf_nlink < 1) {
562 cifs_dbg(1, "replacing bogus file nlink value %u\n",
563 fattr->cf_nlink);
564 fattr->cf_nlink = 1;
565 }
561 } 566 }
562 567
563 fattr->cf_uid = cifs_sb->mnt_uid; 568 fattr->cf_uid = cifs_sb->mnt_uid;
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index e813f04511d8..6457690731a2 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -674,20 +674,23 @@ cifs_mkdir_setinfo(struct inode *inode, const char *full_path,
674} 674}
675 675
676static int 676static int
677cifs_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path, 677cifs_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
678 int disposition, int desired_access, int create_options, 678 __u32 *oplock, FILE_ALL_INFO *buf)
679 struct cifs_fid *fid, __u32 *oplock, FILE_ALL_INFO *buf, 679{
680 struct cifs_sb_info *cifs_sb) 680 if (!(oparms->tcon->ses->capabilities & CAP_NT_SMBS))
681{ 681 return SMBLegacyOpen(xid, oparms->tcon, oparms->path,
682 if (!(tcon->ses->capabilities & CAP_NT_SMBS)) 682 oparms->disposition,
683 return SMBLegacyOpen(xid, tcon, path, disposition, 683 oparms->desired_access,
684 desired_access, create_options, 684 oparms->create_options,
685 &fid->netfid, oplock, buf, 685 &oparms->fid->netfid, oplock, buf,
686 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags 686 oparms->cifs_sb->local_nls,
687 oparms->cifs_sb->mnt_cifs_flags
687 & CIFS_MOUNT_MAP_SPECIAL_CHR); 688 & CIFS_MOUNT_MAP_SPECIAL_CHR);
688 return CIFSSMBOpen(xid, tcon, path, disposition, desired_access, 689 return CIFSSMBOpen(xid, oparms->tcon, oparms->path,
689 create_options, &fid->netfid, oplock, buf, 690 oparms->disposition, oparms->desired_access,
690 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 691 oparms->create_options, &oparms->fid->netfid, oplock,
692 buf, oparms->cifs_sb->local_nls,
693 oparms->cifs_sb->mnt_cifs_flags &
691 CIFS_MOUNT_MAP_SPECIAL_CHR); 694 CIFS_MOUNT_MAP_SPECIAL_CHR);
692} 695}
693 696
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index 5da1b55a2258..04a81a4142c3 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -40,7 +40,8 @@ smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
40 oplock &= 0xFF; 40 oplock &= 0xFF;
41 if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE) 41 if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE)
42 return; 42 return;
43 if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) { 43 if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE ||
44 oplock == SMB2_OPLOCK_LEVEL_BATCH) {
44 cinode->clientCanCacheAll = true; 45 cinode->clientCanCacheAll = true;
45 cinode->clientCanCacheRead = true; 46 cinode->clientCanCacheRead = true;
46 cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n", 47 cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n",
@@ -57,17 +58,16 @@ smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
57} 58}
58 59
59int 60int
60smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path, 61smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
61 int disposition, int desired_access, int create_options, 62 __u32 *oplock, FILE_ALL_INFO *buf)
62 struct cifs_fid *fid, __u32 *oplock, FILE_ALL_INFO *buf,
63 struct cifs_sb_info *cifs_sb)
64{ 63{
65 int rc; 64 int rc;
66 __le16 *smb2_path; 65 __le16 *smb2_path;
67 struct smb2_file_all_info *smb2_data = NULL; 66 struct smb2_file_all_info *smb2_data = NULL;
68 __u8 smb2_oplock[17]; 67 __u8 smb2_oplock[17];
68 struct cifs_fid *fid = oparms->fid;
69 69
70 smb2_path = cifs_convert_path_to_utf16(path, cifs_sb); 70 smb2_path = cifs_convert_path_to_utf16(oparms->path, oparms->cifs_sb);
71 if (smb2_path == NULL) { 71 if (smb2_path == NULL) {
72 rc = -ENOMEM; 72 rc = -ENOMEM;
73 goto out; 73 goto out;
@@ -80,21 +80,19 @@ smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
80 goto out; 80 goto out;
81 } 81 }
82 82
83 desired_access |= FILE_READ_ATTRIBUTES; 83 oparms->desired_access |= FILE_READ_ATTRIBUTES;
84 *smb2_oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE; 84 *smb2_oplock = SMB2_OPLOCK_LEVEL_BATCH;
85 85
86 if (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING) 86 if (oparms->tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING)
87 memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE); 87 memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE);
88 88
89 rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid, 89 rc = SMB2_open(xid, oparms, smb2_path, smb2_oplock, smb2_data);
90 &fid->volatile_fid, desired_access, disposition,
91 0, 0, smb2_oplock, smb2_data);
92 if (rc) 90 if (rc)
93 goto out; 91 goto out;
94 92
95 if (buf) { 93 if (buf) {
96 /* open response does not have IndexNumber field - get it */ 94 /* open response does not have IndexNumber field - get it */
97 rc = SMB2_get_srv_num(xid, tcon, fid->persistent_fid, 95 rc = SMB2_get_srv_num(xid, oparms->tcon, fid->persistent_fid,
98 fid->volatile_fid, 96 fid->volatile_fid,
99 &smb2_data->IndexNumber); 97 &smb2_data->IndexNumber);
100 if (rc) { 98 if (rc) {
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index fff6dfba6204..c6ec1633309a 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -41,21 +41,26 @@ static int
41smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon, 41smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
42 struct cifs_sb_info *cifs_sb, const char *full_path, 42 struct cifs_sb_info *cifs_sb, const char *full_path,
43 __u32 desired_access, __u32 create_disposition, 43 __u32 desired_access, __u32 create_disposition,
44 __u32 file_attributes, __u32 create_options, 44 __u32 create_options, void *data, int command)
45 void *data, int command)
46{ 45{
47 int rc, tmprc = 0; 46 int rc, tmprc = 0;
48 u64 persistent_fid, volatile_fid;
49 __le16 *utf16_path; 47 __le16 *utf16_path;
50 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; 48 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
49 struct cifs_open_parms oparms;
50 struct cifs_fid fid;
51 51
52 utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); 52 utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
53 if (!utf16_path) 53 if (!utf16_path)
54 return -ENOMEM; 54 return -ENOMEM;
55 55
56 rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid, 56 oparms.tcon = tcon;
57 desired_access, create_disposition, file_attributes, 57 oparms.desired_access = desired_access;
58 create_options, &oplock, NULL); 58 oparms.disposition = create_disposition;
59 oparms.create_options = create_options;
60 oparms.fid = &fid;
61 oparms.reconnect = false;
62
63 rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL);
59 if (rc) { 64 if (rc) {
60 kfree(utf16_path); 65 kfree(utf16_path);
61 return rc; 66 return rc;
@@ -65,8 +70,8 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
65 case SMB2_OP_DELETE: 70 case SMB2_OP_DELETE:
66 break; 71 break;
67 case SMB2_OP_QUERY_INFO: 72 case SMB2_OP_QUERY_INFO:
68 tmprc = SMB2_query_info(xid, tcon, persistent_fid, 73 tmprc = SMB2_query_info(xid, tcon, fid.persistent_fid,
69 volatile_fid, 74 fid.volatile_fid,
70 (struct smb2_file_all_info *)data); 75 (struct smb2_file_all_info *)data);
71 break; 76 break;
72 case SMB2_OP_MKDIR: 77 case SMB2_OP_MKDIR:
@@ -76,19 +81,21 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
76 */ 81 */
77 break; 82 break;
78 case SMB2_OP_RENAME: 83 case SMB2_OP_RENAME:
79 tmprc = SMB2_rename(xid, tcon, persistent_fid, volatile_fid, 84 tmprc = SMB2_rename(xid, tcon, fid.persistent_fid,
80 (__le16 *)data); 85 fid.volatile_fid, (__le16 *)data);
81 break; 86 break;
82 case SMB2_OP_HARDLINK: 87 case SMB2_OP_HARDLINK:
83 tmprc = SMB2_set_hardlink(xid, tcon, persistent_fid, 88 tmprc = SMB2_set_hardlink(xid, tcon, fid.persistent_fid,
84 volatile_fid, (__le16 *)data); 89 fid.volatile_fid, (__le16 *)data);
85 break; 90 break;
86 case SMB2_OP_SET_EOF: 91 case SMB2_OP_SET_EOF:
87 tmprc = SMB2_set_eof(xid, tcon, persistent_fid, volatile_fid, 92 tmprc = SMB2_set_eof(xid, tcon, fid.persistent_fid,
88 current->tgid, (__le64 *)data); 93 fid.volatile_fid, current->tgid,
94 (__le64 *)data);
89 break; 95 break;
90 case SMB2_OP_SET_INFO: 96 case SMB2_OP_SET_INFO:
91 tmprc = SMB2_set_info(xid, tcon, persistent_fid, volatile_fid, 97 tmprc = SMB2_set_info(xid, tcon, fid.persistent_fid,
98 fid.volatile_fid,
92 (FILE_BASIC_INFO *)data); 99 (FILE_BASIC_INFO *)data);
93 break; 100 break;
94 default: 101 default:
@@ -96,7 +103,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
96 break; 103 break;
97 } 104 }
98 105
99 rc = SMB2_close(xid, tcon, persistent_fid, volatile_fid); 106 rc = SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
100 if (tmprc) 107 if (tmprc)
101 rc = tmprc; 108 rc = tmprc;
102 kfree(utf16_path); 109 kfree(utf16_path);
@@ -129,8 +136,8 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
129 return -ENOMEM; 136 return -ENOMEM;
130 137
131 rc = smb2_open_op_close(xid, tcon, cifs_sb, full_path, 138 rc = smb2_open_op_close(xid, tcon, cifs_sb, full_path,
132 FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, 139 FILE_READ_ATTRIBUTES, FILE_OPEN, 0, smb2_data,
133 smb2_data, SMB2_OP_QUERY_INFO); 140 SMB2_OP_QUERY_INFO);
134 if (rc) 141 if (rc)
135 goto out; 142 goto out;
136 143
@@ -145,7 +152,7 @@ smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
145 struct cifs_sb_info *cifs_sb) 152 struct cifs_sb_info *cifs_sb)
146{ 153{
147 return smb2_open_op_close(xid, tcon, cifs_sb, name, 154 return smb2_open_op_close(xid, tcon, cifs_sb, name,
148 FILE_WRITE_ATTRIBUTES, FILE_CREATE, 0, 155 FILE_WRITE_ATTRIBUTES, FILE_CREATE,
149 CREATE_NOT_FILE, NULL, SMB2_OP_MKDIR); 156 CREATE_NOT_FILE, NULL, SMB2_OP_MKDIR);
150} 157}
151 158
@@ -164,7 +171,7 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name,
164 dosattrs = cifs_i->cifsAttrs | ATTR_READONLY; 171 dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
165 data.Attributes = cpu_to_le32(dosattrs); 172 data.Attributes = cpu_to_le32(dosattrs);
166 tmprc = smb2_open_op_close(xid, tcon, cifs_sb, name, 173 tmprc = smb2_open_op_close(xid, tcon, cifs_sb, name,
167 FILE_WRITE_ATTRIBUTES, FILE_CREATE, 0, 174 FILE_WRITE_ATTRIBUTES, FILE_CREATE,
168 CREATE_NOT_FILE, &data, SMB2_OP_SET_INFO); 175 CREATE_NOT_FILE, &data, SMB2_OP_SET_INFO);
169 if (tmprc == 0) 176 if (tmprc == 0)
170 cifs_i->cifsAttrs = dosattrs; 177 cifs_i->cifsAttrs = dosattrs;
@@ -175,7 +182,7 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
175 struct cifs_sb_info *cifs_sb) 182 struct cifs_sb_info *cifs_sb)
176{ 183{
177 return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, 184 return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
178 0, CREATE_NOT_FILE | CREATE_DELETE_ON_CLOSE, 185 CREATE_NOT_FILE | CREATE_DELETE_ON_CLOSE,
179 NULL, SMB2_OP_DELETE); 186 NULL, SMB2_OP_DELETE);
180} 187}
181 188
@@ -184,7 +191,7 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
184 struct cifs_sb_info *cifs_sb) 191 struct cifs_sb_info *cifs_sb)
185{ 192{
186 return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, 193 return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
187 0, CREATE_DELETE_ON_CLOSE, NULL, 194 CREATE_DELETE_ON_CLOSE, NULL,
188 SMB2_OP_DELETE); 195 SMB2_OP_DELETE);
189} 196}
190 197
@@ -203,7 +210,7 @@ smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
203 } 210 }
204 211
205 rc = smb2_open_op_close(xid, tcon, cifs_sb, from_name, access, 212 rc = smb2_open_op_close(xid, tcon, cifs_sb, from_name, access,
206 FILE_OPEN, 0, 0, smb2_to_name, command); 213 FILE_OPEN, 0, smb2_to_name, command);
207smb2_rename_path: 214smb2_rename_path:
208 kfree(smb2_to_name); 215 kfree(smb2_to_name);
209 return rc; 216 return rc;
@@ -234,7 +241,7 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
234{ 241{
235 __le64 eof = cpu_to_le64(size); 242 __le64 eof = cpu_to_le64(size);
236 return smb2_open_op_close(xid, tcon, cifs_sb, full_path, 243 return smb2_open_op_close(xid, tcon, cifs_sb, full_path,
237 FILE_WRITE_DATA, FILE_OPEN, 0, 0, &eof, 244 FILE_WRITE_DATA, FILE_OPEN, 0, &eof,
238 SMB2_OP_SET_EOF); 245 SMB2_OP_SET_EOF);
239} 246}
240 247
@@ -250,7 +257,7 @@ smb2_set_file_info(struct inode *inode, const char *full_path,
250 if (IS_ERR(tlink)) 257 if (IS_ERR(tlink))
251 return PTR_ERR(tlink); 258 return PTR_ERR(tlink);
252 rc = smb2_open_op_close(xid, tlink_tcon(tlink), cifs_sb, full_path, 259 rc = smb2_open_op_close(xid, tlink_tcon(tlink), cifs_sb, full_path,
253 FILE_WRITE_ATTRIBUTES, FILE_OPEN, 0, 0, buf, 260 FILE_WRITE_ATTRIBUTES, FILE_OPEN, 0, buf,
254 SMB2_OP_SET_INFO); 261 SMB2_OP_SET_INFO);
255 cifs_put_tlink(tlink); 262 cifs_put_tlink(tlink);
256 return rc; 263 return rc;
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 6d15cab95b99..f259e6cc8357 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -213,22 +213,29 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
213 struct cifs_sb_info *cifs_sb, const char *full_path) 213 struct cifs_sb_info *cifs_sb, const char *full_path)
214{ 214{
215 int rc; 215 int rc;
216 __u64 persistent_fid, volatile_fid;
217 __le16 *utf16_path; 216 __le16 *utf16_path;
218 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; 217 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
218 struct cifs_open_parms oparms;
219 struct cifs_fid fid;
219 220
220 utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); 221 utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
221 if (!utf16_path) 222 if (!utf16_path)
222 return -ENOMEM; 223 return -ENOMEM;
223 224
224 rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid, 225 oparms.tcon = tcon;
225 FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, &oplock, NULL); 226 oparms.desired_access = FILE_READ_ATTRIBUTES;
227 oparms.disposition = FILE_OPEN;
228 oparms.create_options = 0;
229 oparms.fid = &fid;
230 oparms.reconnect = false;
231
232 rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL);
226 if (rc) { 233 if (rc) {
227 kfree(utf16_path); 234 kfree(utf16_path);
228 return rc; 235 return rc;
229 } 236 }
230 237
231 rc = SMB2_close(xid, tcon, persistent_fid, volatile_fid); 238 rc = SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
232 kfree(utf16_path); 239 kfree(utf16_path);
233 return rc; 240 return rc;
234} 241}
@@ -443,15 +450,20 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
443 __le16 *utf16_path; 450 __le16 *utf16_path;
444 int rc; 451 int rc;
445 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; 452 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
446 __u64 persistent_fid, volatile_fid; 453 struct cifs_open_parms oparms;
447 454
448 utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); 455 utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
449 if (!utf16_path) 456 if (!utf16_path)
450 return -ENOMEM; 457 return -ENOMEM;
451 458
452 rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid, 459 oparms.tcon = tcon;
453 FILE_READ_ATTRIBUTES | FILE_READ_DATA, FILE_OPEN, 0, 0, 460 oparms.desired_access = FILE_READ_ATTRIBUTES | FILE_READ_DATA;
454 &oplock, NULL); 461 oparms.disposition = FILE_OPEN;
462 oparms.create_options = 0;
463 oparms.fid = fid;
464 oparms.reconnect = false;
465
466 rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL);
455 kfree(utf16_path); 467 kfree(utf16_path);
456 if (rc) { 468 if (rc) {
457 cifs_dbg(VFS, "open dir failed\n"); 469 cifs_dbg(VFS, "open dir failed\n");
@@ -460,14 +472,12 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
460 472
461 srch_inf->entries_in_buffer = 0; 473 srch_inf->entries_in_buffer = 0;
462 srch_inf->index_of_last_entry = 0; 474 srch_inf->index_of_last_entry = 0;
463 fid->persistent_fid = persistent_fid;
464 fid->volatile_fid = volatile_fid;
465 475
466 rc = SMB2_query_directory(xid, tcon, persistent_fid, volatile_fid, 0, 476 rc = SMB2_query_directory(xid, tcon, fid->persistent_fid,
467 srch_inf); 477 fid->volatile_fid, 0, srch_inf);
468 if (rc) { 478 if (rc) {
469 cifs_dbg(VFS, "query directory failed\n"); 479 cifs_dbg(VFS, "query directory failed\n");
470 SMB2_close(xid, tcon, persistent_fid, volatile_fid); 480 SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
471 } 481 }
472 return rc; 482 return rc;
473} 483}
@@ -528,17 +538,25 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
528 struct kstatfs *buf) 538 struct kstatfs *buf)
529{ 539{
530 int rc; 540 int rc;
531 u64 persistent_fid, volatile_fid;
532 __le16 srch_path = 0; /* Null - open root of share */ 541 __le16 srch_path = 0; /* Null - open root of share */
533 u8 oplock = SMB2_OPLOCK_LEVEL_NONE; 542 u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
543 struct cifs_open_parms oparms;
544 struct cifs_fid fid;
545
546 oparms.tcon = tcon;
547 oparms.desired_access = FILE_READ_ATTRIBUTES;
548 oparms.disposition = FILE_OPEN;
549 oparms.create_options = 0;
550 oparms.fid = &fid;
551 oparms.reconnect = false;
534 552
535 rc = SMB2_open(xid, tcon, &srch_path, &persistent_fid, &volatile_fid, 553 rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL);
536 FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, &oplock, NULL);
537 if (rc) 554 if (rc)
538 return rc; 555 return rc;
539 buf->f_type = SMB2_MAGIC_NUMBER; 556 buf->f_type = SMB2_MAGIC_NUMBER;
540 rc = SMB2_QFS_info(xid, tcon, persistent_fid, volatile_fid, buf); 557 rc = SMB2_QFS_info(xid, tcon, fid.persistent_fid, fid.volatile_fid,
541 SMB2_close(xid, tcon, persistent_fid, volatile_fid); 558 buf);
559 SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
542 return rc; 560 return rc;
543} 561}
544 562
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 2b312e4eeaa6..abc9c2809b51 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -847,29 +847,76 @@ create_lease_buf(u8 *lease_key, u8 oplock)
847 return buf; 847 return buf;
848} 848}
849 849
850static struct create_durable *
851create_durable_buf(void)
852{
853 struct create_durable *buf;
854
855 buf = kzalloc(sizeof(struct create_durable), GFP_KERNEL);
856 if (!buf)
857 return NULL;
858
859 buf->ccontext.DataOffset = cpu_to_le16(offsetof
860 (struct create_durable, Data));
861 buf->ccontext.DataLength = cpu_to_le32(16);
862 buf->ccontext.NameOffset = cpu_to_le16(offsetof
863 (struct create_durable, Name));
864 buf->ccontext.NameLength = cpu_to_le16(4);
865 buf->Name[0] = 'D';
866 buf->Name[1] = 'H';
867 buf->Name[2] = 'n';
868 buf->Name[3] = 'Q';
869 return buf;
870}
871
872static struct create_durable *
873create_reconnect_durable_buf(struct cifs_fid *fid)
874{
875 struct create_durable *buf;
876
877 buf = kzalloc(sizeof(struct create_durable), GFP_KERNEL);
878 if (!buf)
879 return NULL;
880
881 buf->ccontext.DataOffset = cpu_to_le16(offsetof
882 (struct create_durable, Data));
883 buf->ccontext.DataLength = cpu_to_le32(16);
884 buf->ccontext.NameOffset = cpu_to_le16(offsetof
885 (struct create_durable, Name));
886 buf->ccontext.NameLength = cpu_to_le16(4);
887 buf->Data.Fid.PersistentFileId = fid->persistent_fid;
888 buf->Data.Fid.VolatileFileId = fid->volatile_fid;
889 buf->Name[0] = 'D';
890 buf->Name[1] = 'H';
891 buf->Name[2] = 'n';
892 buf->Name[3] = 'C';
893 return buf;
894}
895
850static __u8 896static __u8
851parse_lease_state(struct smb2_create_rsp *rsp) 897parse_lease_state(struct smb2_create_rsp *rsp)
852{ 898{
853 char *data_offset; 899 char *data_offset;
854 struct create_lease *lc; 900 struct create_lease *lc;
855 bool found = false; 901 bool found = false;
902 unsigned int next = 0;
903 char *name;
856 904
857 data_offset = (char *)rsp; 905 data_offset = (char *)rsp + 4 + le32_to_cpu(rsp->CreateContextsOffset);
858 data_offset += 4 + le32_to_cpu(rsp->CreateContextsOffset);
859 lc = (struct create_lease *)data_offset; 906 lc = (struct create_lease *)data_offset;
860 do { 907 do {
861 char *name = le16_to_cpu(lc->ccontext.NameOffset) + (char *)lc; 908 lc = (struct create_lease *)((char *)lc + next);
909 name = le16_to_cpu(lc->ccontext.NameOffset) + (char *)lc;
862 if (le16_to_cpu(lc->ccontext.NameLength) != 4 || 910 if (le16_to_cpu(lc->ccontext.NameLength) != 4 ||
863 strncmp(name, "RqLs", 4)) { 911 strncmp(name, "RqLs", 4)) {
864 lc = (struct create_lease *)((char *)lc 912 next = le32_to_cpu(lc->ccontext.Next);
865 + le32_to_cpu(lc->ccontext.Next));
866 continue; 913 continue;
867 } 914 }
868 if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS) 915 if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS)
869 return SMB2_OPLOCK_LEVEL_NOCHANGE; 916 return SMB2_OPLOCK_LEVEL_NOCHANGE;
870 found = true; 917 found = true;
871 break; 918 break;
872 } while (le32_to_cpu(lc->ccontext.Next) != 0); 919 } while (next != 0);
873 920
874 if (!found) 921 if (!found)
875 return 0; 922 return 0;
@@ -877,23 +924,74 @@ parse_lease_state(struct smb2_create_rsp *rsp)
877 return smb2_map_lease_to_oplock(lc->lcontext.LeaseState); 924 return smb2_map_lease_to_oplock(lc->lcontext.LeaseState);
878} 925}
879 926
927static int
928add_lease_context(struct kvec *iov, unsigned int *num_iovec, __u8 *oplock)
929{
930 struct smb2_create_req *req = iov[0].iov_base;
931 unsigned int num = *num_iovec;
932
933 iov[num].iov_base = create_lease_buf(oplock+1, *oplock);
934 if (iov[num].iov_base == NULL)
935 return -ENOMEM;
936 iov[num].iov_len = sizeof(struct create_lease);
937 req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_LEASE;
938 if (!req->CreateContextsOffset)
939 req->CreateContextsOffset = cpu_to_le32(
940 sizeof(struct smb2_create_req) - 4 +
941 iov[num - 1].iov_len);
942 req->CreateContextsLength = cpu_to_le32(
943 le32_to_cpu(req->CreateContextsLength) +
944 sizeof(struct create_lease));
945 inc_rfc1001_len(&req->hdr, sizeof(struct create_lease));
946 *num_iovec = num + 1;
947 return 0;
948}
949
950static int
951add_durable_context(struct kvec *iov, unsigned int *num_iovec,
952 struct cifs_open_parms *oparms)
953{
954 struct smb2_create_req *req = iov[0].iov_base;
955 unsigned int num = *num_iovec;
956
957 if (oparms->reconnect) {
958 iov[num].iov_base = create_reconnect_durable_buf(oparms->fid);
959 /* indicate that we don't need to relock the file */
960 oparms->reconnect = false;
961 } else
962 iov[num].iov_base = create_durable_buf();
963 if (iov[num].iov_base == NULL)
964 return -ENOMEM;
965 iov[num].iov_len = sizeof(struct create_durable);
966 if (!req->CreateContextsOffset)
967 req->CreateContextsOffset =
968 cpu_to_le32(sizeof(struct smb2_create_req) - 4 +
969 iov[1].iov_len);
970 req->CreateContextsLength =
971 cpu_to_le32(le32_to_cpu(req->CreateContextsLength) +
972 sizeof(struct create_durable));
973 inc_rfc1001_len(&req->hdr, sizeof(struct create_durable));
974 *num_iovec = num + 1;
975 return 0;
976}
977
880int 978int
881SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path, 979SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
882 u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access,
883 __u32 create_disposition, __u32 file_attributes, __u32 create_options,
884 __u8 *oplock, struct smb2_file_all_info *buf) 980 __u8 *oplock, struct smb2_file_all_info *buf)
885{ 981{
886 struct smb2_create_req *req; 982 struct smb2_create_req *req;
887 struct smb2_create_rsp *rsp; 983 struct smb2_create_rsp *rsp;
888 struct TCP_Server_Info *server; 984 struct TCP_Server_Info *server;
985 struct cifs_tcon *tcon = oparms->tcon;
889 struct cifs_ses *ses = tcon->ses; 986 struct cifs_ses *ses = tcon->ses;
890 struct kvec iov[3]; 987 struct kvec iov[4];
891 int resp_buftype; 988 int resp_buftype;
892 int uni_path_len; 989 int uni_path_len;
893 __le16 *copy_path = NULL; 990 __le16 *copy_path = NULL;
894 int copy_size; 991 int copy_size;
895 int rc = 0; 992 int rc = 0;
896 int num_iovecs = 2; 993 unsigned int num_iovecs = 2;
994 __u32 file_attributes = 0;
897 995
898 cifs_dbg(FYI, "create/open\n"); 996 cifs_dbg(FYI, "create/open\n");
899 997
@@ -906,55 +1004,47 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
906 if (rc) 1004 if (rc)
907 return rc; 1005 return rc;
908 1006
1007 if (oparms->create_options & CREATE_OPTION_READONLY)
1008 file_attributes |= ATTR_READONLY;
1009
909 req->ImpersonationLevel = IL_IMPERSONATION; 1010 req->ImpersonationLevel = IL_IMPERSONATION;
910 req->DesiredAccess = cpu_to_le32(desired_access); 1011 req->DesiredAccess = cpu_to_le32(oparms->desired_access);
911 /* File attributes ignored on open (used in create though) */ 1012 /* File attributes ignored on open (used in create though) */
912 req->FileAttributes = cpu_to_le32(file_attributes); 1013 req->FileAttributes = cpu_to_le32(file_attributes);
913 req->ShareAccess = FILE_SHARE_ALL_LE; 1014 req->ShareAccess = FILE_SHARE_ALL_LE;
914 req->CreateDisposition = cpu_to_le32(create_disposition); 1015 req->CreateDisposition = cpu_to_le32(oparms->disposition);
915 req->CreateOptions = cpu_to_le32(create_options); 1016 req->CreateOptions = cpu_to_le32(oparms->create_options & CREATE_OPTIONS_MASK);
916 uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2; 1017 uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2;
917 req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req) 1018 /* do not count rfc1001 len field */
918 - 8 /* pad */ - 4 /* do not count rfc1001 len field */); 1019 req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req) - 4);
919 1020
920 iov[0].iov_base = (char *)req; 1021 iov[0].iov_base = (char *)req;
921 /* 4 for rfc1002 length field */ 1022 /* 4 for rfc1002 length field */
922 iov[0].iov_len = get_rfc1002_length(req) + 4; 1023 iov[0].iov_len = get_rfc1002_length(req) + 4;
923 1024
924 /* MUST set path len (NameLength) to 0 opening root of share */ 1025 /* MUST set path len (NameLength) to 0 opening root of share */
925 if (uni_path_len >= 4) { 1026 req->NameLength = cpu_to_le16(uni_path_len - 2);
926 req->NameLength = cpu_to_le16(uni_path_len - 2); 1027 /* -1 since last byte is buf[0] which is sent below (path) */
927 /* -1 since last byte is buf[0] which is sent below (path) */ 1028 iov[0].iov_len--;
928 iov[0].iov_len--; 1029 if (uni_path_len % 8 != 0) {
929 if (uni_path_len % 8 != 0) { 1030 copy_size = uni_path_len / 8 * 8;
930 copy_size = uni_path_len / 8 * 8; 1031 if (copy_size < uni_path_len)
931 if (copy_size < uni_path_len) 1032 copy_size += 8;
932 copy_size += 8; 1033
933 1034 copy_path = kzalloc(copy_size, GFP_KERNEL);
934 copy_path = kzalloc(copy_size, GFP_KERNEL); 1035 if (!copy_path)
935 if (!copy_path) 1036 return -ENOMEM;
936 return -ENOMEM; 1037 memcpy((char *)copy_path, (const char *)path,
937 memcpy((char *)copy_path, (const char *)path, 1038 uni_path_len);
938 uni_path_len); 1039 uni_path_len = copy_size;
939 uni_path_len = copy_size; 1040 path = copy_path;
940 path = copy_path;
941 }
942
943 iov[1].iov_len = uni_path_len;
944 iov[1].iov_base = path;
945 /*
946 * -1 since last byte is buf[0] which was counted in
947 * smb2_buf_len.
948 */
949 inc_rfc1001_len(req, uni_path_len - 1);
950 } else {
951 iov[0].iov_len += 7;
952 req->hdr.smb2_buf_length = cpu_to_be32(be32_to_cpu(
953 req->hdr.smb2_buf_length) + 8 - 1);
954 num_iovecs = 1;
955 req->NameLength = 0;
956 } 1041 }
957 1042
1043 iov[1].iov_len = uni_path_len;
1044 iov[1].iov_base = path;
1045 /* -1 since last byte is buf[0] which was counted in smb2_buf_len */
1046 inc_rfc1001_len(req, uni_path_len - 1);
1047
958 if (!server->oplocks) 1048 if (!server->oplocks)
959 *oplock = SMB2_OPLOCK_LEVEL_NONE; 1049 *oplock = SMB2_OPLOCK_LEVEL_NONE;
960 1050
@@ -962,21 +1052,29 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
962 *oplock == SMB2_OPLOCK_LEVEL_NONE) 1052 *oplock == SMB2_OPLOCK_LEVEL_NONE)
963 req->RequestedOplockLevel = *oplock; 1053 req->RequestedOplockLevel = *oplock;
964 else { 1054 else {
965 iov[num_iovecs].iov_base = create_lease_buf(oplock+1, *oplock); 1055 rc = add_lease_context(iov, &num_iovecs, oplock);
966 if (iov[num_iovecs].iov_base == NULL) { 1056 if (rc) {
967 cifs_small_buf_release(req); 1057 cifs_small_buf_release(req);
968 kfree(copy_path); 1058 kfree(copy_path);
969 return -ENOMEM; 1059 return rc;
1060 }
1061 }
1062
1063 if (*oplock == SMB2_OPLOCK_LEVEL_BATCH) {
1064 /* need to set Next field of lease context if we request it */
1065 if (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING) {
1066 struct create_context *ccontext =
1067 (struct create_context *)iov[num_iovecs-1].iov_base;
1068 ccontext->Next =
1069 cpu_to_le32(sizeof(struct create_lease));
1070 }
1071 rc = add_durable_context(iov, &num_iovecs, oparms);
1072 if (rc) {
1073 cifs_small_buf_release(req);
1074 kfree(copy_path);
1075 kfree(iov[num_iovecs-1].iov_base);
1076 return rc;
970 } 1077 }
971 iov[num_iovecs].iov_len = sizeof(struct create_lease);
972 req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_LEASE;
973 req->CreateContextsOffset = cpu_to_le32(
974 sizeof(struct smb2_create_req) - 4 - 8 +
975 iov[num_iovecs-1].iov_len);
976 req->CreateContextsLength = cpu_to_le32(
977 sizeof(struct create_lease));
978 inc_rfc1001_len(&req->hdr, sizeof(struct create_lease));
979 num_iovecs++;
980 } 1078 }
981 1079
982 rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0); 1080 rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0);
@@ -987,8 +1085,8 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
987 goto creat_exit; 1085 goto creat_exit;
988 } 1086 }
989 1087
990 *persistent_fid = rsp->PersistentFileId; 1088 oparms->fid->persistent_fid = rsp->PersistentFileId;
991 *volatile_fid = rsp->VolatileFileId; 1089 oparms->fid->volatile_fid = rsp->VolatileFileId;
992 1090
993 if (buf) { 1091 if (buf) {
994 memcpy(buf, &rsp->CreationTime, 32); 1092 memcpy(buf, &rsp->CreationTime, 32);
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index f31043b26bd3..36b0d37ea69b 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -428,7 +428,7 @@ struct smb2_create_req {
428 __le16 NameLength; 428 __le16 NameLength;
429 __le32 CreateContextsOffset; 429 __le32 CreateContextsOffset;
430 __le32 CreateContextsLength; 430 __le32 CreateContextsLength;
431 __u8 Buffer[8]; 431 __u8 Buffer[0];
432} __packed; 432} __packed;
433 433
434struct smb2_create_rsp { 434struct smb2_create_rsp {
@@ -485,6 +485,18 @@ struct create_lease {
485 struct lease_context lcontext; 485 struct lease_context lcontext;
486} __packed; 486} __packed;
487 487
488struct create_durable {
489 struct create_context ccontext;
490 __u8 Name[8];
491 union {
492 __u8 Reserved[16];
493 struct {
494 __u64 PersistentFileId;
495 __u64 VolatileFileId;
496 } Fid;
497 } Data;
498} __packed;
499
488/* this goes in the ioctl buffer when doing a copychunk request */ 500/* this goes in the ioctl buffer when doing a copychunk request */
489struct copychunk_ioctl { 501struct copychunk_ioctl {
490 char SourceKey[24]; 502 char SourceKey[24];
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index d4e1eb807457..1a5ecbed40ed 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -84,11 +84,9 @@ extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
84 const char *from_name, const char *to_name, 84 const char *from_name, const char *to_name,
85 struct cifs_sb_info *cifs_sb); 85 struct cifs_sb_info *cifs_sb);
86 86
87extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, 87extern int smb2_open_file(const unsigned int xid,
88 const char *full_path, int disposition, 88 struct cifs_open_parms *oparms,
89 int desired_access, int create_options, 89 __u32 *oplock, FILE_ALL_INFO *buf);
90 struct cifs_fid *fid, __u32 *oplock,
91 FILE_ALL_INFO *buf, struct cifs_sb_info *cifs_sb);
92extern void smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock); 90extern void smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
93extern int smb2_unlock_range(struct cifsFileInfo *cfile, 91extern int smb2_unlock_range(struct cifsFileInfo *cfile,
94 struct file_lock *flock, const unsigned int xid); 92 struct file_lock *flock, const unsigned int xid);
@@ -106,11 +104,9 @@ extern int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses,
106 const char *tree, struct cifs_tcon *tcon, 104 const char *tree, struct cifs_tcon *tcon,
107 const struct nls_table *); 105 const struct nls_table *);
108extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon); 106extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon);
109extern int SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, 107extern int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms,
110 __le16 *path, u64 *persistent_fid, u64 *volatile_fid, 108 __le16 *path, __u8 *oplock,
111 __u32 desired_access, __u32 create_disposition, 109 struct smb2_file_all_info *buf);
112 __u32 file_attributes, __u32 create_options,
113 __u8 *oplock, struct smb2_file_all_info *buf);
114extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, 110extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon,
115 u64 persistent_fid, u64 volatile_fid, u32 opcode, 111 u64 persistent_fid, u64 volatile_fid, u32 opcode,
116 bool is_fsctl, char *in_data, u32 indatalen, 112 bool is_fsctl, char *in_data, u32 indatalen,
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index 09b4fbaadeb6..301b191270b9 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -39,6 +39,77 @@
39#include "smb2status.h" 39#include "smb2status.h"
40#include "smb2glob.h" 40#include "smb2glob.h"
41 41
42static int
43smb2_crypto_shash_allocate(struct TCP_Server_Info *server)
44{
45 unsigned int size;
46
47 if (server->secmech.sdeschmacsha256 != NULL)
48 return 0; /* already allocated */
49
50 server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
51 if (IS_ERR(server->secmech.hmacsha256)) {
52 cifs_dbg(VFS, "could not allocate crypto hmacsha256\n");
53 return PTR_ERR(server->secmech.hmacsha256);
54 }
55
56 size = sizeof(struct shash_desc) +
57 crypto_shash_descsize(server->secmech.hmacsha256);
58 server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL);
59 if (!server->secmech.sdeschmacsha256) {
60 crypto_free_shash(server->secmech.hmacsha256);
61 server->secmech.hmacsha256 = NULL;
62 return -ENOMEM;
63 }
64 server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
65 server->secmech.sdeschmacsha256->shash.flags = 0x0;
66
67 return 0;
68}
69
70static int
71smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
72{
73 unsigned int size;
74 int rc;
75
76 if (server->secmech.sdesccmacaes != NULL)
77 return 0; /* already allocated */
78
79 rc = smb2_crypto_shash_allocate(server);
80 if (rc)
81 return rc;
82
83 server->secmech.cmacaes = crypto_alloc_shash("cmac(aes)", 0, 0);
84 if (IS_ERR(server->secmech.cmacaes)) {
85 cifs_dbg(VFS, "could not allocate crypto cmac-aes");
86 kfree(server->secmech.sdeschmacsha256);
87 server->secmech.sdeschmacsha256 = NULL;
88 crypto_free_shash(server->secmech.hmacsha256);
89 server->secmech.hmacsha256 = NULL;
90 return PTR_ERR(server->secmech.cmacaes);
91 }
92
93 size = sizeof(struct shash_desc) +
94 crypto_shash_descsize(server->secmech.cmacaes);
95 server->secmech.sdesccmacaes = kmalloc(size, GFP_KERNEL);
96 if (!server->secmech.sdesccmacaes) {
97 cifs_dbg(VFS, "%s: Can't alloc cmacaes\n", __func__);
98 kfree(server->secmech.sdeschmacsha256);
99 server->secmech.sdeschmacsha256 = NULL;
100 crypto_free_shash(server->secmech.hmacsha256);
101 crypto_free_shash(server->secmech.cmacaes);
102 server->secmech.hmacsha256 = NULL;
103 server->secmech.cmacaes = NULL;
104 return -ENOMEM;
105 }
106 server->secmech.sdesccmacaes->shash.tfm = server->secmech.cmacaes;
107 server->secmech.sdesccmacaes->shash.flags = 0x0;
108
109 return 0;
110}
111
112
42int 113int
43smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) 114smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
44{ 115{
@@ -52,6 +123,12 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
52 memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE); 123 memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
53 memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE); 124 memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
54 125
126 rc = smb2_crypto_shash_allocate(server);
127 if (rc) {
128 cifs_dbg(VFS, "%s: shah256 alloc failed\n", __func__);
129 return rc;
130 }
131
55 rc = crypto_shash_setkey(server->secmech.hmacsha256, 132 rc = crypto_shash_setkey(server->secmech.hmacsha256,
56 server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE); 133 server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
57 if (rc) { 134 if (rc) {
@@ -61,7 +138,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
61 138
62 rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash); 139 rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash);
63 if (rc) { 140 if (rc) {
64 cifs_dbg(VFS, "%s: Could not init md5\n", __func__); 141 cifs_dbg(VFS, "%s: Could not init sha256", __func__);
65 return rc; 142 return rc;
66 } 143 }
67 144
@@ -129,6 +206,12 @@ generate_smb3signingkey(struct TCP_Server_Info *server)
129 memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE); 206 memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE);
130 memset(server->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE); 207 memset(server->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE);
131 208
209 rc = smb3_crypto_shash_allocate(server);
210 if (rc) {
211 cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
212 goto smb3signkey_ret;
213 }
214
132 rc = crypto_shash_setkey(server->secmech.hmacsha256, 215 rc = crypto_shash_setkey(server->secmech.hmacsha256,
133 server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE); 216 server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
134 if (rc) { 217 if (rc) {
@@ -210,6 +293,11 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
210 return rc; 293 return rc;
211 } 294 }
212 295
296 /*
297 * we already allocate sdesccmacaes when we init smb3 signing key,
298 * so unlike smb2 case we do not have to check here if secmech are
299 * initialized
300 */
213 rc = crypto_shash_init(&server->secmech.sdesccmacaes->shash); 301 rc = crypto_shash_init(&server->secmech.sdesccmacaes->shash);
214 if (rc) { 302 if (rc) {
215 cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__); 303 cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__);