aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifsglob.h1
-rw-r--r--fs/cifs/dir.c1
-rw-r--r--fs/cifs/file.c15
-rw-r--r--fs/cifs/smb2file.c3
-rw-r--r--fs/cifs/smb2inode.c1
-rw-r--r--fs/cifs/smb2ops.c3
-rw-r--r--fs/cifs/smb2pdu.c38
-rw-r--r--fs/cifs/smb2pdu.h8
8 files changed, 58 insertions, 12 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 982fdf92c791..1fdc37041057 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -920,6 +920,7 @@ struct cifs_open_parms {
920 int create_options; 920 int create_options;
921 const char *path; 921 const char *path;
922 struct cifs_fid *fid; 922 struct cifs_fid *fid;
923 bool reconnect:1;
923}; 924};
924 925
925struct cifs_fid { 926struct cifs_fid {
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index c27c242ac5ba..d62ce0d48141 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -327,6 +327,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
327 oparms.disposition = disposition; 327 oparms.disposition = disposition;
328 oparms.path = full_path; 328 oparms.path = full_path;
329 oparms.fid = fid; 329 oparms.fid = fid;
330 oparms.reconnect = false;
330 331
331 rc = server->ops->open(xid, &oparms, oplock, buf); 332 rc = server->ops->open(xid, &oparms, oplock, buf);
332 if (rc) { 333 if (rc) {
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index f36f9a7893da..ba7eed2ee662 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -232,6 +232,7 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
232 oparms.disposition = disposition; 232 oparms.disposition = disposition;
233 oparms.path = full_path; 233 oparms.path = full_path;
234 oparms.fid = fid; 234 oparms.fid = fid;
235 oparms.reconnect = false;
235 236
236 rc = server->ops->open(xid, &oparms, oplock, buf); 237 rc = server->ops->open(xid, &oparms, oplock, buf);
237 238
@@ -594,7 +595,6 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
594 int desired_access; 595 int desired_access;
595 int disposition = FILE_OPEN; 596 int disposition = FILE_OPEN;
596 int create_options = CREATE_NOT_DIR; 597 int create_options = CREATE_NOT_DIR;
597 struct cifs_fid fid;
598 struct cifs_open_parms oparms; 598 struct cifs_open_parms oparms;
599 599
600 xid = get_xid(); 600 xid = get_xid();
@@ -645,7 +645,7 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
645 645
646 rc = cifs_posix_open(full_path, NULL, inode->i_sb, 646 rc = cifs_posix_open(full_path, NULL, inode->i_sb,
647 cifs_sb->mnt_file_mode /* ignored */, 647 cifs_sb->mnt_file_mode /* ignored */,
648 oflags, &oplock, &fid.netfid, xid); 648 oflags, &oplock, &cfile->fid.netfid, xid);
649 if (rc == 0) { 649 if (rc == 0) {
650 cifs_dbg(FYI, "posix reopen succeeded\n"); 650 cifs_dbg(FYI, "posix reopen succeeded\n");
651 goto reopen_success; 651 goto reopen_success;
@@ -662,7 +662,7 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
662 create_options |= CREATE_OPEN_BACKUP_INTENT; 662 create_options |= CREATE_OPEN_BACKUP_INTENT;
663 663
664 if (server->ops->get_lease_key) 664 if (server->ops->get_lease_key)
665 server->ops->get_lease_key(inode, &fid); 665 server->ops->get_lease_key(inode, &cfile->fid);
666 666
667 oparms.tcon = tcon; 667 oparms.tcon = tcon;
668 oparms.cifs_sb = cifs_sb; 668 oparms.cifs_sb = cifs_sb;
@@ -670,7 +670,8 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
670 oparms.create_options = create_options; 670 oparms.create_options = create_options;
671 oparms.disposition = disposition; 671 oparms.disposition = disposition;
672 oparms.path = full_path; 672 oparms.path = full_path;
673 oparms.fid = &fid; 673 oparms.fid = &cfile->fid;
674 oparms.reconnect = true;
674 675
675 /* 676 /*
676 * Can not refresh inode by passing in file_info buf to be returned by 677 * Can not refresh inode by passing in file_info buf to be returned by
@@ -710,8 +711,9 @@ reopen_success:
710 * to the server to get the new inode info. 711 * to the server to get the new inode info.
711 */ 712 */
712 713
713 server->ops->set_fid(cfile, &fid, oplock); 714 server->ops->set_fid(cfile, &cfile->fid, oplock);
714 cifs_relock_file(cfile); 715 if (oparms.reconnect)
716 cifs_relock_file(cfile);
715 717
716reopen_error_exit: 718reopen_error_exit:
717 kfree(full_path); 719 kfree(full_path);
@@ -1508,6 +1510,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
1508 if (!rc) 1510 if (!rc)
1509 goto out; 1511 goto out;
1510 1512
1513
1511 /* 1514 /*
1512 * Windows 7 server can delay breaking lease from read to None 1515 * Windows 7 server can delay breaking lease from read to None
1513 * if we set a byte-range lock on a file - break it explicitly 1516 * if we set a byte-range lock on a file - break it explicitly
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index 398992962cc6..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",
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 9841df771f08..c6ec1633309a 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -58,6 +58,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
58 oparms.disposition = create_disposition; 58 oparms.disposition = create_disposition;
59 oparms.create_options = create_options; 59 oparms.create_options = create_options;
60 oparms.fid = &fid; 60 oparms.fid = &fid;
61 oparms.reconnect = false;
61 62
62 rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL); 63 rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL);
63 if (rc) { 64 if (rc) {
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 1bc7d7e64cf5..f259e6cc8357 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -227,6 +227,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
227 oparms.disposition = FILE_OPEN; 227 oparms.disposition = FILE_OPEN;
228 oparms.create_options = 0; 228 oparms.create_options = 0;
229 oparms.fid = &fid; 229 oparms.fid = &fid;
230 oparms.reconnect = false;
230 231
231 rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL); 232 rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL);
232 if (rc) { 233 if (rc) {
@@ -460,6 +461,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
460 oparms.disposition = FILE_OPEN; 461 oparms.disposition = FILE_OPEN;
461 oparms.create_options = 0; 462 oparms.create_options = 0;
462 oparms.fid = fid; 463 oparms.fid = fid;
464 oparms.reconnect = false;
463 465
464 rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL); 466 rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL);
465 kfree(utf16_path); 467 kfree(utf16_path);
@@ -546,6 +548,7 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
546 oparms.disposition = FILE_OPEN; 548 oparms.disposition = FILE_OPEN;
547 oparms.create_options = 0; 549 oparms.create_options = 0;
548 oparms.fid = &fid; 550 oparms.fid = &fid;
551 oparms.reconnect = false;
549 552
550 rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL); 553 rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL);
551 if (rc) 554 if (rc)
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 9d7341d696fc..c7ad06fc9d63 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -857,7 +857,7 @@ create_durable_buf(void)
857 return NULL; 857 return NULL;
858 858
859 buf->ccontext.DataOffset = cpu_to_le16(offsetof 859 buf->ccontext.DataOffset = cpu_to_le16(offsetof
860 (struct create_durable, Reserved)); 860 (struct create_durable, Data));
861 buf->ccontext.DataLength = cpu_to_le32(16); 861 buf->ccontext.DataLength = cpu_to_le32(16);
862 buf->ccontext.NameOffset = cpu_to_le16(offsetof 862 buf->ccontext.NameOffset = cpu_to_le16(offsetof
863 (struct create_durable, Name)); 863 (struct create_durable, Name));
@@ -869,6 +869,30 @@ create_durable_buf(void)
869 return buf; 869 return buf;
870} 870}
871 871
872static struct create_durable *
873create_reconnect_durable_buf(struct cifs_fid *fid)
874{
875 struct create_durable *buf;
876
877 buf = kzalloc(sizeof(struct create_durable), GFP_KERNEL);
878 if (!buf)
879 return NULL;
880
881 buf->ccontext.DataOffset = cpu_to_le16(offsetof
882 (struct create_durable, Data));
883 buf->ccontext.DataLength = cpu_to_le32(16);
884 buf->ccontext.NameOffset = cpu_to_le16(offsetof
885 (struct create_durable, Name));
886 buf->ccontext.NameLength = cpu_to_le16(4);
887 buf->Data.Fid.PersistentFileId = fid->persistent_fid;
888 buf->Data.Fid.VolatileFileId = fid->volatile_fid;
889 buf->Name[0] = 'D';
890 buf->Name[1] = 'H';
891 buf->Name[2] = 'n';
892 buf->Name[3] = 'C';
893 return buf;
894}
895
872static __u8 896static __u8
873parse_lease_state(struct smb2_create_rsp *rsp) 897parse_lease_state(struct smb2_create_rsp *rsp)
874{ 898{
@@ -924,12 +948,18 @@ add_lease_context(struct kvec *iov, unsigned int *num_iovec, __u8 *oplock)
924} 948}
925 949
926static int 950static int
927add_durable_context(struct kvec *iov, unsigned int *num_iovec) 951add_durable_context(struct kvec *iov, unsigned int *num_iovec,
952 struct cifs_open_parms *oparms)
928{ 953{
929 struct smb2_create_req *req = iov[0].iov_base; 954 struct smb2_create_req *req = iov[0].iov_base;
930 unsigned int num = *num_iovec; 955 unsigned int num = *num_iovec;
931 956
932 iov[num].iov_base = create_durable_buf(); 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();
933 if (iov[num].iov_base == NULL) 963 if (iov[num].iov_base == NULL)
934 return -ENOMEM; 964 return -ENOMEM;
935 iov[num].iov_len = sizeof(struct create_durable); 965 iov[num].iov_len = sizeof(struct create_durable);
@@ -1037,7 +1067,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
1037 (struct create_context *)iov[num_iovecs-1].iov_base; 1067 (struct create_context *)iov[num_iovecs-1].iov_base;
1038 ccontext->Next = sizeof(struct create_lease); 1068 ccontext->Next = sizeof(struct create_lease);
1039 } 1069 }
1040 rc = add_durable_context(iov, &num_iovecs); 1070 rc = add_durable_context(iov, &num_iovecs, oparms);
1041 if (rc) { 1071 if (rc) {
1042 cifs_small_buf_release(req); 1072 cifs_small_buf_release(req);
1043 kfree(copy_path); 1073 kfree(copy_path);
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 3e30f0ad5749..36b0d37ea69b 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -488,7 +488,13 @@ struct create_lease {
488struct create_durable { 488struct create_durable {
489 struct create_context ccontext; 489 struct create_context ccontext;
490 __u8 Name[8]; 490 __u8 Name[8];
491 __u8 Reserved[16]; 491 union {
492 __u8 Reserved[16];
493 struct {
494 __u64 PersistentFileId;
495 __u64 VolatileFileId;
496 } Fid;
497 } Data;
492} __packed; 498} __packed;
493 499
494/* this goes in the ioctl buffer when doing a copychunk request */ 500/* this goes in the ioctl buffer when doing a copychunk request */