aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifsfs.c11
-rw-r--r--fs/cifs/cifsfs.h2
-rw-r--r--fs/cifs/inode.c16
-rw-r--r--fs/cifs/smb2file.c18
-rw-r--r--fs/cifs/smb2ops.c53
-rw-r--r--fs/cifs/smb2pdu.c46
-rw-r--r--fs/cifs/smb2pdu.h4
-rw-r--r--fs/cifs/smb2proto.h7
8 files changed, 126 insertions, 31 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 270d3c58fb3b..3289b566463f 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -1104,6 +1104,10 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
1104 goto out; 1104 goto out;
1105 } 1105 }
1106 1106
1107 rc = -EOPNOTSUPP;
1108 if (!target_tcon->ses->server->ops->copychunk_range)
1109 goto out;
1110
1107 /* 1111 /*
1108 * Note: cifs case is easier than btrfs since server responsible for 1112 * Note: cifs case is easier than btrfs since server responsible for
1109 * checks for proper open modes and file type and if it wants 1113 * checks for proper open modes and file type and if it wants
@@ -1115,11 +1119,12 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
1115 /* should we flush first and last page first */ 1119 /* should we flush first and last page first */
1116 truncate_inode_pages(&target_inode->i_data, 0); 1120 truncate_inode_pages(&target_inode->i_data, 0);
1117 1121
1118 if (target_tcon->ses->server->ops->copychunk_range) 1122 rc = file_modified(dst_file);
1123 if (!rc)
1119 rc = target_tcon->ses->server->ops->copychunk_range(xid, 1124 rc = target_tcon->ses->server->ops->copychunk_range(xid,
1120 smb_file_src, smb_file_target, off, len, destoff); 1125 smb_file_src, smb_file_target, off, len, destoff);
1121 else 1126
1122 rc = -EOPNOTSUPP; 1127 file_accessed(src_file);
1123 1128
1124 /* force revalidate of size and timestamps of target file now 1129 /* force revalidate of size and timestamps of target file now
1125 * that target is updated on the server 1130 * that target is updated on the server
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index aea005703785..4b21a90015a9 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -152,5 +152,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
152extern const struct export_operations cifs_export_ops; 152extern const struct export_operations cifs_export_ops;
153#endif /* CONFIG_CIFS_NFSD_EXPORT */ 153#endif /* CONFIG_CIFS_NFSD_EXPORT */
154 154
155#define CIFS_VERSION "2.20" 155#define CIFS_VERSION "2.21"
156#endif /* _CIFSFS_H */ 156#endif /* _CIFSFS_H */
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 1bffe029fb66..56ca4b8ccaba 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -2406,6 +2406,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
2406 struct inode *inode = d_inode(direntry); 2406 struct inode *inode = d_inode(direntry);
2407 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 2407 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
2408 struct cifsInodeInfo *cifsInode = CIFS_I(inode); 2408 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
2409 struct cifsFileInfo *wfile;
2410 struct cifs_tcon *tcon;
2409 char *full_path = NULL; 2411 char *full_path = NULL;
2410 int rc = -EACCES; 2412 int rc = -EACCES;
2411 __u32 dosattr = 0; 2413 __u32 dosattr = 0;
@@ -2452,6 +2454,20 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
2452 mapping_set_error(inode->i_mapping, rc); 2454 mapping_set_error(inode->i_mapping, rc);
2453 rc = 0; 2455 rc = 0;
2454 2456
2457 if (attrs->ia_valid & ATTR_MTIME) {
2458 rc = cifs_get_writable_file(cifsInode, false, &wfile);
2459 if (!rc) {
2460 tcon = tlink_tcon(wfile->tlink);
2461 rc = tcon->ses->server->ops->flush(xid, tcon, &wfile->fid);
2462 cifsFileInfo_put(wfile);
2463 if (rc)
2464 return rc;
2465 } else if (rc != -EBADF)
2466 return rc;
2467 else
2468 rc = 0;
2469 }
2470
2455 if (attrs->ia_valid & ATTR_SIZE) { 2471 if (attrs->ia_valid & ATTR_SIZE) {
2456 rc = cifs_set_file_size(inode, attrs, xid, full_path); 2472 rc = cifs_set_file_size(inode, attrs, xid, full_path);
2457 if (rc != 0) 2473 if (rc != 0)
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index 54bffb2a1786..e6a1fc72018f 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -88,14 +88,20 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
88 } 88 }
89 89
90 if (buf) { 90 if (buf) {
91 /* open response does not have IndexNumber field - get it */ 91 /* if open response does not have IndexNumber field - get it */
92 rc = SMB2_get_srv_num(xid, oparms->tcon, fid->persistent_fid, 92 if (smb2_data->IndexNumber == 0) {
93 rc = SMB2_get_srv_num(xid, oparms->tcon,
94 fid->persistent_fid,
93 fid->volatile_fid, 95 fid->volatile_fid,
94 &smb2_data->IndexNumber); 96 &smb2_data->IndexNumber);
95 if (rc) { 97 if (rc) {
96 /* let get_inode_info disable server inode numbers */ 98 /*
97 smb2_data->IndexNumber = 0; 99 * let get_inode_info disable server inode
98 rc = 0; 100 * numbers
101 */
102 smb2_data->IndexNumber = 0;
103 rc = 0;
104 }
99 } 105 }
100 move_smb2_info_to_cifs(buf, smb2_data); 106 move_smb2_info_to_cifs(buf, smb2_data);
101 } 107 }
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 0cdc4e47ca87..a5bc1b671c12 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -694,8 +694,51 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
694 694
695 smb2_set_related(&rqst[1]); 695 smb2_set_related(&rqst[1]);
696 696
697 /*
698 * We do not hold the lock for the open because in case
699 * SMB2_open needs to reconnect, it will end up calling
700 * cifs_mark_open_files_invalid() which takes the lock again
701 * thus causing a deadlock
702 */
703
704 mutex_unlock(&tcon->crfid.fid_mutex);
697 rc = compound_send_recv(xid, ses, flags, 2, rqst, 705 rc = compound_send_recv(xid, ses, flags, 2, rqst,
698 resp_buftype, rsp_iov); 706 resp_buftype, rsp_iov);
707 mutex_lock(&tcon->crfid.fid_mutex);
708
709 /*
710 * Now we need to check again as the cached root might have
711 * been successfully re-opened from a concurrent process
712 */
713
714 if (tcon->crfid.is_valid) {
715 /* work was already done */
716
717 /* stash fids for close() later */
718 struct cifs_fid fid = {
719 .persistent_fid = pfid->persistent_fid,
720 .volatile_fid = pfid->volatile_fid,
721 };
722
723 /*
724 * caller expects this func to set pfid to a valid
725 * cached root, so we copy the existing one and get a
726 * reference.
727 */
728 memcpy(pfid, tcon->crfid.fid, sizeof(*pfid));
729 kref_get(&tcon->crfid.refcount);
730
731 mutex_unlock(&tcon->crfid.fid_mutex);
732
733 if (rc == 0) {
734 /* close extra handle outside of crit sec */
735 SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
736 }
737 goto oshr_free;
738 }
739
740 /* Cached root is still invalid, continue normaly */
741
699 if (rc) 742 if (rc)
700 goto oshr_exit; 743 goto oshr_exit;
701 744
@@ -711,11 +754,12 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
711 tcon->crfid.is_valid = true; 754 tcon->crfid.is_valid = true;
712 kref_init(&tcon->crfid.refcount); 755 kref_init(&tcon->crfid.refcount);
713 756
757 /* BB TBD check to see if oplock level check can be removed below */
714 if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) { 758 if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) {
715 kref_get(&tcon->crfid.refcount); 759 kref_get(&tcon->crfid.refcount);
716 oplock = smb2_parse_lease_state(server, o_rsp, 760 smb2_parse_contexts(server, o_rsp,
717 &oparms.fid->epoch, 761 &oparms.fid->epoch,
718 oparms.fid->lease_key); 762 oparms.fid->lease_key, &oplock, NULL);
719 } else 763 } else
720 goto oshr_exit; 764 goto oshr_exit;
721 765
@@ -729,8 +773,9 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
729 (char *)&tcon->crfid.file_all_info)) 773 (char *)&tcon->crfid.file_all_info))
730 tcon->crfid.file_all_info_is_valid = 1; 774 tcon->crfid.file_all_info_is_valid = 1;
731 775
732 oshr_exit: 776oshr_exit:
733 mutex_unlock(&tcon->crfid.fid_mutex); 777 mutex_unlock(&tcon->crfid.fid_mutex);
778oshr_free:
734 SMB2_open_free(&rqst[0]); 779 SMB2_open_free(&rqst[0]);
735 SMB2_query_info_free(&rqst[1]); 780 SMB2_query_info_free(&rqst[1]);
736 free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); 781 free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index f58e4dc3987b..c8cd7b6cdda2 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1873,10 +1873,21 @@ create_reconnect_durable_buf(struct cifs_fid *fid)
1873 return buf; 1873 return buf;
1874} 1874}
1875 1875
1876__u8 1876static void
1877smb2_parse_lease_state(struct TCP_Server_Info *server, 1877parse_query_id_ctxt(struct create_context *cc, struct smb2_file_all_info *buf)
1878{
1879 struct create_on_disk_id *pdisk_id = (struct create_on_disk_id *)cc;
1880
1881 cifs_dbg(FYI, "parse query id context 0x%llx 0x%llx\n",
1882 pdisk_id->DiskFileId, pdisk_id->VolumeId);
1883 buf->IndexNumber = pdisk_id->DiskFileId;
1884}
1885
1886void
1887smb2_parse_contexts(struct TCP_Server_Info *server,
1878 struct smb2_create_rsp *rsp, 1888 struct smb2_create_rsp *rsp,
1879 unsigned int *epoch, char *lease_key) 1889 unsigned int *epoch, char *lease_key, __u8 *oplock,
1890 struct smb2_file_all_info *buf)
1880{ 1891{
1881 char *data_offset; 1892 char *data_offset;
1882 struct create_context *cc; 1893 struct create_context *cc;
@@ -1884,15 +1895,24 @@ smb2_parse_lease_state(struct TCP_Server_Info *server,
1884 unsigned int remaining; 1895 unsigned int remaining;
1885 char *name; 1896 char *name;
1886 1897
1898 *oplock = 0;
1887 data_offset = (char *)rsp + le32_to_cpu(rsp->CreateContextsOffset); 1899 data_offset = (char *)rsp + le32_to_cpu(rsp->CreateContextsOffset);
1888 remaining = le32_to_cpu(rsp->CreateContextsLength); 1900 remaining = le32_to_cpu(rsp->CreateContextsLength);
1889 cc = (struct create_context *)data_offset; 1901 cc = (struct create_context *)data_offset;
1902
1903 /* Initialize inode number to 0 in case no valid data in qfid context */
1904 if (buf)
1905 buf->IndexNumber = 0;
1906
1890 while (remaining >= sizeof(struct create_context)) { 1907 while (remaining >= sizeof(struct create_context)) {
1891 name = le16_to_cpu(cc->NameOffset) + (char *)cc; 1908 name = le16_to_cpu(cc->NameOffset) + (char *)cc;
1892 if (le16_to_cpu(cc->NameLength) == 4 && 1909 if (le16_to_cpu(cc->NameLength) == 4 &&
1893 strncmp(name, "RqLs", 4) == 0) 1910 strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4) == 0)
1894 return server->ops->parse_lease_buf(cc, epoch, 1911 *oplock = server->ops->parse_lease_buf(cc, epoch,
1895 lease_key); 1912 lease_key);
1913 else if (buf && (le16_to_cpu(cc->NameLength) == 4) &&
1914 strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 4) == 0)
1915 parse_query_id_ctxt(cc, buf);
1896 1916
1897 next = le32_to_cpu(cc->Next); 1917 next = le32_to_cpu(cc->Next);
1898 if (!next) 1918 if (!next)
@@ -1901,7 +1921,10 @@ smb2_parse_lease_state(struct TCP_Server_Info *server,
1901 cc = (struct create_context *)((char *)cc + next); 1921 cc = (struct create_context *)((char *)cc + next);
1902 } 1922 }
1903 1923
1904 return 0; 1924 if (rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE)
1925 *oplock = rsp->OplockLevel;
1926
1927 return;
1905} 1928}
1906 1929
1907static int 1930static int
@@ -2588,12 +2611,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
2588 buf->DeletePending = 0; 2611 buf->DeletePending = 0;
2589 } 2612 }
2590 2613
2591 if (rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) 2614
2592 *oplock = smb2_parse_lease_state(server, rsp, 2615 smb2_parse_contexts(server, rsp, &oparms->fid->epoch,
2593 &oparms->fid->epoch, 2616 oparms->fid->lease_key, oplock, buf);
2594 oparms->fid->lease_key);
2595 else
2596 *oplock = rsp->OplockLevel;
2597creat_exit: 2617creat_exit:
2598 SMB2_open_free(&rqst); 2618 SMB2_open_free(&rqst);
2599 free_rsp_buf(resp_buftype, rsp); 2619 free_rsp_buf(resp_buftype, rsp);
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 7e2e782f8edd..747de9317659 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -818,7 +818,9 @@ struct durable_reconnect_context_v2 {
818} __packed; 818} __packed;
819 819
820/* See MS-SMB2 2.2.14.2.9 */ 820/* See MS-SMB2 2.2.14.2.9 */
821struct on_disk_id { 821struct create_on_disk_id {
822 struct create_context ccontext;
823 __u8 Name[8];
822 __le64 DiskFileId; 824 __le64 DiskFileId;
823 __le64 VolumeId; 825 __le64 VolumeId;
824 __u32 Reserved[4]; 826 __u32 Reserved[4];
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 52df125e9189..07ca72486cfa 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -228,9 +228,10 @@ extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *);
228 228
229extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *, 229extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
230 enum securityEnum); 230 enum securityEnum);
231extern __u8 smb2_parse_lease_state(struct TCP_Server_Info *server, 231extern void smb2_parse_contexts(struct TCP_Server_Info *server,
232 struct smb2_create_rsp *rsp, 232 struct smb2_create_rsp *rsp,
233 unsigned int *epoch, char *lease_key); 233 unsigned int *epoch, char *lease_key,
234 __u8 *oplock, struct smb2_file_all_info *buf);
234extern int smb3_encryption_required(const struct cifs_tcon *tcon); 235extern int smb3_encryption_required(const struct cifs_tcon *tcon);
235extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length, 236extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
236 struct kvec *iov, unsigned int min_buf_size); 237 struct kvec *iov, unsigned int min_buf_size);