diff options
-rw-r--r-- | fs/cifs/cifsglob.h | 1 | ||||
-rw-r--r-- | fs/cifs/dir.c | 1 | ||||
-rw-r--r-- | fs/cifs/file.c | 15 | ||||
-rw-r--r-- | fs/cifs/smb2file.c | 3 | ||||
-rw-r--r-- | fs/cifs/smb2inode.c | 1 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 3 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 38 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.h | 8 |
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 | ||
925 | struct cifs_fid { | 926 | struct 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 | ||
716 | reopen_error_exit: | 718 | reopen_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 | ||
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 | |||
872 | static __u8 | 896 | static __u8 |
873 | parse_lease_state(struct smb2_create_rsp *rsp) | 897 | parse_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 | ||
926 | static int | 950 | static int |
927 | add_durable_context(struct kvec *iov, unsigned int *num_iovec) | 951 | add_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 { | |||
488 | struct create_durable { | 488 | struct 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 */ |