aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilovsky@samba.org>2012-09-19 09:22:44 -0400
committerSteve French <smfrench@gmail.com>2012-09-24 22:46:33 -0400
commitb8c32dbb0deb287a5fcb78251e4eae6c7275760d (patch)
treefa3cddfd4595846921f51a922b7e1722b1e35fa4 /fs/cifs
parent579f9053236c796d718162c37c72bb3bd32d008c (diff)
CIFS: Request SMB2.1 leases
if server supports them and we need oplocks. Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifsfs.c28
-rw-r--r--fs/cifs/cifsglob.h10
-rw-r--r--fs/cifs/dir.c13
-rw-r--r--fs/cifs/file.c21
-rw-r--r--fs/cifs/smb2file.c9
-rw-r--r--fs/cifs/smb2ops.c21
-rw-r--r--fs/cifs/smb2pdu.c138
-rw-r--r--fs/cifs/smb2pdu.h43
8 files changed, 256 insertions, 27 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 4cd68c77ce3..28ac048d54e 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -36,6 +36,7 @@
36#include <linux/kthread.h> 36#include <linux/kthread.h>
37#include <linux/freezer.h> 37#include <linux/freezer.h>
38#include <linux/namei.h> 38#include <linux/namei.h>
39#include <linux/random.h>
39#include <net/ipv6.h> 40#include <net/ipv6.h>
40#include "cifsfs.h" 41#include "cifsfs.h"
41#include "cifspdu.h" 42#include "cifspdu.h"
@@ -88,6 +89,10 @@ extern mempool_t *cifs_mid_poolp;
88 89
89struct workqueue_struct *cifsiod_wq; 90struct workqueue_struct *cifsiod_wq;
90 91
92#ifdef CONFIG_CIFS_SMB2
93__u8 cifs_client_guid[SMB2_CLIENT_GUID_SIZE];
94#endif
95
91static int 96static int
92cifs_read_super(struct super_block *sb) 97cifs_read_super(struct super_block *sb)
93{ 98{
@@ -218,9 +223,10 @@ cifs_alloc_inode(struct super_block *sb)
218 return NULL; 223 return NULL;
219 cifs_inode->cifsAttrs = 0x20; /* default */ 224 cifs_inode->cifsAttrs = 0x20; /* default */
220 cifs_inode->time = 0; 225 cifs_inode->time = 0;
221 /* Until the file is open and we have gotten oplock 226 /*
222 info back from the server, can not assume caching of 227 * Until the file is open and we have gotten oplock info back from the
223 file data or metadata */ 228 * server, can not assume caching of file data or metadata.
229 */
224 cifs_set_oplock_level(cifs_inode, 0); 230 cifs_set_oplock_level(cifs_inode, 0);
225 cifs_inode->delete_pending = false; 231 cifs_inode->delete_pending = false;
226 cifs_inode->invalid_mapping = false; 232 cifs_inode->invalid_mapping = false;
@@ -228,10 +234,14 @@ cifs_alloc_inode(struct super_block *sb)
228 cifs_inode->server_eof = 0; 234 cifs_inode->server_eof = 0;
229 cifs_inode->uniqueid = 0; 235 cifs_inode->uniqueid = 0;
230 cifs_inode->createtime = 0; 236 cifs_inode->createtime = 0;
231 237#ifdef CONFIG_CIFS_SMB2
232 /* Can not set i_flags here - they get immediately overwritten 238 get_random_bytes(cifs_inode->lease_key, SMB2_LEASE_KEY_SIZE);
233 to zero by the VFS */ 239#endif
234/* cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME;*/ 240 /*
241 * Can not set i_flags here - they get immediately overwritten to zero
242 * by the VFS.
243 */
244 /* cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME; */
235 INIT_LIST_HEAD(&cifs_inode->openFileList); 245 INIT_LIST_HEAD(&cifs_inode->openFileList);
236 INIT_LIST_HEAD(&cifs_inode->llist); 246 INIT_LIST_HEAD(&cifs_inode->llist);
237 return &cifs_inode->vfs_inode; 247 return &cifs_inode->vfs_inode;
@@ -1107,6 +1117,10 @@ init_cifs(void)
1107 spin_lock_init(&cifs_file_list_lock); 1117 spin_lock_init(&cifs_file_list_lock);
1108 spin_lock_init(&GlobalMid_Lock); 1118 spin_lock_init(&GlobalMid_Lock);
1109 1119
1120#ifdef CONFIG_CIFS_SMB2
1121 get_random_bytes(cifs_client_guid, SMB2_CLIENT_GUID_SIZE);
1122#endif
1123
1110 if (cifs_max_pending < 2) { 1124 if (cifs_max_pending < 2) {
1111 cifs_max_pending = 2; 1125 cifs_max_pending = 2;
1112 cFYI(1, "cifs_max_pending set to min of 2"); 1126 cFYI(1, "cifs_max_pending set to min of 2");
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index e2492e1cdb8..b6ec142028e 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -361,6 +361,12 @@ struct smb_version_operations {
361 const unsigned int); 361 const unsigned int);
362 /* push brlocks from the cache to the server */ 362 /* push brlocks from the cache to the server */
363 int (*push_mand_locks)(struct cifsFileInfo *); 363 int (*push_mand_locks)(struct cifsFileInfo *);
364 /* get lease key of the inode */
365 void (*get_lease_key)(struct inode *, struct cifs_fid *fid);
366 /* set lease key of the inode */
367 void (*set_lease_key)(struct inode *, struct cifs_fid *fid);
368 /* generate new lease key */
369 void (*new_lease_key)(struct cifs_fid *fid);
364}; 370};
365 371
366struct smb_version_values { 372struct smb_version_values {
@@ -895,6 +901,7 @@ struct cifs_fid {
895#ifdef CONFIG_CIFS_SMB2 901#ifdef CONFIG_CIFS_SMB2
896 __u64 persistent_fid; /* persist file id for smb2 */ 902 __u64 persistent_fid; /* persist file id for smb2 */
897 __u64 volatile_fid; /* volatile file id for smb2 */ 903 __u64 volatile_fid; /* volatile file id for smb2 */
904 __u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for smb2 */
898#endif 905#endif
899}; 906};
900 907
@@ -1012,6 +1019,9 @@ struct cifsInodeInfo {
1012 u64 server_eof; /* current file size on server -- protected by i_lock */ 1019 u64 server_eof; /* current file size on server -- protected by i_lock */
1013 u64 uniqueid; /* server inode number */ 1020 u64 uniqueid; /* server inode number */
1014 u64 createtime; /* creation time on server */ 1021 u64 createtime; /* creation time on server */
1022#ifdef CONFIG_CIFS_SMB2
1023 __u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for this inode */
1024#endif
1015#ifdef CONFIG_CIFS_FSCACHE 1025#ifdef CONFIG_CIFS_FSCACHE
1016 struct fscache_cookie *fscache; 1026 struct fscache_cookie *fscache;
1017#endif 1027#endif
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index b99a1670dad..4f2147c5adb 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -340,6 +340,8 @@ cifs_create_get_file_info:
340 rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb, 340 rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb,
341 xid, &fid->netfid); 341 xid, &fid->netfid);
342 if (newinode) { 342 if (newinode) {
343 if (server->ops->set_lease_key)
344 server->ops->set_lease_key(newinode, fid);
343 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) 345 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
344 newinode->i_mode = mode; 346 newinode->i_mode = mode;
345 if ((*oplock & CIFS_CREATE_ACTION) && 347 if ((*oplock & CIFS_CREATE_ACTION) &&
@@ -418,6 +420,9 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
418 tcon = tlink_tcon(tlink); 420 tcon = tlink_tcon(tlink);
419 server = tcon->ses->server; 421 server = tcon->ses->server;
420 422
423 if (server->ops->new_lease_key)
424 server->ops->new_lease_key(&fid);
425
421 rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, 426 rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
422 &oplock, &fid, opened); 427 &oplock, &fid, opened);
423 428
@@ -473,10 +478,14 @@ int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
473 if (IS_ERR(tlink)) 478 if (IS_ERR(tlink))
474 goto out_free_xid; 479 goto out_free_xid;
475 480
476 rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
477 &oplock, &fid, &created);
478 tcon = tlink_tcon(tlink); 481 tcon = tlink_tcon(tlink);
479 server = tcon->ses->server; 482 server = tcon->ses->server;
483
484 if (server->ops->new_lease_key)
485 server->ops->new_lease_key(&fid);
486
487 rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
488 &oplock, &fid, &created);
480 if (!rc && server->ops->close) 489 if (!rc && server->ops->close)
481 server->ops->close(xid, tcon, &fid); 490 server->ops->close(xid, tcon, &fid);
482 491
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 2e2e4f9aeb6..ccad858d2d6 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -177,8 +177,9 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
177 int disposition; 177 int disposition;
178 int create_options = CREATE_NOT_DIR; 178 int create_options = CREATE_NOT_DIR;
179 FILE_ALL_INFO *buf; 179 FILE_ALL_INFO *buf;
180 struct TCP_Server_Info *server = tcon->ses->server;
180 181
181 if (!tcon->ses->server->ops->open) 182 if (!server->ops->open)
182 return -ENOSYS; 183 return -ENOSYS;
183 184
184 desired_access = cifs_convert_flags(f_flags); 185 desired_access = cifs_convert_flags(f_flags);
@@ -218,9 +219,9 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
218 if (backup_cred(cifs_sb)) 219 if (backup_cred(cifs_sb))
219 create_options |= CREATE_OPEN_BACKUP_INTENT; 220 create_options |= CREATE_OPEN_BACKUP_INTENT;
220 221
221 rc = tcon->ses->server->ops->open(xid, tcon, full_path, disposition, 222 rc = server->ops->open(xid, tcon, full_path, disposition,
222 desired_access, create_options, fid, 223 desired_access, create_options, fid, oplock, buf,
223 oplock, buf, cifs_sb); 224 cifs_sb);
224 225
225 if (rc) 226 if (rc)
226 goto out; 227 goto out;
@@ -372,6 +373,7 @@ int cifs_open(struct inode *inode, struct file *file)
372 unsigned int xid; 373 unsigned int xid;
373 __u32 oplock; 374 __u32 oplock;
374 struct cifs_sb_info *cifs_sb; 375 struct cifs_sb_info *cifs_sb;
376 struct TCP_Server_Info *server;
375 struct cifs_tcon *tcon; 377 struct cifs_tcon *tcon;
376 struct tcon_link *tlink; 378 struct tcon_link *tlink;
377 struct cifsFileInfo *cfile = NULL; 379 struct cifsFileInfo *cfile = NULL;
@@ -388,6 +390,7 @@ int cifs_open(struct inode *inode, struct file *file)
388 return PTR_ERR(tlink); 390 return PTR_ERR(tlink);
389 } 391 }
390 tcon = tlink_tcon(tlink); 392 tcon = tlink_tcon(tlink);
393 server = tcon->ses->server;
391 394
392 full_path = build_path_from_dentry(file->f_path.dentry); 395 full_path = build_path_from_dentry(file->f_path.dentry);
393 if (full_path == NULL) { 396 if (full_path == NULL) {
@@ -432,6 +435,9 @@ int cifs_open(struct inode *inode, struct file *file)
432 } 435 }
433 436
434 if (!posix_open_ok) { 437 if (!posix_open_ok) {
438 if (server->ops->get_lease_key)
439 server->ops->get_lease_key(inode, &fid);
440
435 rc = cifs_nt_open(full_path, inode, cifs_sb, tcon, 441 rc = cifs_nt_open(full_path, inode, cifs_sb, tcon,
436 file->f_flags, &oplock, &fid, xid); 442 file->f_flags, &oplock, &fid, xid);
437 if (rc) 443 if (rc)
@@ -440,8 +446,8 @@ int cifs_open(struct inode *inode, struct file *file)
440 446
441 cfile = cifs_new_fileinfo(&fid, file, tlink, oplock); 447 cfile = cifs_new_fileinfo(&fid, file, tlink, oplock);
442 if (cfile == NULL) { 448 if (cfile == NULL) {
443 if (tcon->ses->server->ops->close) 449 if (server->ops->close)
444 tcon->ses->server->ops->close(xid, tcon, &fid); 450 server->ops->close(xid, tcon, &fid);
445 rc = -ENOMEM; 451 rc = -ENOMEM;
446 goto out; 452 goto out;
447 } 453 }
@@ -567,6 +573,9 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
567 if (backup_cred(cifs_sb)) 573 if (backup_cred(cifs_sb))
568 create_options |= CREATE_OPEN_BACKUP_INTENT; 574 create_options |= CREATE_OPEN_BACKUP_INTENT;
569 575
576 if (server->ops->get_lease_key)
577 server->ops->get_lease_key(inode, &fid);
578
570 /* 579 /*
571 * Can not refresh inode by passing in file_info buf to be returned by 580 * Can not refresh inode by passing in file_info buf to be returned by
572 * CIFSSMBOpen and then calling get_inode_info with returned buf since 581 * CIFSSMBOpen and then calling get_inode_info with returned buf since
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index 0ddd617ffa1..78fb2050e0d 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -63,6 +63,7 @@ smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
63 int rc; 63 int rc;
64 __le16 *smb2_path; 64 __le16 *smb2_path;
65 struct smb2_file_all_info *smb2_data = NULL; 65 struct smb2_file_all_info *smb2_data = NULL;
66 __u8 smb2_oplock[17];
66 67
67 smb2_path = cifs_convert_path_to_utf16(path, cifs_sb); 68 smb2_path = cifs_convert_path_to_utf16(path, cifs_sb);
68 if (smb2_path == NULL) { 69 if (smb2_path == NULL) {
@@ -78,11 +79,14 @@ smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
78 } 79 }
79 80
80 desired_access |= FILE_READ_ATTRIBUTES; 81 desired_access |= FILE_READ_ATTRIBUTES;
81 *oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE; 82 *smb2_oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
83
84 if (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING)
85 memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE);
82 86
83 rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid, 87 rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid,
84 &fid->volatile_fid, desired_access, disposition, 88 &fid->volatile_fid, desired_access, disposition,
85 0, 0, (__u8 *)oplock, smb2_data); 89 0, 0, smb2_oplock, smb2_data);
86 if (rc) 90 if (rc)
87 goto out; 91 goto out;
88 92
@@ -99,6 +103,7 @@ smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
99 move_smb2_info_to_cifs(buf, smb2_data); 103 move_smb2_info_to_cifs(buf, smb2_data);
100 } 104 }
101 105
106 *oplock = *smb2_oplock;
102out: 107out:
103 kfree(smb2_data); 108 kfree(smb2_data);
104 kfree(smb2_path); 109 kfree(smb2_path);
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 0808b238219..360d9079af4 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -555,6 +555,24 @@ smb2_mand_lock(const unsigned int xid, struct cifsFileInfo *cfile, __u64 offset,
555 current->tgid, length, offset, type, wait); 555 current->tgid, length, offset, type, wait);
556} 556}
557 557
558static void
559smb2_get_lease_key(struct inode *inode, struct cifs_fid *fid)
560{
561 memcpy(fid->lease_key, CIFS_I(inode)->lease_key, SMB2_LEASE_KEY_SIZE);
562}
563
564static void
565smb2_set_lease_key(struct inode *inode, struct cifs_fid *fid)
566{
567 memcpy(CIFS_I(inode)->lease_key, fid->lease_key, SMB2_LEASE_KEY_SIZE);
568}
569
570static void
571smb2_new_lease_key(struct cifs_fid *fid)
572{
573 get_random_bytes(fid->lease_key, SMB2_LEASE_KEY_SIZE);
574}
575
558struct smb_version_operations smb21_operations = { 576struct smb_version_operations smb21_operations = {
559 .compare_fids = smb2_compare_fids, 577 .compare_fids = smb2_compare_fids,
560 .setup_request = smb2_setup_request, 578 .setup_request = smb2_setup_request,
@@ -616,6 +634,9 @@ struct smb_version_operations smb21_operations = {
616 .mand_lock = smb2_mand_lock, 634 .mand_lock = smb2_mand_lock,
617 .mand_unlock_range = smb2_unlock_range, 635 .mand_unlock_range = smb2_unlock_range,
618 .push_mand_locks = smb2_push_mandatory_locks, 636 .push_mand_locks = smb2_push_mandatory_locks,
637 .get_lease_key = smb2_get_lease_key,
638 .set_lease_key = smb2_set_lease_key,
639 .new_lease_key = smb2_new_lease_key,
619}; 640};
620 641
621struct smb_version_values smb21_values = { 642struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index d3e1cfca337..89d2824587b 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -304,7 +304,7 @@ free_rsp_buf(int resp_buftype, void *rsp)
304 cifs_buf_release(rsp); 304 cifs_buf_release(rsp);
305} 305}
306 306
307#define SMB2_NUM_PROT 1 307#define SMB2_NUM_PROT 2
308 308
309#define SMB2_PROT 0 309#define SMB2_PROT 0
310#define SMB21_PROT 1 310#define SMB21_PROT 1
@@ -393,6 +393,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
393 393
394 req->Capabilities = cpu_to_le32(SMB2_GLOBAL_CAP_DFS); 394 req->Capabilities = cpu_to_le32(SMB2_GLOBAL_CAP_DFS);
395 395
396 memcpy(req->ClientGUID, cifs_client_guid, SMB2_CLIENT_GUID_SIZE);
397
396 iov[0].iov_base = (char *)req; 398 iov[0].iov_base = (char *)req;
397 /* 4 for rfc1002 length field */ 399 /* 4 for rfc1002 length field */
398 iov[0].iov_len = get_rfc1002_length(req) + 4; 400 iov[0].iov_len = get_rfc1002_length(req) + 4;
@@ -868,6 +870,83 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
868 return rc; 870 return rc;
869} 871}
870 872
873static struct create_lease *
874create_lease_buf(u8 *lease_key, u8 oplock)
875{
876 struct create_lease *buf;
877
878 buf = kmalloc(sizeof(struct create_lease), GFP_KERNEL);
879 if (!buf)
880 return NULL;
881
882 memset(buf, 0, sizeof(struct create_lease));
883
884 buf->lcontext.LeaseKeyLow = cpu_to_le64(*((u64 *)lease_key));
885 buf->lcontext.LeaseKeyHigh = cpu_to_le64(*((u64 *)(lease_key + 8)));
886 if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE)
887 buf->lcontext.LeaseState = SMB2_LEASE_WRITE_CACHING |
888 SMB2_LEASE_READ_CACHING;
889 else if (oplock == SMB2_OPLOCK_LEVEL_II)
890 buf->lcontext.LeaseState = SMB2_LEASE_READ_CACHING;
891 else if (oplock == SMB2_OPLOCK_LEVEL_BATCH)
892 buf->lcontext.LeaseState = SMB2_LEASE_HANDLE_CACHING |
893 SMB2_LEASE_READ_CACHING |
894 SMB2_LEASE_WRITE_CACHING;
895
896 buf->ccontext.DataOffset = cpu_to_le16(offsetof
897 (struct create_lease, lcontext));
898 buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context));
899 buf->ccontext.NameOffset = cpu_to_le16(offsetof
900 (struct create_lease, Name));
901 buf->ccontext.NameLength = cpu_to_le16(4);
902 buf->Name[0] = 'R';
903 buf->Name[1] = 'q';
904 buf->Name[2] = 'L';
905 buf->Name[3] = 's';
906 return buf;
907}
908
909static __u8
910parse_lease_state(struct smb2_create_rsp *rsp)
911{
912 char *data_offset;
913 struct create_lease *lc;
914 __u8 oplock = 0;
915 bool found = false;
916
917 data_offset = (char *)rsp;
918 data_offset += 4 + le32_to_cpu(rsp->CreateContextsOffset);
919 lc = (struct create_lease *)data_offset;
920 do {
921 char *name = le16_to_cpu(lc->ccontext.NameOffset) + (char *)lc;
922 if (le16_to_cpu(lc->ccontext.NameLength) != 4 ||
923 strncmp(name, "RqLs", 4)) {
924 lc = (struct create_lease *)((char *)lc
925 + le32_to_cpu(lc->ccontext.Next));
926 continue;
927 }
928 if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS)
929 return SMB2_OPLOCK_LEVEL_NOCHANGE;
930 found = true;
931 break;
932 } while (le32_to_cpu(lc->ccontext.Next) != 0);
933
934 if (!found)
935 return oplock;
936
937 if (le32_to_cpu(lc->lcontext.LeaseState) & SMB2_LEASE_WRITE_CACHING) {
938 if (le32_to_cpu(lc->lcontext.LeaseState) &
939 SMB2_LEASE_HANDLE_CACHING)
940 oplock = SMB2_OPLOCK_LEVEL_BATCH;
941 else
942 oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
943 } else if (le32_to_cpu(lc->lcontext.LeaseState) &
944 SMB2_LEASE_READ_CACHING)
945 oplock = SMB2_OPLOCK_LEVEL_II;
946
947 return oplock;
948}
949
871int 950int
872SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path, 951SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
873 u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access, 952 u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access,
@@ -878,9 +957,11 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
878 struct smb2_create_rsp *rsp; 957 struct smb2_create_rsp *rsp;
879 struct TCP_Server_Info *server; 958 struct TCP_Server_Info *server;
880 struct cifs_ses *ses = tcon->ses; 959 struct cifs_ses *ses = tcon->ses;
881 struct kvec iov[2]; 960 struct kvec iov[3];
882 int resp_buftype; 961 int resp_buftype;
883 int uni_path_len; 962 int uni_path_len;
963 __le16 *copy_path = NULL;
964 int copy_size;
884 int rc = 0; 965 int rc = 0;
885 int num_iovecs = 2; 966 int num_iovecs = 2;
886 967
@@ -895,10 +976,6 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
895 if (rc) 976 if (rc)
896 return rc; 977 return rc;
897 978
898 if (server->oplocks)
899 req->RequestedOplockLevel = *oplock;
900 else
901 req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
902 req->ImpersonationLevel = IL_IMPERSONATION; 979 req->ImpersonationLevel = IL_IMPERSONATION;
903 req->DesiredAccess = cpu_to_le32(desired_access); 980 req->DesiredAccess = cpu_to_le32(desired_access);
904 /* File attributes ignored on open (used in create though) */ 981 /* File attributes ignored on open (used in create though) */
@@ -908,7 +985,7 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
908 req->CreateOptions = cpu_to_le32(create_options); 985 req->CreateOptions = cpu_to_le32(create_options);
909 uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2; 986 uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2;
910 req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req) 987 req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req)
911 - 1 /* pad */ - 4 /* do not count rfc1001 len field */); 988 - 8 /* pad */ - 4 /* do not count rfc1001 len field */);
912 989
913 iov[0].iov_base = (char *)req; 990 iov[0].iov_base = (char *)req;
914 /* 4 for rfc1002 length field */ 991 /* 4 for rfc1002 length field */
@@ -919,6 +996,20 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
919 req->NameLength = cpu_to_le16(uni_path_len - 2); 996 req->NameLength = cpu_to_le16(uni_path_len - 2);
920 /* -1 since last byte is buf[0] which is sent below (path) */ 997 /* -1 since last byte is buf[0] which is sent below (path) */
921 iov[0].iov_len--; 998 iov[0].iov_len--;
999 if (uni_path_len % 8 != 0) {
1000 copy_size = uni_path_len / 8 * 8;
1001 if (copy_size < uni_path_len)
1002 copy_size += 8;
1003
1004 copy_path = kzalloc(copy_size, GFP_KERNEL);
1005 if (!copy_path)
1006 return -ENOMEM;
1007 memcpy((char *)copy_path, (const char *)path,
1008 uni_path_len);
1009 uni_path_len = copy_size;
1010 path = copy_path;
1011 }
1012
922 iov[1].iov_len = uni_path_len; 1013 iov[1].iov_len = uni_path_len;
923 iov[1].iov_base = path; 1014 iov[1].iov_base = path;
924 /* 1015 /*
@@ -927,10 +1018,37 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
927 */ 1018 */
928 inc_rfc1001_len(req, uni_path_len - 1); 1019 inc_rfc1001_len(req, uni_path_len - 1);
929 } else { 1020 } else {
1021 iov[0].iov_len += 7;
1022 req->hdr.smb2_buf_length = cpu_to_be32(be32_to_cpu(
1023 req->hdr.smb2_buf_length) + 8 - 1);
930 num_iovecs = 1; 1024 num_iovecs = 1;
931 req->NameLength = 0; 1025 req->NameLength = 0;
932 } 1026 }
933 1027
1028 if (!server->oplocks)
1029 *oplock = SMB2_OPLOCK_LEVEL_NONE;
1030
1031 if (!(tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING) ||
1032 *oplock == SMB2_OPLOCK_LEVEL_NONE)
1033 req->RequestedOplockLevel = *oplock;
1034 else {
1035 iov[num_iovecs].iov_base = create_lease_buf(oplock+1, *oplock);
1036 if (iov[num_iovecs].iov_base == NULL) {
1037 cifs_small_buf_release(req);
1038 kfree(copy_path);
1039 return -ENOMEM;
1040 }
1041 iov[num_iovecs].iov_len = sizeof(struct create_lease);
1042 req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_LEASE;
1043 req->CreateContextsOffset = cpu_to_le32(
1044 sizeof(struct smb2_create_req) - 4 - 8 +
1045 iov[num_iovecs-1].iov_len);
1046 req->CreateContextsLength = cpu_to_le32(
1047 sizeof(struct create_lease));
1048 inc_rfc1001_len(&req->hdr, sizeof(struct create_lease));
1049 num_iovecs++;
1050 }
1051
934 rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0); 1052 rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0);
935 rsp = (struct smb2_create_rsp *)iov[0].iov_base; 1053 rsp = (struct smb2_create_rsp *)iov[0].iov_base;
936 1054
@@ -955,8 +1073,12 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
955 buf->DeletePending = 0; 1073 buf->DeletePending = 0;
956 } 1074 }
957 1075
958 *oplock = rsp->OplockLevel; 1076 if (rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE)
1077 *oplock = parse_lease_state(rsp);
1078 else
1079 *oplock = rsp->OplockLevel;
959creat_exit: 1080creat_exit:
1081 kfree(copy_path);
960 free_rsp_buf(resp_buftype, rsp); 1082 free_rsp_buf(resp_buftype, rsp);
961 return rc; 1083 return rc;
962} 1084}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 889ee5e193d..e818a5cc5bd 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -150,6 +150,10 @@ struct smb2_err_rsp {
150 __u8 ErrorData[1]; /* variable length */ 150 __u8 ErrorData[1]; /* variable length */
151} __packed; 151} __packed;
152 152
153#define SMB2_CLIENT_GUID_SIZE 16
154
155extern __u8 cifs_client_guid[SMB2_CLIENT_GUID_SIZE];
156
153struct smb2_negotiate_req { 157struct smb2_negotiate_req {
154 struct smb2_hdr hdr; 158 struct smb2_hdr hdr;
155 __le16 StructureSize; /* Must be 36 */ 159 __le16 StructureSize; /* Must be 36 */
@@ -157,7 +161,7 @@ struct smb2_negotiate_req {
157 __le16 SecurityMode; 161 __le16 SecurityMode;
158 __le16 Reserved; /* MBZ */ 162 __le16 Reserved; /* MBZ */
159 __le32 Capabilities; 163 __le32 Capabilities;
160 __u8 ClientGUID[16]; /* MBZ */ 164 __u8 ClientGUID[SMB2_CLIENT_GUID_SIZE];
161 __le64 ClientStartTime; /* MBZ */ 165 __le64 ClientStartTime; /* MBZ */
162 __le16 Dialects[2]; /* variable length */ 166 __le16 Dialects[2]; /* variable length */
163} __packed; 167} __packed;
@@ -307,6 +311,8 @@ struct smb2_tree_disconnect_rsp {
307#define SMB2_OPLOCK_LEVEL_EXCLUSIVE 0x08 311#define SMB2_OPLOCK_LEVEL_EXCLUSIVE 0x08
308#define SMB2_OPLOCK_LEVEL_BATCH 0x09 312#define SMB2_OPLOCK_LEVEL_BATCH 0x09
309#define SMB2_OPLOCK_LEVEL_LEASE 0xFF 313#define SMB2_OPLOCK_LEVEL_LEASE 0xFF
314/* Non-spec internal type */
315#define SMB2_OPLOCK_LEVEL_NOCHANGE 0x99
310 316
311/* Desired Access Flags */ 317/* Desired Access Flags */
312#define FILE_READ_DATA_LE cpu_to_le32(0x00000001) 318#define FILE_READ_DATA_LE cpu_to_le32(0x00000001)
@@ -404,7 +410,7 @@ struct smb2_create_req {
404 __le16 NameLength; 410 __le16 NameLength;
405 __le32 CreateContextsOffset; 411 __le32 CreateContextsOffset;
406 __le32 CreateContextsLength; 412 __le32 CreateContextsLength;
407 __u8 Buffer[1]; 413 __u8 Buffer[8];
408} __packed; 414} __packed;
409 415
410struct smb2_create_rsp { 416struct smb2_create_rsp {
@@ -428,6 +434,39 @@ struct smb2_create_rsp {
428 __u8 Buffer[1]; 434 __u8 Buffer[1];
429} __packed; 435} __packed;
430 436
437struct create_context {
438 __le32 Next;
439 __le16 NameOffset;
440 __le16 NameLength;
441 __le16 Reserved;
442 __le16 DataOffset;
443 __le32 DataLength;
444 __u8 Buffer[0];
445} __packed;
446
447#define SMB2_LEASE_NONE __constant_cpu_to_le32(0x00)
448#define SMB2_LEASE_READ_CACHING __constant_cpu_to_le32(0x01)
449#define SMB2_LEASE_HANDLE_CACHING __constant_cpu_to_le32(0x02)
450#define SMB2_LEASE_WRITE_CACHING __constant_cpu_to_le32(0x04)
451
452#define SMB2_LEASE_FLAG_BREAK_IN_PROGRESS __constant_cpu_to_le32(0x02)
453
454#define SMB2_LEASE_KEY_SIZE 16
455
456struct lease_context {
457 __le64 LeaseKeyLow;
458 __le64 LeaseKeyHigh;
459 __le32 LeaseState;
460 __le32 LeaseFlags;
461 __le64 LeaseDuration;
462} __packed;
463
464struct create_lease {
465 struct create_context ccontext;
466 __u8 Name[8];
467 struct lease_context lcontext;
468} __packed;
469
431/* Currently defined values for close flags */ 470/* Currently defined values for close flags */
432#define SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB cpu_to_le16(0x0001) 471#define SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB cpu_to_le16(0x0001)
433struct smb2_close_req { 472struct smb2_close_req {