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 | 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 | 1112 | * Note: cifs case is easier than btrfs since server responsible for |
| 1109 | 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 | 1119 | /* should we flush first and last page first */ |
| 1116 | 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 | 1124 | rc = target_tcon->ses->server->ops->copychunk_range(xid, |
| 1120 | 1125 | smb_file_src, smb_file_target, off, len, destoff); |
| 1121 | − else | |
| 1122 | − rc = -EOPNOTSUPP; | |
| 1126 | + | |
| 1127 | + file_accessed(src_file); | |
| 1123 | 1128 | |
| 1124 | 1129 | /* force revalidate of size and timestamps of target file now |
| 1125 | 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 | 152 | extern const struct export_operations cifs_export_ops; |
| 153 | 153 | #endif /* CONFIG_CIFS_NFSD_EXPORT */ |
| 154 | 154 | |
| 155 | −#define CIFS_VERSION "2.20" | |
| 155 | +#define CIFS_VERSION "2.21" | |
| 156 | 156 | #endif /* _CIFSFS_H */ |
| @@ -2406,6 +2406,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) · 2405 unmodified lines | ||
| 2406 | 2406 | struct inode *inode = d_inode(direntry); |
| 2407 | 2407 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
| 2408 | 2408 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); |
| 2409 | + struct cifsFileInfo *wfile; | |
| 2410 | + struct cifs_tcon *tcon; | |
| 2409 | 2411 | char *full_path = NULL; |
| 2410 | 2412 | int rc = -EACCES; |
| 2411 | 2413 | __u32 dosattr = 0; |
| @@ -2452,6 +2454,20 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) · 40 unmodified lines | ||
| 2452 | 2454 | mapping_set_error(inode->i_mapping, rc); |
| 2453 | 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 | 2471 | if (attrs->ia_valid & ATTR_SIZE) { |
| 2456 | 2472 | rc = cifs_set_file_size(inode, attrs, xid, full_path); |
| 2457 | 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 | 90 | if (buf) { |
| 91 | − /* open response does not have IndexNumber field - get it */ | |
| 92 | − rc = SMB2_get_srv_num(xid, oparms->tcon, fid->persistent_fid, | |
| 91 | + /* if open response does not have IndexNumber field - get it */ | |
| 92 | + if (smb2_data->IndexNumber == 0) { | |
| 93 | + rc = SMB2_get_srv_num(xid, oparms->tcon, | |
| 94 | + fid->persistent_fid, | |
| 93 | 95 | fid->volatile_fid, |
| 94 | 96 | &smb2_data->IndexNumber); |
| 95 | − if (rc) { | |
| 96 | − /* let get_inode_info disable server inode numbers */ | |
| 97 | − smb2_data->IndexNumber = 0; | |
| 98 | − rc = 0; | |
| 97 | + if (rc) { | |
| 98 | + /* | |
| 99 | + * let get_inode_info disable server inode | |
| 100 | + * numbers | |
| 101 | + */ | |
| 102 | + smb2_data->IndexNumber = 0; | |
| 103 | + rc = 0; | |
| 104 | + } | |
| 99 | 105 | } |
| 100 | 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 | 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 | 705 | rc = compound_send_recv(xid, ses, flags, 2, rqst, |
| 698 | 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 | 742 | if (rc) |
| 700 | 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 | 754 | tcon->crfid.is_valid = true; |
| 712 | 755 | kref_init(&tcon->crfid.refcount); |
| 713 | 756 | |
| 757 | + /* BB TBD check to see if oplock level check can be removed below */ | |
| 714 | 758 | if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) { |
| 715 | 759 | kref_get(&tcon->crfid.refcount); |
| 716 | − oplock = smb2_parse_lease_state(server, o_rsp, | |
| 717 | − &oparms.fid->epoch, | |
| 718 | − oparms.fid->lease_key); | |
| 760 | + smb2_parse_contexts(server, o_rsp, | |
| 761 | + &oparms.fid->epoch, | |
| 762 | + oparms.fid->lease_key, &oplock, NULL); | |
| 719 | 763 | } else |
| 720 | 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 | 773 | (char *)&tcon->crfid.file_all_info)) |
| 730 | 774 | tcon->crfid.file_all_info_is_valid = 1; |
| 731 | 775 | |
| 732 | − oshr_exit: | |
| 776 | +oshr_exit: | |
| 733 | 777 | mutex_unlock(&tcon->crfid.fid_mutex); |
| 778 | +oshr_free: | |
| 734 | 779 | SMB2_open_free(&rqst[0]); |
| 735 | 780 | SMB2_query_info_free(&rqst[1]); |
| 736 | 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 | 1873 | return buf; |
| 1874 | 1874 | } |
| 1875 | 1875 | |
| 1876 | −__u8 | |
| 1877 | −smb2_parse_lease_state(struct TCP_Server_Info *server, | |
| 1876 | +static void | |
| 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 | 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 | 1892 | char *data_offset; |
| 1882 | 1893 | struct create_context *cc; |
| @@ -1884,15 +1895,24 @@ smb2_parse_lease_state(struct TCP_Server_Info *server, · 1 unmodified line | ||
| 1884 | 1895 | unsigned int remaining; |
| 1885 | 1896 | char *name; |
| 1886 | 1897 | |
| 1898 | + *oplock = 0; | |
| 1887 | 1899 | data_offset = (char *)rsp + le32_to_cpu(rsp->CreateContextsOffset); |
| 1888 | 1900 | remaining = le32_to_cpu(rsp->CreateContextsLength); |
| 1889 | 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 | 1907 | while (remaining >= sizeof(struct create_context)) { |
| 1891 | 1908 | name = le16_to_cpu(cc->NameOffset) + (char *)cc; |
| 1892 | 1909 | if (le16_to_cpu(cc->NameLength) == 4 && |
| 1893 | − strncmp(name, "RqLs", 4) == 0) | |
| 1894 | − return server->ops->parse_lease_buf(cc, epoch, | |
| 1895 | − lease_key); | |
| 1910 | + strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4) == 0) | |
| 1911 | + *oplock = server->ops->parse_lease_buf(cc, epoch, | |
| 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 | 1917 | next = le32_to_cpu(cc->Next); |
| 1898 | 1918 | if (!next) |
| @@ -1901,7 +1921,10 @@ smb2_parse_lease_state(struct TCP_Server_Info *server, · 2 unmodified lines | ||
| 1901 | 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 | 1930 | static int |
| @@ -2588,12 +2611,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, · 680 unmodified lines | ||
| 2588 | 2611 | buf->DeletePending = 0; |
| 2589 | 2612 | } |
| 2590 | 2613 | |
| 2591 | − if (rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) | |
| 2592 | − *oplock = smb2_parse_lease_state(server, rsp, | |
| 2593 | − &oparms->fid->epoch, | |
| 2594 | − oparms->fid->lease_key); | |
| 2595 | − else | |
| 2596 | − *oplock = rsp->OplockLevel; | |
| 2614 | + | |
| 2615 | + smb2_parse_contexts(server, rsp, &oparms->fid->epoch, | |
| 2616 | + oparms->fid->lease_key, oplock, buf); | |
| 2597 | 2617 | creat_exit: |
| 2598 | 2618 | SMB2_open_free(&rqst); |
| 2599 | 2619 | free_rsp_buf(resp_buftype, rsp); |
| @@ -818,7 +818,9 @@ struct durable_reconnect_context_v2 { · 817 unmodified lines | ||
| 818 | 818 | } __packed; |
| 819 | 819 | |
| 820 | 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 | 824 | __le64 DiskFileId; |
| 823 | 825 | __le64 VolumeId; |
| 824 | 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 | 229 | extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *, |
| 230 | 230 | enum securityEnum); |
| 231 | −extern __u8 smb2_parse_lease_state(struct TCP_Server_Info *server, | |
| 232 | − struct smb2_create_rsp *rsp, | |
| 233 | − unsigned int *epoch, char *lease_key); | |
| 231 | +extern void smb2_parse_contexts(struct TCP_Server_Info *server, | |
| 232 | + struct smb2_create_rsp *rsp, | |
| 233 | + unsigned int *epoch, char *lease_key, | |
| 234 | + __u8 *oplock, struct smb2_file_all_info *buf); | |
| 234 | 235 | extern int smb3_encryption_required(const struct cifs_tcon *tcon); |
| 235 | 236 | extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length, |
| 236 | 237 | struct kvec *iov, unsigned int min_buf_size); |