Pull cifs fixes from Steve French: "Two fixes for stable, one that had dependency on earlier patch in this merge window and can now go in, and a perf improvement in SMB3 open" * tag '5.3-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: update internal module number cifs: flush before set-info if we have writeable handles smb3: optimize open to not send query file internal info cifs: copy_file_range needs to strip setuid bits and update timestamps CIFS: fix deadlock in cached root handling
Unified · Split
| @@ -1104,6 +1104,10 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, · 1103 unmodified lines | |||
| 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, · 5 unmodified lines | |||
| 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 |
| @@ -152,5 +152,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); · 151 unmodified lines | |||
| 152 | extern const struct export_operations cifs_export_ops; | 152 | extern 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 */ |
| @@ -2406,6 +2406,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) · 2405 unmodified lines | |||
| 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) · 40 unmodified lines | |||
| 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) |
| @@ -88,14 +88,20 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, · 87 unmodified lines | |||
| 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 | } |
| @@ -694,8 +694,51 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid) · 693 unmodified lines | |||
| 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) · 9 unmodified lines | |||
| 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) · 7 unmodified lines | |||
| 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: | 776 | oshr_exit: |
| 733 | mutex_unlock(&tcon->crfid.fid_mutex); | 777 | mutex_unlock(&tcon->crfid.fid_mutex); |
| 778 | oshr_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); |
| @@ -1873,10 +1873,21 @@ create_reconnect_durable_buf(struct cifs_fid *fid) · 1872 unmodified lines | |||
| 1873 | return buf; | 1873 | return buf; |
| 1874 | } | 1874 | } |
| 1875 | 1875 | ||
| 1876 | __u8 | 1876 | static void |
| 1877 | smb2_parse_lease_state(struct TCP_Server_Info *server, | 1877 | parse_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 | |||
| 1886 | void | ||
| 1887 | smb2_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, · 1 unmodified line | |||
| 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, · 2 unmodified lines | |||
| 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 | ||
| 1907 | static int | 1930 | static int |
| @@ -2588,12 +2611,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, · 680 unmodified lines | |||
| 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; | ||
| 2597 | creat_exit: | 2617 | creat_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); |
| @@ -818,7 +818,9 @@ struct durable_reconnect_context_v2 { · 817 unmodified lines | |||
| 818 | } __packed; | 818 | } __packed; |
| 819 | 819 | ||
| 820 | /* See MS-SMB2 2.2.14.2.9 */ | 820 | /* See MS-SMB2 2.2.14.2.9 */ |
| 821 | struct on_disk_id { | 821 | struct 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]; |
| @@ -228,9 +228,10 @@ extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *); · 227 unmodified lines | |||
| 228 | 228 | ||
| 229 | extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *, | 229 | extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *, |
| 230 | enum securityEnum); | 230 | enum securityEnum); |
| 231 | extern __u8 smb2_parse_lease_state(struct TCP_Server_Info *server, | 231 | extern 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); | ||
| 234 | extern int smb3_encryption_required(const struct cifs_tcon *tcon); | 235 | extern int smb3_encryption_required(const struct cifs_tcon *tcon); |
| 235 | extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length, | 236 | extern 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); |