Pull smb client fixes from Steve French: "Six smb3 client fixes: - Fixes for copy_file_range and clone (cache invalidation and file size), also addresses an xfstest failure - Fix to return proper error if REMAP_FILE_DEDUP set (also fixes xfstest generic/304) - Fix potential null pointer reference with DFS - Multichannel fix addressing (reverting an earlier patch) some of the problems with enabling/disabling channels dynamically Still working on a followon multichannel fix to address another issue found in reconnect testing that will send next week" * tag '6.7-rc4-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: reconnect worker should take reference on server struct unconditionally Revert "cifs: reconnect work should have reference on server struct" cifs: Fix non-availability of dedup breaking generic/304 smb: client: fix potential NULL deref in parse_dfs_referrals() cifs: Fix flushing, invalidation and file size with FICLONE cifs: Fix flushing, invalidation and file size with copy_file_range()
Unified · Split
| @@ -1196,32 +1196,103 @@ const struct inode_operations cifs_symlink_inode_ops = { · 1195 unmodified lines | |||
| 1196 | .listxattr = cifs_listxattr, | 1196 | .listxattr = cifs_listxattr, |
| 1197 | }; | 1197 | }; |
| 1198 | 1198 | ||
| 1199 | /* | ||
| 1200 | * Advance the EOF marker to after the source range. | ||
| 1201 | */ | ||
| 1202 | static int cifs_precopy_set_eof(struct inode *src_inode, struct cifsInodeInfo *src_cifsi, | ||
| 1203 | struct cifs_tcon *src_tcon, | ||
| 1204 | unsigned int xid, loff_t src_end) | ||
| 1205 | { | ||
| 1206 | struct cifsFileInfo *writeable_srcfile; | ||
| 1207 | int rc = -EINVAL; | ||
| 1208 | |||
| 1209 | writeable_srcfile = find_writable_file(src_cifsi, FIND_WR_FSUID_ONLY); | ||
| 1210 | if (writeable_srcfile) { | ||
| 1211 | if (src_tcon->ses->server->ops->set_file_size) | ||
| 1212 | rc = src_tcon->ses->server->ops->set_file_size( | ||
| 1213 | xid, src_tcon, writeable_srcfile, | ||
| 1214 | src_inode->i_size, true /* no need to set sparse */); | ||
| 1215 | else | ||
| 1216 | rc = -ENOSYS; | ||
| 1217 | cifsFileInfo_put(writeable_srcfile); | ||
| 1218 | cifs_dbg(FYI, "SetFSize for copychunk rc = %d\n", rc); | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | if (rc < 0) | ||
| 1222 | goto set_failed; | ||
| 1223 | |||
| 1224 | netfs_resize_file(&src_cifsi->netfs, src_end); | ||
| 1225 | fscache_resize_cookie(cifs_inode_cookie(src_inode), src_end); | ||
| 1226 | return 0; | ||
| 1227 | |||
| 1228 | set_failed: | ||
| 1229 | return filemap_write_and_wait(src_inode->i_mapping); | ||
| 1230 | } | ||
| 1231 | |||
| 1232 | /* | ||
| 1233 | * Flush out either the folio that overlaps the beginning of a range in which | ||
| 1234 | * pos resides or the folio that overlaps the end of a range unless that folio | ||
| 1235 | * is entirely within the range we're going to invalidate. We extend the flush | ||
| 1236 | * bounds to encompass the folio. | ||
| 1237 | */ | ||
| 1238 | static int cifs_flush_folio(struct inode *inode, loff_t pos, loff_t *_fstart, loff_t *_fend, | ||
| 1239 | bool first) | ||
| 1240 | { | ||
| 1241 | struct folio *folio; | ||
| 1242 | unsigned long long fpos, fend; | ||
| 1243 | pgoff_t index = pos / PAGE_SIZE; | ||
| 1244 | size_t size; | ||
| 1245 | int rc = 0; | ||
| 1246 | |||
| 1247 | folio = filemap_get_folio(inode->i_mapping, index); | ||
| 1248 | if (IS_ERR(folio)) | ||
| 1249 | return 0; | ||
| 1250 | |||
| 1251 | size = folio_size(folio); | ||
| 1252 | fpos = folio_pos(folio); | ||
| 1253 | fend = fpos + size - 1; | ||
| 1254 | *_fstart = min_t(unsigned long long, *_fstart, fpos); | ||
| 1255 | *_fend = max_t(unsigned long long, *_fend, fend); | ||
| 1256 | if ((first && pos == fpos) || (!first && pos == fend)) | ||
| 1257 | goto out; | ||
| 1258 | |||
| 1259 | rc = filemap_write_and_wait_range(inode->i_mapping, fpos, fend); | ||
| 1260 | out: | ||
| 1261 | folio_put(folio); | ||
| 1262 | return rc; | ||
| 1263 | } | ||
| 1264 | |||
| 1199 | static loff_t cifs_remap_file_range(struct file *src_file, loff_t off, | 1265 | static loff_t cifs_remap_file_range(struct file *src_file, loff_t off, |
| 1200 | struct file *dst_file, loff_t destoff, loff_t len, | 1266 | struct file *dst_file, loff_t destoff, loff_t len, |
| 1201 | unsigned int remap_flags) | 1267 | unsigned int remap_flags) |
| 1202 | { | 1268 | { |
| 1203 | struct inode *src_inode = file_inode(src_file); | 1269 | struct inode *src_inode = file_inode(src_file); |
| 1204 | struct inode *target_inode = file_inode(dst_file); | 1270 | struct inode *target_inode = file_inode(dst_file); |
| 1271 | struct cifsInodeInfo *src_cifsi = CIFS_I(src_inode); | ||
| 1272 | struct cifsInodeInfo *target_cifsi = CIFS_I(target_inode); | ||
| 1205 | struct cifsFileInfo *smb_file_src = src_file->private_data; | 1273 | struct cifsFileInfo *smb_file_src = src_file->private_data; |
| 1206 | struct cifsFileInfo *smb_file_target; | 1274 | struct cifsFileInfo *smb_file_target = dst_file->private_data; |
| 1207 | struct cifs_tcon *target_tcon; | 1275 | struct cifs_tcon *target_tcon, *src_tcon; |
| 1276 | unsigned long long destend, fstart, fend, new_size; | ||
| 1208 | unsigned int xid; | 1277 | unsigned int xid; |
| 1209 | int rc; | 1278 | int rc; |
| 1210 | 1279 | ||
| 1211 | if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY)) | 1280 | if (remap_flags & REMAP_FILE_DEDUP) |
| 1281 | return -EOPNOTSUPP; | ||
| 1282 | if (remap_flags & ~REMAP_FILE_ADVISORY) | ||
| 1212 | return -EINVAL; | 1283 | return -EINVAL; |
| 1213 | 1284 | ||
| 1214 | cifs_dbg(FYI, "clone range\n"); | 1285 | cifs_dbg(FYI, "clone range\n"); |
| 1215 | 1286 | ||
| 1216 | xid = get_xid(); | 1287 | xid = get_xid(); |
| 1217 | 1288 | ||
| 1218 | if (!src_file->private_data || !dst_file->private_data) { | 1289 | if (!smb_file_src || !smb_file_target) { |
| 1219 | rc = -EBADF; | 1290 | rc = -EBADF; |
| 1220 | cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n"); | 1291 | cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n"); |
| 1221 | goto out; | 1292 | goto out; |
| 1222 | } | 1293 | } |
| 1223 | 1294 | ||
| 1224 | smb_file_target = dst_file->private_data; | 1295 | src_tcon = tlink_tcon(smb_file_src->tlink); |
| 1225 | target_tcon = tlink_tcon(smb_file_target->tlink); | 1296 | target_tcon = tlink_tcon(smb_file_target->tlink); |
| 1226 | 1297 | ||
| 1227 | /* | 1298 | /* |
| @@ -1234,20 +1305,63 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off, · 6 unmodified lines | |||
| 1234 | if (len == 0) | 1305 | if (len == 0) |
| 1235 | len = src_inode->i_size - off; | 1306 | len = src_inode->i_size - off; |
| 1236 | 1307 | ||
| 1237 | cifs_dbg(FYI, "about to flush pages\n"); | 1308 | cifs_dbg(FYI, "clone range\n"); |
| 1238 | /* should we flush first and last page first */ | ||
| 1239 | truncate_inode_pages_range(&target_inode->i_data, destoff, | ||
| 1240 | PAGE_ALIGN(destoff + len)-1); | ||
| 1241 | 1309 | ||
| 1242 | if (target_tcon->ses->server->ops->duplicate_extents) | 1310 | /* Flush the source buffer */ |
| 1311 | rc = filemap_write_and_wait_range(src_inode->i_mapping, off, | ||
| 1312 | off + len - 1); | ||
| 1313 | if (rc) | ||
| 1314 | goto unlock; | ||
| 1315 | |||
| 1316 | /* The server-side copy will fail if the source crosses the EOF marker. | ||
| 1317 | * Advance the EOF marker after the flush above to the end of the range | ||
| 1318 | * if it's short of that. | ||
| 1319 | */ | ||
| 1320 | if (src_cifsi->netfs.remote_i_size < off + len) { | ||
| 1321 | rc = cifs_precopy_set_eof(src_inode, src_cifsi, src_tcon, xid, off + len); | ||
| 1322 | if (rc < 0) | ||
| 1323 | goto unlock; | ||
| 1324 | } | ||
| 1325 | |||
| 1326 | new_size = destoff + len; | ||
| 1327 | destend = destoff + len - 1; | ||
| 1328 | |||
| 1329 | /* Flush the folios at either end of the destination range to prevent | ||
| 1330 | * accidental loss of dirty data outside of the range. | ||
| 1331 | */ | ||
| 1332 | fstart = destoff; | ||
| 1333 | fend = destend; | ||
| 1334 | |||
| 1335 | rc = cifs_flush_folio(target_inode, destoff, &fstart, &fend, true); | ||
| 1336 | if (rc) | ||
| 1337 | goto unlock; | ||
| 1338 | rc = cifs_flush_folio(target_inode, destend, &fstart, &fend, false); | ||
| 1339 | if (rc) | ||
| 1340 | goto unlock; | ||
| 1341 | |||
| 1342 | /* Discard all the folios that overlap the destination region. */ | ||
| 1343 | cifs_dbg(FYI, "about to discard pages %llx-%llx\n", fstart, fend); | ||
| 1344 | truncate_inode_pages_range(&target_inode->i_data, fstart, fend); | ||
| 1345 | |||
| 1346 | fscache_invalidate(cifs_inode_cookie(target_inode), NULL, | ||
| 1347 | i_size_read(target_inode), 0); | ||
| 1348 | |||
| 1349 | rc = -EOPNOTSUPP; | ||
| 1350 | if (target_tcon->ses->server->ops->duplicate_extents) { | ||
| 1243 | rc = target_tcon->ses->server->ops->duplicate_extents(xid, | 1351 | rc = target_tcon->ses->server->ops->duplicate_extents(xid, |
| 1244 | smb_file_src, smb_file_target, off, len, destoff); | 1352 | smb_file_src, smb_file_target, off, len, destoff); |
| 1245 | else | 1353 | if (rc == 0 && new_size > i_size_read(target_inode)) { |
| 1246 | rc = -EOPNOTSUPP; | 1354 | truncate_setsize(target_inode, new_size); |
| 1355 | netfs_resize_file(&target_cifsi->netfs, new_size); | ||
| 1356 | fscache_resize_cookie(cifs_inode_cookie(target_inode), | ||
| 1357 | new_size); | ||
| 1358 | } | ||
| 1359 | } | ||
| 1247 | 1360 | ||
| 1248 | /* force revalidate of size and timestamps of target file now | 1361 | /* force revalidate of size and timestamps of target file now |
| 1249 | that target is updated on the server */ | 1362 | that target is updated on the server */ |
| 1250 | CIFS_I(target_inode)->time = 0; | 1363 | CIFS_I(target_inode)->time = 0; |
| 1364 | unlock: | ||
| 1251 | /* although unlocking in the reverse order from locking is not | 1365 | /* although unlocking in the reverse order from locking is not |
| 1252 | strictly necessary here it is a little cleaner to be consistent */ | 1366 | strictly necessary here it is a little cleaner to be consistent */ |
| 1253 | unlock_two_nondirectories(src_inode, target_inode); | 1367 | unlock_two_nondirectories(src_inode, target_inode); |
| @@ -1263,10 +1377,12 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, · 9 unmodified lines | |||
| 1263 | { | 1377 | { |
| 1264 | struct inode *src_inode = file_inode(src_file); | 1378 | struct inode *src_inode = file_inode(src_file); |
| 1265 | struct inode *target_inode = file_inode(dst_file); | 1379 | struct inode *target_inode = file_inode(dst_file); |
| 1380 | struct cifsInodeInfo *src_cifsi = CIFS_I(src_inode); | ||
| 1266 | struct cifsFileInfo *smb_file_src; | 1381 | struct cifsFileInfo *smb_file_src; |
| 1267 | struct cifsFileInfo *smb_file_target; | 1382 | struct cifsFileInfo *smb_file_target; |
| 1268 | struct cifs_tcon *src_tcon; | 1383 | struct cifs_tcon *src_tcon; |
| 1269 | struct cifs_tcon *target_tcon; | 1384 | struct cifs_tcon *target_tcon; |
| 1385 | unsigned long long destend, fstart, fend; | ||
| 1270 | ssize_t rc; | 1386 | ssize_t rc; |
| 1271 | 1387 | ||
| 1272 | cifs_dbg(FYI, "copychunk range\n"); | 1388 | cifs_dbg(FYI, "copychunk range\n"); |
| @@ -1306,13 +1422,41 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, · 33 unmodified lines | |||
| 1306 | if (rc) | 1422 | if (rc) |
| 1307 | goto unlock; | 1423 | goto unlock; |
| 1308 | 1424 | ||
| 1309 | /* should we flush first and last page first */ | 1425 | /* The server-side copy will fail if the source crosses the EOF marker. |
| 1310 | truncate_inode_pages(&target_inode->i_data, 0); | 1426 | * Advance the EOF marker after the flush above to the end of the range |
| 1427 | * if it's short of that. | ||
| 1428 | */ | ||
| 1429 | if (src_cifsi->server_eof < off + len) { | ||
| 1430 | rc = cifs_precopy_set_eof(src_inode, src_cifsi, src_tcon, xid, off + len); | ||
| 1431 | if (rc < 0) | ||
| 1432 | goto unlock; | ||
| 1433 | } | ||
| 1434 | |||
| 1435 | destend = destoff + len - 1; | ||
| 1436 | |||
| 1437 | /* Flush the folios at either end of the destination range to prevent | ||
| 1438 | * accidental loss of dirty data outside of the range. | ||
| 1439 | */ | ||
| 1440 | fstart = destoff; | ||
| 1441 | fend = destend; | ||
| 1442 | |||
| 1443 | rc = cifs_flush_folio(target_inode, destoff, &fstart, &fend, true); | ||
| 1444 | if (rc) | ||
| 1445 | goto unlock; | ||
| 1446 | rc = cifs_flush_folio(target_inode, destend, &fstart, &fend, false); | ||
| 1447 | if (rc) | ||
| 1448 | goto unlock; | ||
| 1449 | |||
| 1450 | /* Discard all the folios that overlap the destination region. */ | ||
| 1451 | truncate_inode_pages_range(&target_inode->i_data, fstart, fend); | ||
| 1311 | 1452 | ||
| 1312 | rc = file_modified(dst_file); | 1453 | rc = file_modified(dst_file); |
| 1313 | if (!rc) | 1454 | if (!rc) { |
| 1314 | rc = target_tcon->ses->server->ops->copychunk_range(xid, | 1455 | rc = target_tcon->ses->server->ops->copychunk_range(xid, |
| 1315 | smb_file_src, smb_file_target, off, len, destoff); | 1456 | smb_file_src, smb_file_target, off, len, destoff); |
| 1457 | if (rc > 0 && destoff + rc > i_size_read(target_inode)) | ||
| 1458 | truncate_setsize(target_inode, destoff + rc); | ||
| 1459 | } | ||
| 1316 | 1460 | ||
| 1317 | file_accessed(src_file); | 1461 | file_accessed(src_file); |
| 1318 | 1462 | ||
| @@ -402,13 +402,7 @@ static int __cifs_reconnect(struct TCP_Server_Info *server, · 401 unmodified lines | |||
| 402 | spin_unlock(&server->srv_lock); | 402 | spin_unlock(&server->srv_lock); |
| 403 | cifs_swn_reset_server_dstaddr(server); | 403 | cifs_swn_reset_server_dstaddr(server); |
| 404 | cifs_server_unlock(server); | 404 | cifs_server_unlock(server); |
| 405 | 405 | mod_delayed_work(cifsiod_wq, &server->reconnect, 0); | |
| 406 | /* increase ref count which reconnect work will drop */ | ||
| 407 | spin_lock(&cifs_tcp_ses_lock); | ||
| 408 | server->srv_count++; | ||
| 409 | spin_unlock(&cifs_tcp_ses_lock); | ||
| 410 | if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0)) | ||
| 411 | cifs_put_tcp_session(server, false); | ||
| 412 | } | 406 | } |
| 413 | } while (server->tcpStatus == CifsNeedReconnect); | 407 | } while (server->tcpStatus == CifsNeedReconnect); |
| 414 | 408 | ||
| @@ -538,13 +532,7 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server) · 123 unmodified lines | |||
| 538 | spin_unlock(&server->srv_lock); | 532 | spin_unlock(&server->srv_lock); |
| 539 | cifs_swn_reset_server_dstaddr(server); | 533 | cifs_swn_reset_server_dstaddr(server); |
| 540 | cifs_server_unlock(server); | 534 | cifs_server_unlock(server); |
| 541 | 535 | mod_delayed_work(cifsiod_wq, &server->reconnect, 0); | |
| 542 | /* increase ref count which reconnect work will drop */ | ||
| 543 | spin_lock(&cifs_tcp_ses_lock); | ||
| 544 | server->srv_count++; | ||
| 545 | spin_unlock(&cifs_tcp_ses_lock); | ||
| 546 | if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0)) | ||
| 547 | cifs_put_tcp_session(server, false); | ||
| 548 | } while (server->tcpStatus == CifsNeedReconnect); | 536 | } while (server->tcpStatus == CifsNeedReconnect); |
| 549 | 537 | ||
| 550 | mutex_lock(&server->refpath_lock); | 538 | mutex_lock(&server->refpath_lock); |
| @@ -1620,25 +1608,22 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect) · 1069 unmodified lines | |||
| 1620 | list_del_init(&server->tcp_ses_list); | 1608 | list_del_init(&server->tcp_ses_list); |
| 1621 | spin_unlock(&cifs_tcp_ses_lock); | 1609 | spin_unlock(&cifs_tcp_ses_lock); |
| 1622 | 1610 | ||
| 1623 | /* For secondary channels, we pick up ref-count on the primary server */ | ||
| 1624 | if (SERVER_IS_CHAN(server)) | ||
| 1625 | cifs_put_tcp_session(server->primary_server, from_reconnect); | ||
| 1626 | |||
| 1627 | cancel_delayed_work_sync(&server->echo); | 1611 | cancel_delayed_work_sync(&server->echo); |
| 1628 | 1612 | ||
| 1629 | if (from_reconnect) { | 1613 | if (from_reconnect) |
| 1630 | /* | 1614 | /* |
| 1631 | * Avoid deadlock here: reconnect work calls | 1615 | * Avoid deadlock here: reconnect work calls |
| 1632 | * cifs_put_tcp_session() at its end. Need to be sure | 1616 | * cifs_put_tcp_session() at its end. Need to be sure |
| 1633 | * that reconnect work does nothing with server pointer after | 1617 | * that reconnect work does nothing with server pointer after |
| 1634 | * that step. | 1618 | * that step. |
| 1635 | */ | 1619 | */ |
| 1636 | if (cancel_delayed_work(&server->reconnect)) | 1620 | cancel_delayed_work(&server->reconnect); |
| 1637 | cifs_put_tcp_session(server, from_reconnect); | 1621 | else |
| 1638 | } else { | 1622 | cancel_delayed_work_sync(&server->reconnect); |
| 1639 | if (cancel_delayed_work_sync(&server->reconnect)) | 1623 | |
| 1640 | cifs_put_tcp_session(server, from_reconnect); | 1624 | /* For secondary channels, we pick up ref-count on the primary server */ |
| 1641 | } | 1625 | if (SERVER_IS_CHAN(server)) |
| 1626 | cifs_put_tcp_session(server->primary_server, from_reconnect); | ||
| 1642 | 1627 | ||
| 1643 | spin_lock(&server->srv_lock); | 1628 | spin_lock(&server->srv_lock); |
| 1644 | server->tcpStatus = CifsExiting; | 1629 | server->tcpStatus = CifsExiting; |
| @@ -2836,6 +2836,8 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses, · 2835 unmodified lines | |||
| 2836 | usleep_range(512, 2048); | 2836 | usleep_range(512, 2048); |
| 2837 | } while (++retry_count < 5); | 2837 | } while (++retry_count < 5); |
| 2838 | 2838 | ||
| 2839 | if (!rc && !dfs_rsp) | ||
| 2840 | rc = -EIO; | ||
| 2839 | if (rc) { | 2841 | if (rc) { |
| 2840 | if (!is_retryable_error(rc) && rc != -ENOENT && rc != -EOPNOTSUPP) | 2842 | if (!is_retryable_error(rc) && rc != -ENOENT && rc != -EOPNOTSUPP) |
| 2841 | cifs_tcon_dbg(VFS, "%s: ioctl error: rc=%d\n", __func__, rc); | 2843 | cifs_tcon_dbg(VFS, "%s: ioctl error: rc=%d\n", __func__, rc); |
| @@ -158,7 +158,7 @@ out: · 157 unmodified lines | |||
| 158 | 158 | ||
| 159 | static int | 159 | static int |
| 160 | smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, | 160 | smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, |
| 161 | struct TCP_Server_Info *server) | 161 | struct TCP_Server_Info *server, bool from_reconnect) |
| 162 | { | 162 | { |
| 163 | int rc = 0; | 163 | int rc = 0; |
| 164 | struct nls_table *nls_codepage = NULL; | 164 | struct nls_table *nls_codepage = NULL; |
| @@ -331,7 +331,7 @@ again: · 166 unmodified lines | |||
| 331 | * as cifs_put_tcp_session takes a higher lock | 331 | * as cifs_put_tcp_session takes a higher lock |
| 332 | * i.e. cifs_tcp_ses_lock | 332 | * i.e. cifs_tcp_ses_lock |
| 333 | */ | 333 | */ |
| 334 | cifs_put_tcp_session(server, 1); | 334 | cifs_put_tcp_session(server, from_reconnect); |
| 335 | 335 | ||
| 336 | server->terminate = true; | 336 | server->terminate = true; |
| 337 | cifs_signal_cifsd_for_reconnect(server, false); | 337 | cifs_signal_cifsd_for_reconnect(server, false); |
| @@ -499,7 +499,7 @@ static int smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon, · 161 unmodified lines | |||
| 499 | { | 499 | { |
| 500 | int rc; | 500 | int rc; |
| 501 | 501 | ||
| 502 | rc = smb2_reconnect(smb2_command, tcon, server); | 502 | rc = smb2_reconnect(smb2_command, tcon, server, false); |
| 503 | if (rc) | 503 | if (rc) |
| 504 | return rc; | 504 | return rc; |
| 505 | 505 | ||
| @@ -3895,6 +3895,15 @@ void smb2_reconnect_server(struct work_struct *work) · 3389 unmodified lines | |||
| 3895 | int rc; | 3895 | int rc; |
| 3896 | bool resched = false; | 3896 | bool resched = false; |
| 3897 | 3897 | ||
| 3898 | /* first check if ref count has reached 0, if not inc ref count */ | ||
| 3899 | spin_lock(&cifs_tcp_ses_lock); | ||
| 3900 | if (!server->srv_count) { | ||
| 3901 | spin_unlock(&cifs_tcp_ses_lock); | ||
| 3902 | return; | ||
| 3903 | } | ||
| 3904 | server->srv_count++; | ||
| 3905 | spin_unlock(&cifs_tcp_ses_lock); | ||
| 3906 | |||
| 3898 | /* If server is a channel, select the primary channel */ | 3907 | /* If server is a channel, select the primary channel */ |
| 3899 | pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; | 3908 | pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; |
| 3900 | 3909 | ||
| @@ -3952,11 +3961,10 @@ void smb2_reconnect_server(struct work_struct *work) · 51 unmodified lines | |||
| 3952 | } | 3961 | } |
| 3953 | spin_unlock(&ses->chan_lock); | 3962 | spin_unlock(&ses->chan_lock); |
| 3954 | } | 3963 | } |
| 3955 | |||
| 3956 | spin_unlock(&cifs_tcp_ses_lock); | 3964 | spin_unlock(&cifs_tcp_ses_lock); |
| 3957 | 3965 | ||
| 3958 | list_for_each_entry_safe(tcon, tcon2, &tmp_list, rlist) { | 3966 | list_for_each_entry_safe(tcon, tcon2, &tmp_list, rlist) { |
| 3959 | rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server); | 3967 | rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server, true); |
| 3960 | if (!rc) | 3968 | if (!rc) |
| 3961 | cifs_reopen_persistent_handles(tcon); | 3969 | cifs_reopen_persistent_handles(tcon); |
| 3962 | else | 3970 | else |
| @@ -3989,7 +3997,7 @@ void smb2_reconnect_server(struct work_struct *work) · 26 unmodified lines | |||
| 3989 | /* now reconnect sessions for necessary channels */ | 3997 | /* now reconnect sessions for necessary channels */ |
| 3990 | list_for_each_entry_safe(ses, ses2, &tmp_ses_list, rlist) { | 3998 | list_for_each_entry_safe(ses, ses2, &tmp_ses_list, rlist) { |
| 3991 | tcon->ses = ses; | 3999 | tcon->ses = ses; |
| 3992 | rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server); | 4000 | rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server, true); |
| 3993 | if (rc) | 4001 | if (rc) |
| 3994 | resched = true; | 4002 | resched = true; |
| 3995 | list_del_init(&ses->rlist); | 4003 | list_del_init(&ses->rlist); |
| @@ -3999,13 +4007,8 @@ void smb2_reconnect_server(struct work_struct *work) · 3 unmodified lines | |||
| 3999 | 4007 | ||
| 4000 | done: | 4008 | done: |
| 4001 | cifs_dbg(FYI, "Reconnecting tcons and channels finished\n"); | 4009 | cifs_dbg(FYI, "Reconnecting tcons and channels finished\n"); |
| 4002 | if (resched) { | 4010 | if (resched) |
| 4003 | queue_delayed_work(cifsiod_wq, &server->reconnect, 2 * HZ); | 4011 | queue_delayed_work(cifsiod_wq, &server->reconnect, 2 * HZ); |
| 4004 | mutex_unlock(&pserver->reconnect_mutex); | ||
| 4005 | |||
| 4006 | /* no need to put tcp session as we're retrying */ | ||
| 4007 | return; | ||
| 4008 | } | ||
| 4009 | mutex_unlock(&pserver->reconnect_mutex); | 4012 | mutex_unlock(&pserver->reconnect_mutex); |
| 4010 | 4013 | ||
| 4011 | /* now we can safely release srv struct */ | 4014 | /* now we can safely release srv struct */ |
| @@ -4029,12 +4032,7 @@ SMB2_echo(struct TCP_Server_Info *server) · 17 unmodified lines | |||
| 4029 | server->ops->need_neg(server)) { | 4032 | server->ops->need_neg(server)) { |
| 4030 | spin_unlock(&server->srv_lock); | 4033 | spin_unlock(&server->srv_lock); |
| 4031 | /* No need to send echo on newly established connections */ | 4034 | /* No need to send echo on newly established connections */ |
| 4032 | spin_lock(&cifs_tcp_ses_lock); | 4035 | mod_delayed_work(cifsiod_wq, &server->reconnect, 0); |
| 4033 | server->srv_count++; | ||
| 4034 | spin_unlock(&cifs_tcp_ses_lock); | ||
| 4035 | if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0)) | ||
| 4036 | cifs_put_tcp_session(server, false); | ||
| 4037 | |||
| 4038 | return rc; | 4036 | return rc; |
| 4039 | } | 4037 | } |
| 4040 | spin_unlock(&server->srv_lock); | 4038 | spin_unlock(&server->srv_lock); |