Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag '6.7-rc4-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

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()

+187 -58
+159 -15
fs/smb/client/cifsfs.c
··· 1196 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 1265 static loff_t cifs_remap_file_range(struct file *src_file, loff_t off, 1200 1266 struct file *dst_file, loff_t destoff, loff_t len, 1201 1267 unsigned int remap_flags) 1202 1268 { 1203 1269 struct inode *src_inode = file_inode(src_file); 1204 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 1273 struct cifsFileInfo *smb_file_src = src_file->private_data; 1206 - struct cifsFileInfo *smb_file_target; 1207 - struct cifs_tcon *target_tcon; 1274 + struct cifsFileInfo *smb_file_target = dst_file->private_data; 1275 + struct cifs_tcon *target_tcon, *src_tcon; 1276 + unsigned long long destend, fstart, fend, new_size; 1208 1277 unsigned int xid; 1209 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 1283 return -EINVAL; 1213 1284 1214 1285 cifs_dbg(FYI, "clone range\n"); 1215 1286 1216 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 1290 rc = -EBADF; 1220 1291 cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n"); 1221 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 1296 target_tcon = tlink_tcon(smb_file_target->tlink); 1226 1297 1227 1298 /* ··· 1305 1234 if (len == 0) 1306 1235 len = src_inode->i_size - off; 1307 1236 1308 - cifs_dbg(FYI, "about to flush pages\n"); 1309 - /* should we flush first and last page first */ 1310 - truncate_inode_pages_range(&target_inode->i_data, destoff, 1311 - PAGE_ALIGN(destoff + len)-1); 1237 + cifs_dbg(FYI, "clone range\n"); 1312 1238 1313 - if (target_tcon->ses->server->ops->duplicate_extents) 1239 + /* Flush the source buffer */ 1240 + rc = filemap_write_and_wait_range(src_inode->i_mapping, off, 1241 + off + len - 1); 1242 + if (rc) 1243 + goto unlock; 1244 + 1245 + /* The server-side copy will fail if the source crosses the EOF marker. 1246 + * Advance the EOF marker after the flush above to the end of the range 1247 + * if it's short of that. 1248 + */ 1249 + if (src_cifsi->netfs.remote_i_size < off + len) { 1250 + rc = cifs_precopy_set_eof(src_inode, src_cifsi, src_tcon, xid, off + len); 1251 + if (rc < 0) 1252 + goto unlock; 1253 + } 1254 + 1255 + new_size = destoff + len; 1256 + destend = destoff + len - 1; 1257 + 1258 + /* Flush the folios at either end of the destination range to prevent 1259 + * accidental loss of dirty data outside of the range. 1260 + */ 1261 + fstart = destoff; 1262 + fend = destend; 1263 + 1264 + rc = cifs_flush_folio(target_inode, destoff, &fstart, &fend, true); 1265 + if (rc) 1266 + goto unlock; 1267 + rc = cifs_flush_folio(target_inode, destend, &fstart, &fend, false); 1268 + if (rc) 1269 + goto unlock; 1270 + 1271 + /* Discard all the folios that overlap the destination region. */ 1272 + cifs_dbg(FYI, "about to discard pages %llx-%llx\n", fstart, fend); 1273 + truncate_inode_pages_range(&target_inode->i_data, fstart, fend); 1274 + 1275 + fscache_invalidate(cifs_inode_cookie(target_inode), NULL, 1276 + i_size_read(target_inode), 0); 1277 + 1278 + rc = -EOPNOTSUPP; 1279 + if (target_tcon->ses->server->ops->duplicate_extents) { 1314 1280 rc = target_tcon->ses->server->ops->duplicate_extents(xid, 1315 1281 smb_file_src, smb_file_target, off, len, destoff); 1316 - else 1317 - rc = -EOPNOTSUPP; 1282 + if (rc == 0 && new_size > i_size_read(target_inode)) { 1283 + truncate_setsize(target_inode, new_size); 1284 + netfs_resize_file(&target_cifsi->netfs, new_size); 1285 + fscache_resize_cookie(cifs_inode_cookie(target_inode), 1286 + new_size); 1287 + } 1288 + } 1318 1289 1319 1290 /* force revalidate of size and timestamps of target file now 1320 1291 that target is updated on the server */ 1321 1292 CIFS_I(target_inode)->time = 0; 1293 + unlock: 1322 1294 /* although unlocking in the reverse order from locking is not 1323 1295 strictly necessary here it is a little cleaner to be consistent */ 1324 1296 unlock_two_nondirectories(src_inode, target_inode); ··· 1377 1263 { 1378 1264 struct inode *src_inode = file_inode(src_file); 1379 1265 struct inode *target_inode = file_inode(dst_file); 1266 + struct cifsInodeInfo *src_cifsi = CIFS_I(src_inode); 1380 1267 struct cifsFileInfo *smb_file_src; 1381 1268 struct cifsFileInfo *smb_file_target; 1382 1269 struct cifs_tcon *src_tcon; 1383 1270 struct cifs_tcon *target_tcon; 1271 + unsigned long long destend, fstart, fend; 1384 1272 ssize_t rc; 1385 1273 1386 1274 cifs_dbg(FYI, "copychunk range\n"); ··· 1422 1306 if (rc) 1423 1307 goto unlock; 1424 1308 1425 - /* should we flush first and last page first */ 1426 - truncate_inode_pages(&target_inode->i_data, 0); 1309 + /* The server-side copy will fail if the source crosses the EOF marker. 1310 + * Advance the EOF marker after the flush above to the end of the range 1311 + * if it's short of that. 1312 + */ 1313 + if (src_cifsi->server_eof < off + len) { 1314 + rc = cifs_precopy_set_eof(src_inode, src_cifsi, src_tcon, xid, off + len); 1315 + if (rc < 0) 1316 + goto unlock; 1317 + } 1318 + 1319 + destend = destoff + len - 1; 1320 + 1321 + /* Flush the folios at either end of the destination range to prevent 1322 + * accidental loss of dirty data outside of the range. 1323 + */ 1324 + fstart = destoff; 1325 + fend = destend; 1326 + 1327 + rc = cifs_flush_folio(target_inode, destoff, &fstart, &fend, true); 1328 + if (rc) 1329 + goto unlock; 1330 + rc = cifs_flush_folio(target_inode, destend, &fstart, &fend, false); 1331 + if (rc) 1332 + goto unlock; 1333 + 1334 + /* Discard all the folios that overlap the destination region. */ 1335 + truncate_inode_pages_range(&target_inode->i_data, fstart, fend); 1427 1336 1428 1337 rc = file_modified(dst_file); 1429 - if (!rc) 1338 + if (!rc) { 1430 1339 rc = target_tcon->ses->server->ops->copychunk_range(xid, 1431 1340 smb_file_src, smb_file_target, off, len, destoff); 1341 + if (rc > 0 && destoff + rc > i_size_read(target_inode)) 1342 + truncate_setsize(target_inode, destoff + rc); 1343 + } 1432 1344 1433 1345 file_accessed(src_file); 1434 1346
+10 -25
fs/smb/client/connect.c
··· 402 402 spin_unlock(&server->srv_lock); 403 403 cifs_swn_reset_server_dstaddr(server); 404 404 cifs_server_unlock(server); 405 - 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); 405 + mod_delayed_work(cifsiod_wq, &server->reconnect, 0); 412 406 } 413 407 } while (server->tcpStatus == CifsNeedReconnect); 414 408 ··· 532 538 spin_unlock(&server->srv_lock); 533 539 cifs_swn_reset_server_dstaddr(server); 534 540 cifs_server_unlock(server); 535 - 536 - /* increase ref count which reconnect work will drop */ 537 - spin_lock(&cifs_tcp_ses_lock); 538 - server->srv_count++; 539 - spin_unlock(&cifs_tcp_ses_lock); 540 - if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0)) 541 - cifs_put_tcp_session(server, false); 541 + mod_delayed_work(cifsiod_wq, &server->reconnect, 0); 542 542 } while (server->tcpStatus == CifsNeedReconnect); 543 543 544 544 mutex_lock(&server->refpath_lock); ··· 1608 1620 list_del_init(&server->tcp_ses_list); 1609 1621 spin_unlock(&cifs_tcp_ses_lock); 1610 1622 1611 - /* For secondary channels, we pick up ref-count on the primary server */ 1612 - if (SERVER_IS_CHAN(server)) 1613 - cifs_put_tcp_session(server->primary_server, from_reconnect); 1614 - 1615 1623 cancel_delayed_work_sync(&server->echo); 1616 1624 1617 - if (from_reconnect) { 1625 + if (from_reconnect) 1618 1626 /* 1619 1627 * Avoid deadlock here: reconnect work calls 1620 1628 * cifs_put_tcp_session() at its end. Need to be sure 1621 1629 * that reconnect work does nothing with server pointer after 1622 1630 * that step. 1623 1631 */ 1624 - if (cancel_delayed_work(&server->reconnect)) 1625 - cifs_put_tcp_session(server, from_reconnect); 1626 - } else { 1627 - if (cancel_delayed_work_sync(&server->reconnect)) 1628 - cifs_put_tcp_session(server, from_reconnect); 1629 - } 1632 + cancel_delayed_work(&server->reconnect); 1633 + else 1634 + cancel_delayed_work_sync(&server->reconnect); 1635 + 1636 + /* For secondary channels, we pick up ref-count on the primary server */ 1637 + if (SERVER_IS_CHAN(server)) 1638 + cifs_put_tcp_session(server->primary_server, from_reconnect); 1630 1639 1631 1640 spin_lock(&server->srv_lock); 1632 1641 server->tcpStatus = CifsExiting;
+2
fs/smb/client/smb2ops.c
··· 2836 2836 usleep_range(512, 2048); 2837 2837 } while (++retry_count < 5); 2838 2838 2839 + if (!rc && !dfs_rsp) 2840 + rc = -EIO; 2839 2841 if (rc) { 2840 2842 if (!is_retryable_error(rc) && rc != -ENOENT && rc != -EOPNOTSUPP) 2841 2843 cifs_tcon_dbg(VFS, "%s: ioctl error: rc=%d\n", __func__, rc);
+16 -18
fs/smb/client/smb2pdu.c
··· 158 158 159 159 static int 160 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 163 int rc = 0; 164 164 struct nls_table *nls_codepage = NULL; ··· 331 331 * as cifs_put_tcp_session takes a higher lock 332 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 336 server->terminate = true; 337 337 cifs_signal_cifsd_for_reconnect(server, false); ··· 499 499 { 500 500 int rc; 501 501 502 - rc = smb2_reconnect(smb2_command, tcon, server); 502 + rc = smb2_reconnect(smb2_command, tcon, server, false); 503 503 if (rc) 504 504 return rc; 505 505 ··· 3895 3895 int rc; 3896 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 3907 /* If server is a channel, select the primary channel */ 3899 3908 pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; 3900 3909 ··· 3961 3952 } 3962 3953 spin_unlock(&ses->chan_lock); 3963 3954 } 3964 - 3965 3955 spin_unlock(&cifs_tcp_ses_lock); 3966 3956 3967 3957 list_for_each_entry_safe(tcon, tcon2, &tmp_list, rlist) { 3968 - rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server); 3958 + rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server, true); 3969 3959 if (!rc) 3970 3960 cifs_reopen_persistent_handles(tcon); 3971 3961 else ··· 3997 3989 /* now reconnect sessions for necessary channels */ 3998 3990 list_for_each_entry_safe(ses, ses2, &tmp_ses_list, rlist) { 3999 3991 tcon->ses = ses; 4000 - rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server); 3992 + rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server, true); 4001 3993 if (rc) 4002 3994 resched = true; 4003 3995 list_del_init(&ses->rlist); ··· 4007 3999 4008 4000 done: 4009 4001 cifs_dbg(FYI, "Reconnecting tcons and channels finished\n"); 4010 - if (resched) { 4002 + if (resched) 4011 4003 queue_delayed_work(cifsiod_wq, &server->reconnect, 2 * HZ); 4012 - mutex_unlock(&pserver->reconnect_mutex); 4013 - 4014 - /* no need to put tcp session as we're retrying */ 4015 - return; 4016 - } 4017 4004 mutex_unlock(&pserver->reconnect_mutex); 4018 4005 4019 4006 /* now we can safely release srv struct */ ··· 4032 4029 server->ops->need_neg(server)) { 4033 4030 spin_unlock(&server->srv_lock); 4034 4031 /* No need to send echo on newly established connections */ 4035 - spin_lock(&cifs_tcp_ses_lock); 4036 - server->srv_count++; 4037 - spin_unlock(&cifs_tcp_ses_lock); 4038 - if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0)) 4039 - cifs_put_tcp_session(server, false); 4040 - 4032 + mod_delayed_work(cifsiod_wq, &server->reconnect, 0); 4041 4033 return rc; 4042 4034 } 4043 4035 spin_unlock(&server->srv_lock);