Pull smb client fixes from Steve French: - Fix unlink race and rename races - SMB3.1.1 compression fix - Avoid unneeded strlen calls in cifs_get_spnego_key - Fix slab out of bounds in parse_server_interfaces() - Fix mid leak and server buffer leak - smbdirect send error path fix - update internal version # - Fix unneeded response time update in negotiate protocol * tag '6.17-rc1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: smb: client: remove redundant lstrp update in negotiate protocol cifs: update internal version number smb: client: don't wait for info->send_pending == 0 on error smb: client: fix mid_q_entry memleak leak with per-mid locking smb3: fix for slab out of bounds on mount to ksmbd cifs: avoid extra calls to strlen() in cifs_get_spnego_key() cifs: Fix collect_sample() to handle any iterator type smb: client: fix race with concurrent opens in rename(2) smb: client: fix race with concurrent opens in unlink(2)
Unified · Split
| @@ -124,55 +124,44 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo, · 123 unmodified lines | |||
| 124 | dp = description; | 124 | dp = description; |
| 125 | /* start with version and hostname portion of UNC string */ | 125 | /* start with version and hostname portion of UNC string */ |
| 126 | spnego_key = ERR_PTR(-EINVAL); | 126 | spnego_key = ERR_PTR(-EINVAL); |
| 127 | sprintf(dp, "ver=0x%x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION, | 127 | dp += sprintf(dp, "ver=0x%x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION, |
| 128 | hostname); | 128 | hostname); |
| 129 | dp = description + strlen(description); | ||
| 130 | 129 | ||
| 131 | /* add the server address */ | 130 | /* add the server address */ |
| 132 | if (server->dstaddr.ss_family == AF_INET) | 131 | if (server->dstaddr.ss_family == AF_INET) |
| 133 | sprintf(dp, "ip4=%pI4", &sa->sin_addr); | 132 | dp += sprintf(dp, "ip4=%pI4", &sa->sin_addr); |
| 134 | else if (server->dstaddr.ss_family == AF_INET6) | 133 | else if (server->dstaddr.ss_family == AF_INET6) |
| 135 | sprintf(dp, "ip6=%pI6", &sa6->sin6_addr); | 134 | dp += sprintf(dp, "ip6=%pI6", &sa6->sin6_addr); |
| 136 | else | 135 | else |
| 137 | goto out; | 136 | goto out; |
| 138 | 137 | ||
| 139 | dp = description + strlen(description); | ||
| 140 | |||
| 141 | /* for now, only sec=krb5 and sec=mskrb5 and iakerb are valid */ | 138 | /* for now, only sec=krb5 and sec=mskrb5 and iakerb are valid */ |
| 142 | if (server->sec_kerberos) | 139 | if (server->sec_kerberos) |
| 143 | sprintf(dp, ";sec=krb5"); | 140 | dp += sprintf(dp, ";sec=krb5"); |
| 144 | else if (server->sec_mskerberos) | 141 | else if (server->sec_mskerberos) |
| 145 | sprintf(dp, ";sec=mskrb5"); | 142 | dp += sprintf(dp, ";sec=mskrb5"); |
| 146 | else if (server->sec_iakerb) | 143 | else if (server->sec_iakerb) |
| 147 | sprintf(dp, ";sec=iakerb"); | 144 | dp += sprintf(dp, ";sec=iakerb"); |
| 148 | else { | 145 | else { |
| 149 | cifs_dbg(VFS, "unknown or missing server auth type, use krb5\n"); | 146 | cifs_dbg(VFS, "unknown or missing server auth type, use krb5\n"); |
| 150 | sprintf(dp, ";sec=krb5"); | 147 | dp += sprintf(dp, ";sec=krb5"); |
| 151 | } | 148 | } |
| 152 | 149 | ||
| 153 | dp = description + strlen(description); | 150 | dp += sprintf(dp, ";uid=0x%x", |
| 154 | sprintf(dp, ";uid=0x%x", | 151 | from_kuid_munged(&init_user_ns, sesInfo->linux_uid)); |
| 155 | from_kuid_munged(&init_user_ns, sesInfo->linux_uid)); | ||
| 156 | 152 | ||
| 157 | dp = description + strlen(description); | 153 | dp += sprintf(dp, ";creduid=0x%x", |
| 158 | sprintf(dp, ";creduid=0x%x", | ||
| 159 | from_kuid_munged(&init_user_ns, sesInfo->cred_uid)); | 154 | from_kuid_munged(&init_user_ns, sesInfo->cred_uid)); |
| 160 | 155 | ||
| 161 | if (sesInfo->user_name) { | 156 | if (sesInfo->user_name) |
| 162 | dp = description + strlen(description); | 157 | dp += sprintf(dp, ";user=%s", sesInfo->user_name); |
| 163 | sprintf(dp, ";user=%s", sesInfo->user_name); | ||
| 164 | } | ||
| 165 | 158 | ||
| 166 | dp = description + strlen(description); | 159 | dp += sprintf(dp, ";pid=0x%x", current->pid); |
| 167 | sprintf(dp, ";pid=0x%x", current->pid); | ||
| 168 | 160 | ||
| 169 | if (sesInfo->upcall_target == UPTARGET_MOUNT) { | 161 | if (sesInfo->upcall_target == UPTARGET_MOUNT) |
| 170 | dp = description + strlen(description); | 162 | dp += sprintf(dp, ";upcall_target=mount"); |
| 171 | sprintf(dp, ";upcall_target=mount"); | 163 | else |
| 172 | } else { | 164 | dp += sprintf(dp, ";upcall_target=app"); |
| 173 | dp = description + strlen(description); | ||
| 174 | sprintf(dp, ";upcall_target=app"); | ||
| 175 | } | ||
| 176 | 165 | ||
| 177 | cifs_dbg(FYI, "key description = %s\n", description); | 166 | cifs_dbg(FYI, "key description = %s\n", description); |
| 178 | saved_cred = override_creds(spnego_cred); | 167 | saved_cred = override_creds(spnego_cred); |
| @@ -145,6 +145,6 @@ extern const struct export_operations cifs_export_ops; · 144 unmodified lines | |||
| 145 | #endif /* CONFIG_CIFS_NFSD_EXPORT */ | 145 | #endif /* CONFIG_CIFS_NFSD_EXPORT */ |
| 146 | 146 | ||
| 147 | /* when changing internal version - update following two lines at same time */ | 147 | /* when changing internal version - update following two lines at same time */ |
| 148 | #define SMB3_PRODUCT_BUILD 55 | 148 | #define SMB3_PRODUCT_BUILD 56 |
| 149 | #define CIFS_VERSION "2.55" | 149 | #define CIFS_VERSION "2.56" |
| 150 | #endif /* _CIFSFS_H */ | 150 | #endif /* _CIFSFS_H */ |
| @@ -1732,6 +1732,7 @@ struct mid_q_entry { · 1731 unmodified lines | |||
| 1732 | int mid_rc; /* rc for MID_RC */ | 1732 | int mid_rc; /* rc for MID_RC */ |
| 1733 | __le16 command; /* smb command code */ | 1733 | __le16 command; /* smb command code */ |
| 1734 | unsigned int optype; /* operation type */ | 1734 | unsigned int optype; /* operation type */ |
| 1735 | spinlock_t mid_lock; | ||
| 1735 | bool wait_cancelled:1; /* Cancelled while waiting for response */ | 1736 | bool wait_cancelled:1; /* Cancelled while waiting for response */ |
| 1736 | bool deleted_from_q:1; /* Whether Mid has been dequeued frem pending_mid_q */ | 1737 | bool deleted_from_q:1; /* Whether Mid has been dequeued frem pending_mid_q */ |
| 1737 | bool large_buf:1; /* if valid response, is pointer to large buf */ | 1738 | bool large_buf:1; /* if valid response, is pointer to large buf */ |
| @@ -2036,6 +2037,9 @@ require use of the stronger protocol */ · 298 unmodified lines | |||
| 2036 | * cifsFileInfo->file_info_lock cifsFileInfo->count cifs_new_fileinfo | 2037 | * cifsFileInfo->file_info_lock cifsFileInfo->count cifs_new_fileinfo |
| 2037 | * ->invalidHandle initiate_cifs_search | 2038 | * ->invalidHandle initiate_cifs_search |
| 2038 | * ->oplock_break_cancelled | 2039 | * ->oplock_break_cancelled |
| 2040 | * mid_q_entry->mid_lock mid_q_entry->callback alloc_mid | ||
| 2041 | * smb2_mid_entry_alloc | ||
| 2042 | * (Any fields of mid_q_entry that will need protection) | ||
| 2039 | ****************************************************************************/ | 2043 | ****************************************************************************/ |
| 2040 | 2044 | ||
| 2041 | #ifdef DECLARE_GLOBALS_HERE | 2045 | #ifdef DECLARE_GLOBALS_HERE |
| @@ -2375,6 +2379,23 @@ static inline bool cifs_netbios_name(const char *name, size_t namelen) · 333 unmodified lines | |||
| 2375 | return ret; | 2379 | return ret; |
| 2376 | } | 2380 | } |
| 2377 | 2381 | ||
| 2382 | /* | ||
| 2383 | * Execute mid callback atomically - ensures callback runs exactly once | ||
| 2384 | * and prevents sleeping in atomic context. | ||
| 2385 | */ | ||
| 2386 | static inline void mid_execute_callback(struct mid_q_entry *mid) | ||
| 2387 | { | ||
| 2388 | void (*callback)(struct mid_q_entry *mid); | ||
| 2389 | |||
| 2390 | spin_lock(&mid->mid_lock); | ||
| 2391 | callback = mid->callback; | ||
| 2392 | mid->callback = NULL; /* Mark as executed, */ | ||
| 2393 | spin_unlock(&mid->mid_lock); | ||
| 2394 | |||
| 2395 | if (callback) | ||
| 2396 | callback(mid); | ||
| 2397 | } | ||
| 2398 | |||
| 2378 | #define CIFS_REPARSE_SUPPORT(tcon) \ | 2399 | #define CIFS_REPARSE_SUPPORT(tcon) \ |
| 2379 | ((tcon)->posix_extensions || \ | 2400 | ((tcon)->posix_extensions || \ |
| 2380 | (le32_to_cpu((tcon)->fsAttrInfo.Attributes) & \ | 2401 | (le32_to_cpu((tcon)->fsAttrInfo.Attributes) & \ |
| @@ -46,6 +46,7 @@ alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) · 45 unmodified lines | |||
| 46 | temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS); | 46 | temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS); |
| 47 | memset(temp, 0, sizeof(struct mid_q_entry)); | 47 | memset(temp, 0, sizeof(struct mid_q_entry)); |
| 48 | kref_init(&temp->refcount); | 48 | kref_init(&temp->refcount); |
| 49 | spin_lock_init(&temp->mid_lock); | ||
| 49 | temp->mid = get_mid(smb_buffer); | 50 | temp->mid = get_mid(smb_buffer); |
| 50 | temp->pid = current->pid; | 51 | temp->pid = current->pid; |
| 51 | temp->command = cpu_to_le16(smb_buffer->Command); | 52 | temp->command = cpu_to_le16(smb_buffer->Command); |
| @@ -345,16 +346,15 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, · 293 unmodified lines | |||
| 345 | rc = wait_for_response(server, midQ); | 346 | rc = wait_for_response(server, midQ); |
| 346 | if (rc != 0) { | 347 | if (rc != 0) { |
| 347 | send_cancel(server, &rqst, midQ); | 348 | send_cancel(server, &rqst, midQ); |
| 348 | spin_lock(&server->mid_queue_lock); | 349 | spin_lock(&midQ->mid_lock); |
| 349 | if (midQ->mid_state == MID_REQUEST_SUBMITTED || | 350 | if (midQ->callback) { |
| 350 | midQ->mid_state == MID_RESPONSE_RECEIVED) { | ||
| 351 | /* no longer considered to be "in-flight" */ | 351 | /* no longer considered to be "in-flight" */ |
| 352 | midQ->callback = release_mid; | 352 | midQ->callback = release_mid; |
| 353 | spin_unlock(&server->mid_queue_lock); | 353 | spin_unlock(&midQ->mid_lock); |
| 354 | add_credits(server, &credits, 0); | 354 | add_credits(server, &credits, 0); |
| 355 | return rc; | 355 | return rc; |
| 356 | } | 356 | } |
| 357 | spin_unlock(&server->mid_queue_lock); | 357 | spin_unlock(&midQ->mid_lock); |
| 358 | } | 358 | } |
| 359 | 359 | ||
| 360 | rc = cifs_sync_mid_result(midQ, server); | 360 | rc = cifs_sync_mid_result(midQ, server); |
| @@ -527,15 +527,14 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, · 166 unmodified lines | |||
| 527 | rc = wait_for_response(server, midQ); | 527 | rc = wait_for_response(server, midQ); |
| 528 | if (rc) { | 528 | if (rc) { |
| 529 | send_cancel(server, &rqst, midQ); | 529 | send_cancel(server, &rqst, midQ); |
| 530 | spin_lock(&server->mid_queue_lock); | 530 | spin_lock(&midQ->mid_lock); |
| 531 | if (midQ->mid_state == MID_REQUEST_SUBMITTED || | 531 | if (midQ->callback) { |
| 532 | midQ->mid_state == MID_RESPONSE_RECEIVED) { | ||
| 533 | /* no longer considered to be "in-flight" */ | 532 | /* no longer considered to be "in-flight" */ |
| 534 | midQ->callback = release_mid; | 533 | midQ->callback = release_mid; |
| 535 | spin_unlock(&server->mid_queue_lock); | 534 | spin_unlock(&midQ->mid_lock); |
| 536 | return rc; | 535 | return rc; |
| 537 | } | 536 | } |
| 538 | spin_unlock(&server->mid_queue_lock); | 537 | spin_unlock(&midQ->mid_lock); |
| 539 | } | 538 | } |
| 540 | 539 | ||
| 541 | /* We got the response - restart system call. */ | 540 | /* We got the response - restart system call. */ |
| @@ -155,58 +155,29 @@ static int cmp_bkt(const void *_a, const void *_b) · 154 unmodified lines | |||
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | /* | 157 | /* |
| 158 | * TODO: | 158 | * Collect some 2K samples with 2K gaps between. |
| 159 | * Support other iter types, if required. | ||
| 160 | * Only ITER_XARRAY is supported for now. | ||
| 161 | */ | 159 | */ |
| 162 | static int collect_sample(const struct iov_iter *iter, ssize_t max, u8 *sample) | 160 | static int collect_sample(const struct iov_iter *source, ssize_t max, u8 *sample) |
| 163 | { | 161 | { |
| 164 | struct folio *folios[16], *folio; | 162 | struct iov_iter iter = *source; |
| 165 | unsigned int nr, i, j, npages; | 163 | size_t s = 0; |
| 166 | loff_t start = iter->xarray_start + iter->iov_offset; | 164 | |
| 167 | pgoff_t last, index = start / PAGE_SIZE; | 165 | while (iov_iter_count(&iter) >= SZ_2K) { |
| 168 | size_t len, off, foff; | 166 | size_t part = umin(umin(iov_iter_count(&iter), SZ_2K), max); |
| 169 | void *p; | 167 | size_t n; |
| 170 | int s = 0; | 168 | |
| 171 | 169 | n = copy_from_iter(sample + s, part, &iter); | |
| 172 | last = (start + max - 1) / PAGE_SIZE; | 170 | if (n != part) |
| 173 | do { | 171 | return -EFAULT; |
| 174 | nr = xa_extract(iter->xarray, (void **)folios, index, last, ARRAY_SIZE(folios), | 172 | |
| 175 | XA_PRESENT); | 173 | s += n; |
| 176 | if (nr == 0) | 174 | max -= n; |
| 177 | return -EIO; | 175 | |
| 178 | 176 | if (iov_iter_count(&iter) < PAGE_SIZE - SZ_2K) | |
| 179 | for (i = 0; i < nr; i++) { | 177 | break; |
| 180 | folio = folios[i]; | 178 | |
| 181 | npages = folio_nr_pages(folio); | 179 | iov_iter_advance(&iter, SZ_2K); |
| 182 | foff = start - folio_pos(folio); | 180 | } |
| 183 | off = foff % PAGE_SIZE; | ||
| 184 | |||
| 185 | for (j = foff / PAGE_SIZE; j < npages; j++) { | ||
| 186 | size_t len2; | ||
| 187 | |||
| 188 | len = min_t(size_t, max, PAGE_SIZE - off); | ||
| 189 | len2 = min_t(size_t, len, SZ_2K); | ||
| 190 | |||
| 191 | p = kmap_local_page(folio_page(folio, j)); | ||
| 192 | memcpy(&sample[s], p, len2); | ||
| 193 | kunmap_local(p); | ||
| 194 | |||
| 195 | s += len2; | ||
| 196 | |||
| 197 | if (len2 < SZ_2K || s >= max - SZ_2K) | ||
| 198 | return s; | ||
| 199 | |||
| 200 | max -= len; | ||
| 201 | if (max <= 0) | ||
| 202 | return s; | ||
| 203 | |||
| 204 | start += len; | ||
| 205 | off = 0; | ||
| 206 | index++; | ||
| 207 | } | ||
| 208 | } | ||
| 209 | } while (nr == ARRAY_SIZE(folios)); | ||
| 210 | 181 | ||
| 211 | return s; | 182 | return s; |
| 212 | } | 183 | } |
| @@ -335,7 +335,7 @@ cifs_abort_connection(struct TCP_Server_Info *server) · 334 unmodified lines | |||
| 335 | cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__); | 335 | cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__); |
| 336 | list_for_each_entry_safe(mid, nmid, &retry_list, qhead) { | 336 | list_for_each_entry_safe(mid, nmid, &retry_list, qhead) { |
| 337 | list_del_init(&mid->qhead); | 337 | list_del_init(&mid->qhead); |
| 338 | mid->callback(mid); | 338 | mid_execute_callback(mid); |
| 339 | release_mid(mid); | 339 | release_mid(mid); |
| 340 | } | 340 | } |
| 341 | 341 | ||
| @@ -919,7 +919,7 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type) · 577 unmodified lines | |||
| 919 | list_del_init(&mid->qhead); | 919 | list_del_init(&mid->qhead); |
| 920 | mid->mid_rc = mid_rc; | 920 | mid->mid_rc = mid_rc; |
| 921 | mid->mid_state = MID_RC; | 921 | mid->mid_state = MID_RC; |
| 922 | mid->callback(mid); | 922 | mid_execute_callback(mid); |
| 923 | release_mid(mid); | 923 | release_mid(mid); |
| 924 | } | 924 | } |
| 925 | 925 | ||
| @@ -1117,7 +1117,7 @@ clean_demultiplex_info(struct TCP_Server_Info *server) · 191 unmodified lines | |||
| 1117 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | 1117 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); |
| 1118 | cifs_dbg(FYI, "Callback mid %llu\n", mid_entry->mid); | 1118 | cifs_dbg(FYI, "Callback mid %llu\n", mid_entry->mid); |
| 1119 | list_del_init(&mid_entry->qhead); | 1119 | list_del_init(&mid_entry->qhead); |
| 1120 | mid_entry->callback(mid_entry); | 1120 | mid_execute_callback(mid_entry); |
| 1121 | release_mid(mid_entry); | 1121 | release_mid(mid_entry); |
| 1122 | } | 1122 | } |
| 1123 | /* 1/8th of sec is more than enough time for them to exit */ | 1123 | /* 1/8th of sec is more than enough time for them to exit */ |
| @@ -1394,7 +1394,7 @@ next_pdu: · 270 unmodified lines | |||
| 1394 | } | 1394 | } |
| 1395 | 1395 | ||
| 1396 | if (!mids[i]->multiRsp || mids[i]->multiEnd) | 1396 | if (!mids[i]->multiRsp || mids[i]->multiEnd) |
| 1397 | mids[i]->callback(mids[i]); | 1397 | mid_execute_callback(mids[i]); |
| 1398 | 1398 | ||
| 1399 | release_mid(mids[i]); | 1399 | release_mid(mids[i]); |
| 1400 | } else if (server->ops->is_oplock_break && | 1400 | } else if (server->ops->is_oplock_break && |
| @@ -4205,7 +4205,6 @@ retry: · 2804 unmodified lines | |||
| 4205 | return 0; | 4205 | return 0; |
| 4206 | } | 4206 | } |
| 4207 | 4207 | ||
| 4208 | server->lstrp = jiffies; | ||
| 4209 | server->tcpStatus = CifsInNegotiate; | 4208 | server->tcpStatus = CifsInNegotiate; |
| 4210 | server->neg_start = jiffies; | 4209 | server->neg_start = jiffies; |
| 4211 | spin_unlock(&server->srv_lock); | 4210 | spin_unlock(&server->srv_lock); |
| @@ -1943,15 +1943,24 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) · 1942 unmodified lines | |||
| 1943 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 1943 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
| 1944 | struct tcon_link *tlink; | 1944 | struct tcon_link *tlink; |
| 1945 | struct cifs_tcon *tcon; | 1945 | struct cifs_tcon *tcon; |
| 1946 | __u32 dosattr = 0, origattr = 0; | ||
| 1946 | struct TCP_Server_Info *server; | 1947 | struct TCP_Server_Info *server; |
| 1947 | struct iattr *attrs = NULL; | 1948 | struct iattr *attrs = NULL; |
| 1948 | __u32 dosattr = 0, origattr = 0; | 1949 | bool rehash = false; |
| 1949 | 1950 | ||
| 1950 | cifs_dbg(FYI, "cifs_unlink, dir=0x%p, dentry=0x%p\n", dir, dentry); | 1951 | cifs_dbg(FYI, "cifs_unlink, dir=0x%p, dentry=0x%p\n", dir, dentry); |
| 1951 | 1952 | ||
| 1952 | if (unlikely(cifs_forced_shutdown(cifs_sb))) | 1953 | if (unlikely(cifs_forced_shutdown(cifs_sb))) |
| 1953 | return -EIO; | 1954 | return -EIO; |
| 1954 | 1955 | ||
| 1956 | /* Unhash dentry in advance to prevent any concurrent opens */ | ||
| 1957 | spin_lock(&dentry->d_lock); | ||
| 1958 | if (!d_unhashed(dentry)) { | ||
| 1959 | __d_drop(dentry); | ||
| 1960 | rehash = true; | ||
| 1961 | } | ||
| 1962 | spin_unlock(&dentry->d_lock); | ||
| 1963 | |||
| 1955 | tlink = cifs_sb_tlink(cifs_sb); | 1964 | tlink = cifs_sb_tlink(cifs_sb); |
| 1956 | if (IS_ERR(tlink)) | 1965 | if (IS_ERR(tlink)) |
| 1957 | return PTR_ERR(tlink); | 1966 | return PTR_ERR(tlink); |
| @@ -2003,7 +2012,8 @@ psx_del_no_retry: · 45 unmodified lines | |||
| 2003 | cifs_drop_nlink(inode); | 2012 | cifs_drop_nlink(inode); |
| 2004 | } | 2013 | } |
| 2005 | } else if (rc == -ENOENT) { | 2014 | } else if (rc == -ENOENT) { |
| 2006 | d_drop(dentry); | 2015 | if (simple_positive(dentry)) |
| 2016 | d_delete(dentry); | ||
| 2007 | } else if (rc == -EBUSY) { | 2017 | } else if (rc == -EBUSY) { |
| 2008 | if (server->ops->rename_pending_delete) { | 2018 | if (server->ops->rename_pending_delete) { |
| 2009 | rc = server->ops->rename_pending_delete(full_path, | 2019 | rc = server->ops->rename_pending_delete(full_path, |
| @@ -2056,6 +2066,8 @@ unlink_out: · 46 unmodified lines | |||
| 2056 | kfree(attrs); | 2066 | kfree(attrs); |
| 2057 | free_xid(xid); | 2067 | free_xid(xid); |
| 2058 | cifs_put_tlink(tlink); | 2068 | cifs_put_tlink(tlink); |
| 2069 | if (rehash) | ||
| 2070 | d_rehash(dentry); | ||
| 2059 | return rc; | 2071 | return rc; |
| 2060 | } | 2072 | } |
| 2061 | 2073 | ||
| @@ -2462,6 +2474,7 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir, · 400 unmodified lines | |||
| 2462 | struct cifs_sb_info *cifs_sb; | 2474 | struct cifs_sb_info *cifs_sb; |
| 2463 | struct tcon_link *tlink; | 2475 | struct tcon_link *tlink; |
| 2464 | struct cifs_tcon *tcon; | 2476 | struct cifs_tcon *tcon; |
| 2477 | bool rehash = false; | ||
| 2465 | unsigned int xid; | 2478 | unsigned int xid; |
| 2466 | int rc, tmprc; | 2479 | int rc, tmprc; |
| 2467 | int retry_count = 0; | 2480 | int retry_count = 0; |
| @@ -2477,6 +2490,17 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir, · 9 unmodified lines | |||
| 2477 | if (unlikely(cifs_forced_shutdown(cifs_sb))) | 2490 | if (unlikely(cifs_forced_shutdown(cifs_sb))) |
| 2478 | return -EIO; | 2491 | return -EIO; |
| 2479 | 2492 | ||
| 2493 | /* | ||
| 2494 | * Prevent any concurrent opens on the target by unhashing the dentry. | ||
| 2495 | * VFS already unhashes the target when renaming directories. | ||
| 2496 | */ | ||
| 2497 | if (d_is_positive(target_dentry) && !d_is_dir(target_dentry)) { | ||
| 2498 | if (!d_unhashed(target_dentry)) { | ||
| 2499 | d_drop(target_dentry); | ||
| 2500 | rehash = true; | ||
| 2501 | } | ||
| 2502 | } | ||
| 2503 | |||
| 2480 | tlink = cifs_sb_tlink(cifs_sb); | 2504 | tlink = cifs_sb_tlink(cifs_sb); |
| 2481 | if (IS_ERR(tlink)) | 2505 | if (IS_ERR(tlink)) |
| 2482 | return PTR_ERR(tlink); | 2506 | return PTR_ERR(tlink); |
| @@ -2518,6 +2542,8 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir, · 35 unmodified lines | |||
| 2518 | } | 2542 | } |
| 2519 | } | 2543 | } |
| 2520 | 2544 | ||
| 2545 | if (!rc) | ||
| 2546 | rehash = false; | ||
| 2521 | /* | 2547 | /* |
| 2522 | * No-replace is the natural behavior for CIFS, so skip unlink hacks. | 2548 | * No-replace is the natural behavior for CIFS, so skip unlink hacks. |
| 2523 | */ | 2549 | */ |
| @@ -2576,12 +2602,16 @@ unlink_target: · 52 unmodified lines | |||
| 2576 | goto cifs_rename_exit; | 2602 | goto cifs_rename_exit; |
| 2577 | rc = cifs_do_rename(xid, source_dentry, from_name, | 2603 | rc = cifs_do_rename(xid, source_dentry, from_name, |
| 2578 | target_dentry, to_name); | 2604 | target_dentry, to_name); |
| 2605 | if (!rc) | ||
| 2606 | rehash = false; | ||
| 2579 | } | 2607 | } |
| 2580 | 2608 | ||
| 2581 | /* force revalidate to go get info when needed */ | 2609 | /* force revalidate to go get info when needed */ |
| 2582 | CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0; | 2610 | CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0; |
| 2583 | 2611 | ||
| 2584 | cifs_rename_exit: | 2612 | cifs_rename_exit: |
| 2613 | if (rehash) | ||
| 2614 | d_rehash(target_dentry); | ||
| 2585 | kfree(info_buf_source); | 2615 | kfree(info_buf_source); |
| 2586 | free_dentry_path(page2); | 2616 | free_dentry_path(page2); |
| 2587 | free_dentry_path(page1); | 2617 | free_dentry_path(page1); |
| @@ -772,6 +772,13 @@ next_iface: · 771 unmodified lines | |||
| 772 | bytes_left -= sizeof(*p); | 772 | bytes_left -= sizeof(*p); |
| 773 | break; | 773 | break; |
| 774 | } | 774 | } |
| 775 | /* Validate that Next doesn't point beyond the buffer */ | ||
| 776 | if (next > bytes_left) { | ||
| 777 | cifs_dbg(VFS, "%s: invalid Next pointer %zu > %zd\n", | ||
| 778 | __func__, next, bytes_left); | ||
| 779 | rc = -EINVAL; | ||
| 780 | goto out; | ||
| 781 | } | ||
| 775 | p = (struct network_interface_info_ioctl_rsp *)((u8 *)p+next); | 782 | p = (struct network_interface_info_ioctl_rsp *)((u8 *)p+next); |
| 776 | bytes_left -= next; | 783 | bytes_left -= next; |
| 777 | } | 784 | } |
| @@ -783,7 +790,9 @@ next_iface: · 5 unmodified lines | |||
| 783 | } | 790 | } |
| 784 | 791 | ||
| 785 | /* Azure rounds the buffer size up 8, to a 16 byte boundary */ | 792 | /* Azure rounds the buffer size up 8, to a 16 byte boundary */ |
| 786 | if ((bytes_left > 8) || p->Next) | 793 | if ((bytes_left > 8) || |
| 794 | (bytes_left >= offsetof(struct network_interface_info_ioctl_rsp, Next) | ||
| 795 | + sizeof(p->Next) && p->Next)) | ||
| 787 | cifs_dbg(VFS, "%s: incomplete interface info\n", __func__); | 796 | cifs_dbg(VFS, "%s: incomplete interface info\n", __func__); |
| 788 | 797 | ||
| 789 | ses->iface_last_update = jiffies; | 798 | ses->iface_last_update = jiffies; |
| @@ -4805,7 +4814,7 @@ static void smb2_decrypt_offload(struct work_struct *work) · 4015 unmodified lines | |||
| 4805 | dw->server->ops->is_network_name_deleted(dw->buf, | 4814 | dw->server->ops->is_network_name_deleted(dw->buf, |
| 4806 | dw->server); | 4815 | dw->server); |
| 4807 | 4816 | ||
| 4808 | mid->callback(mid); | 4817 | mid_execute_callback(mid); |
| 4809 | } else { | 4818 | } else { |
| 4810 | spin_lock(&dw->server->srv_lock); | 4819 | spin_lock(&dw->server->srv_lock); |
| 4811 | if (dw->server->tcpStatus == CifsNeedReconnect) { | 4820 | if (dw->server->tcpStatus == CifsNeedReconnect) { |
| @@ -4813,7 +4822,7 @@ static void smb2_decrypt_offload(struct work_struct *work) · 1 unmodified line | |||
| 4813 | mid->mid_state = MID_RETRY_NEEDED; | 4822 | mid->mid_state = MID_RETRY_NEEDED; |
| 4814 | spin_unlock(&dw->server->mid_queue_lock); | 4823 | spin_unlock(&dw->server->mid_queue_lock); |
| 4815 | spin_unlock(&dw->server->srv_lock); | 4824 | spin_unlock(&dw->server->srv_lock); |
| 4816 | mid->callback(mid); | 4825 | mid_execute_callback(mid); |
| 4817 | } else { | 4826 | } else { |
| 4818 | spin_lock(&dw->server->mid_queue_lock); | 4827 | spin_lock(&dw->server->mid_queue_lock); |
| 4819 | mid->mid_state = MID_REQUEST_SUBMITTED; | 4828 | mid->mid_state = MID_REQUEST_SUBMITTED; |
| @@ -771,6 +771,7 @@ smb2_mid_entry_alloc(const struct smb2_hdr *shdr, · 770 unmodified lines | |||
| 771 | temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS); | 771 | temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS); |
| 772 | memset(temp, 0, sizeof(struct mid_q_entry)); | 772 | memset(temp, 0, sizeof(struct mid_q_entry)); |
| 773 | kref_init(&temp->refcount); | 773 | kref_init(&temp->refcount); |
| 774 | spin_lock_init(&temp->mid_lock); | ||
| 774 | temp->mid = le64_to_cpu(shdr->MessageId); | 775 | temp->mid = le64_to_cpu(shdr->MessageId); |
| 775 | temp->credits = credits > 0 ? credits : 1; | 776 | temp->credits = credits > 0 ? credits : 1; |
| 776 | temp->pid = current->pid; | 777 | temp->pid = current->pid; |
| @@ -1337,10 +1337,6 @@ void smbd_destroy(struct TCP_Server_Info *server) · 1336 unmodified lines | |||
| 1337 | log_rdma_event(INFO, "cancelling idle timer\n"); | 1337 | log_rdma_event(INFO, "cancelling idle timer\n"); |
| 1338 | cancel_delayed_work_sync(&info->idle_timer_work); | 1338 | cancel_delayed_work_sync(&info->idle_timer_work); |
| 1339 | 1339 | ||
| 1340 | log_rdma_event(INFO, "wait for all send posted to IB to finish\n"); | ||
| 1341 | wait_event(info->wait_send_pending, | ||
| 1342 | atomic_read(&info->send_pending) == 0); | ||
| 1343 | |||
| 1344 | /* It's not possible for upper layer to get to reassembly */ | 1340 | /* It's not possible for upper layer to get to reassembly */ |
| 1345 | log_rdma_event(INFO, "drain the reassembly queue\n"); | 1341 | log_rdma_event(INFO, "drain the reassembly queue\n"); |
| 1346 | do { | 1342 | do { |
| @@ -1986,7 +1982,11 @@ int smbd_send(struct TCP_Server_Info *server, · 639 unmodified lines | |||
| 1986 | */ | 1982 | */ |
| 1987 | 1983 | ||
| 1988 | wait_event(info->wait_send_pending, | 1984 | wait_event(info->wait_send_pending, |
| 1989 | atomic_read(&info->send_pending) == 0); | 1985 | atomic_read(&info->send_pending) == 0 || |
| 1986 | sc->status != SMBDIRECT_SOCKET_CONNECTED); | ||
| 1987 | |||
| 1988 | if (sc->status != SMBDIRECT_SOCKET_CONNECTED && rc == 0) | ||
| 1989 | rc = -EAGAIN; | ||
| 1990 | 1990 | ||
| 1991 | return rc; | 1991 | return rc; |
| 1992 | } | 1992 | } |
| @@ -1005,15 +1005,14 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, · 1004 unmodified lines | |||
| 1005 | cifs_server_dbg(FYI, "Cancelling wait for mid %llu cmd: %d\n", | 1005 | cifs_server_dbg(FYI, "Cancelling wait for mid %llu cmd: %d\n", |
| 1006 | midQ[i]->mid, le16_to_cpu(midQ[i]->command)); | 1006 | midQ[i]->mid, le16_to_cpu(midQ[i]->command)); |
| 1007 | send_cancel(server, &rqst[i], midQ[i]); | 1007 | send_cancel(server, &rqst[i], midQ[i]); |
| 1008 | spin_lock(&server->mid_queue_lock); | 1008 | spin_lock(&midQ[i]->mid_lock); |
| 1009 | midQ[i]->wait_cancelled = true; | 1009 | midQ[i]->wait_cancelled = true; |
| 1010 | if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED || | 1010 | if (midQ[i]->callback) { |
| 1011 | midQ[i]->mid_state == MID_RESPONSE_RECEIVED) { | ||
| 1012 | midQ[i]->callback = cifs_cancelled_callback; | 1011 | midQ[i]->callback = cifs_cancelled_callback; |
| 1013 | cancelled_mid[i] = true; | 1012 | cancelled_mid[i] = true; |
| 1014 | credits[i].value = 0; | 1013 | credits[i].value = 0; |
| 1015 | } | 1014 | } |
| 1016 | spin_unlock(&server->mid_queue_lock); | 1015 | spin_unlock(&midQ[i]->mid_lock); |
| 1017 | } | 1016 | } |
| 1018 | } | 1017 | } |
| 1019 | 1018 | ||