diff options
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/cifsencrypt.c | 195 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 17 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 1 | ||||
-rw-r--r-- | fs/cifs/connect.c | 6 | ||||
-rw-r--r-- | fs/cifs/dir.c | 14 | ||||
-rw-r--r-- | fs/cifs/file.c | 54 | ||||
-rw-r--r-- | fs/cifs/inode.c | 5 | ||||
-rw-r--r-- | fs/cifs/smb1ops.c | 29 | ||||
-rw-r--r-- | fs/cifs/smb2file.c | 24 | ||||
-rw-r--r-- | fs/cifs/smb2inode.c | 57 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 54 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 220 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.h | 14 | ||||
-rw-r--r-- | fs/cifs/smb2proto.h | 16 | ||||
-rw-r--r-- | fs/cifs/smb2transport.c | 90 |
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 | ||
34 | static int | ||
35 | cifs_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 | ||
592 | static 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 | ||
560 | int | 620 | int |
561 | setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) | 621 | setup_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) | |||
705 | void | 771 | void |
706 | cifs_crypto_shash_release(struct TCP_Server_Info *server) | 772 | cifs_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 | |||
729 | int | ||
730 | cifs_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 | |||
805 | crypto_allocate_cmacaes_sdesc_fail: | ||
806 | kfree(server->secmech.sdeschmacsha256); | ||
807 | |||
808 | crypto_allocate_hmacsha256_sdesc_fail: | ||
809 | kfree(server->secmech.sdescmd5); | ||
810 | |||
811 | crypto_allocate_md5_sdesc_fail: | ||
812 | kfree(server->secmech.sdeschmacmd5); | ||
813 | |||
814 | crypto_allocate_hmacmd5_sdesc_fail: | ||
815 | crypto_free_shash(server->secmech.cmacaes); | ||
816 | |||
817 | crypto_allocate_cmacaes_fail: | ||
818 | crypto_free_shash(server->secmech.hmacsha256); | ||
819 | |||
820 | crypto_allocate_hmacsha256_fail: | ||
821 | crypto_free_shash(server->secmech.md5); | ||
822 | |||
823 | crypto_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; | |||
194 | struct cifs_io_parms; | 194 | struct cifs_io_parms; |
195 | struct cifs_search_info; | 195 | struct cifs_search_info; |
196 | struct cifsInodeInfo; | 196 | struct cifsInodeInfo; |
197 | struct cifs_open_parms; | ||
197 | 198 | ||
198 | struct smb_version_operations { | 199 | struct 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 | ||
915 | struct 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 | |||
915 | struct cifs_fid { | 926 | struct 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 *); |
434 | extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *); | 434 | extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *); |
435 | extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *); | 435 | extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *); |
436 | extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *); | ||
437 | extern void cifs_crypto_shash_release(struct TCP_Server_Info *); | 436 | extern void cifs_crypto_shash_release(struct TCP_Server_Info *); |
438 | extern int calc_seckey(struct cifs_ses *); | 437 | extern int calc_seckey(struct cifs_ses *); |
439 | extern void generate_smb3signingkey(struct TCP_Server_Info *); | 438 | extern 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 | ||
702 | reopen_error_exit: | 724 | reopen_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 | ||
676 | static int | 676 | static int |
677 | cifs_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path, | 677 | cifs_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 | ||
59 | int | 60 | int |
60 | smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path, | 61 | smb2_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 | |||
41 | smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon, | 41 | smb2_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); |
207 | smb2_rename_path: | 214 | smb2_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 | ||
850 | static struct create_durable * | ||
851 | create_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 | |||
872 | static struct create_durable * | ||
873 | create_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 | |||
850 | static __u8 | 896 | static __u8 |
851 | parse_lease_state(struct smb2_create_rsp *rsp) | 897 | parse_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 | ||
927 | static int | ||
928 | add_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 | |||
950 | static int | ||
951 | add_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 | |||
880 | int | 978 | int |
881 | SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path, | 979 | SMB2_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 | ||
434 | struct smb2_create_rsp { | 434 | struct 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 | ||
488 | struct 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 */ |
489 | struct copychunk_ioctl { | 501 | struct 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 | ||
87 | extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, | 87 | extern 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); | ||
92 | extern void smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock); | 90 | extern void smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock); |
93 | extern int smb2_unlock_range(struct cifsFileInfo *cfile, | 91 | extern 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 *); |
108 | extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon); | 106 | extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon); |
109 | extern int SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, | 107 | extern 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); | ||
114 | extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, | 110 | extern 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 | ||
42 | static int | ||
43 | smb2_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 | |||
70 | static int | ||
71 | smb3_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 | |||
42 | int | 113 | int |
43 | smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | 114 | smb2_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__); |