History

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

Linus Torvalds committed 2 years ago

Commit 20993062 parents f2e8a57 04909194 files · +187 −58Browse files

Unified · Split

4 files
  1. fs/smb/client/cifsfs.c +159 −15
  2. fs/smb/client/connect.c +10 −25
  3. fs/smb/client/smb2ops.c +2 −0
  4. fs/smb/client/smb2pdu.c +16 −18
fs/smb/client/cifsfs.c+159−15
@@ -1196,32 +1196,103 @@ const struct inode_operations cifs_symlink_inode_ops = { · 1195 unmodified lines
11961196 .listxattr = cifs_listxattr,
11971197 };
11981198
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+
11991265 static loff_t cifs_remap_file_range(struct file *src_file, loff_t off,
12001266 struct file *dst_file, loff_t destoff, loff_t len,
12011267 unsigned int remap_flags)
12021268 {
12031269 struct inode *src_inode = file_inode(src_file);
12041270 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);
12051273 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;
12081277 unsigned int xid;
12091278 int rc;
12101279
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)
12121283 return -EINVAL;
12131284
12141285 cifs_dbg(FYI, "clone range\n");
12151286
12161287 xid = get_xid();
12171288
1218− if (!src_file->private_data || !dst_file->private_data) {
1289+ if (!smb_file_src || !smb_file_target) {
12191290 rc = -EBADF;
12201291 cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n");
12211292 goto out;
12221293 }
12231294
1224− smb_file_target = dst_file->private_data;
1295+ src_tcon = tlink_tcon(smb_file_src->tlink);
12251296 target_tcon = tlink_tcon(smb_file_target->tlink);
12261297
12271298 /*
@@ -1234,20 +1305,63 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off, · 6 unmodified lines
12341305 if (len == 0)
12351306 len = src_inode->i_size - off;
12361307
1237− cifs_dbg(FYI, "about to flush pages\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);
1308+ cifs_dbg(FYI, "clone range\n");
12411309
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) {
12431351 rc = target_tcon->ses->server->ops->duplicate_extents(xid,
12441352 smb_file_src, smb_file_target, off, len, destoff);
1245− else
1246− rc = -EOPNOTSUPP;
1353+ if (rc == 0 && new_size > i_size_read(target_inode)) {
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+ }
12471360
12481361 /* force revalidate of size and timestamps of target file now
12491362 that target is updated on the server */
12501363 CIFS_I(target_inode)->time = 0;
1364+unlock:
12511365 /* although unlocking in the reverse order from locking is not
12521366 strictly necessary here it is a little cleaner to be consistent */
12531367 unlock_two_nondirectories(src_inode, target_inode);
@@ -1263,10 +1377,12 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, · 9 unmodified lines
12631377 {
12641378 struct inode *src_inode = file_inode(src_file);
12651379 struct inode *target_inode = file_inode(dst_file);
1380+ struct cifsInodeInfo *src_cifsi = CIFS_I(src_inode);
12661381 struct cifsFileInfo *smb_file_src;
12671382 struct cifsFileInfo *smb_file_target;
12681383 struct cifs_tcon *src_tcon;
12691384 struct cifs_tcon *target_tcon;
1385+ unsigned long long destend, fstart, fend;
12701386 ssize_t rc;
12711387
12721388 cifs_dbg(FYI, "copychunk range\n");
@@ -1306,13 +1422,41 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, · 33 unmodified lines
13061422 if (rc)
13071423 goto unlock;
13081424
1309− /* should we flush first and last page first */
1310− truncate_inode_pages(&target_inode->i_data, 0);
1425+ /* The server-side copy will fail if the source crosses the EOF marker.
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);
13111452
13121453 rc = file_modified(dst_file);
1313− if (!rc)
1454+ if (!rc) {
13141455 rc = target_tcon->ses->server->ops->copychunk_range(xid,
13151456 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+ }
13161460
13171461 file_accessed(src_file);
13181462
fs/smb/client/connect.c+10−25
@@ -402,13 +402,7 @@ static int __cifs_reconnect(struct TCP_Server_Info *server, · 401 unmodified lines
402402 spin_unlock(&server->srv_lock);
403403 cifs_swn_reset_server_dstaddr(server);
404404 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);
412406 }
413407 } while (server->tcpStatus == CifsNeedReconnect);
414408
@@ -538,13 +532,7 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server) · 123 unmodified lines
538532 spin_unlock(&server->srv_lock);
539533 cifs_swn_reset_server_dstaddr(server);
540534 cifs_server_unlock(server);
541−
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);
535+ mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
548536 } while (server->tcpStatus == CifsNeedReconnect);
549537
550538 mutex_lock(&server->refpath_lock);
@@ -1620,25 +1608,22 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect) · 1069 unmodified lines
16201608 list_del_init(&server->tcp_ses_list);
16211609 spin_unlock(&cifs_tcp_ses_lock);
16221610
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−
16271611 cancel_delayed_work_sync(&server->echo);
16281612
1629− if (from_reconnect) {
1613+ if (from_reconnect)
16301614 /*
16311615 * Avoid deadlock here: reconnect work calls
16321616 * cifs_put_tcp_session() at its end. Need to be sure
16331617 * that reconnect work does nothing with server pointer after
16341618 * that step.
16351619 */
1636− if (cancel_delayed_work(&server->reconnect))
1637− cifs_put_tcp_session(server, from_reconnect);
1638− } else {
1639− if (cancel_delayed_work_sync(&server->reconnect))
1640− cifs_put_tcp_session(server, from_reconnect);
1641− }
1620+ cancel_delayed_work(&server->reconnect);
1621+ else
1622+ cancel_delayed_work_sync(&server->reconnect);
1623+
1624+ /* For secondary channels, we pick up ref-count on the primary server */
1625+ if (SERVER_IS_CHAN(server))
1626+ cifs_put_tcp_session(server->primary_server, from_reconnect);
16421627
16431628 spin_lock(&server->srv_lock);
16441629 server->tcpStatus = CifsExiting;
fs/smb/client/smb2ops.c+2−0
@@ -2836,6 +2836,8 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses, · 2835 unmodified lines
28362836 usleep_range(512, 2048);
28372837 } while (++retry_count < 5);
28382838
2839+ if (!rc && !dfs_rsp)
2840+ rc = -EIO;
28392841 if (rc) {
28402842 if (!is_retryable_error(rc) && rc != -ENOENT && rc != -EOPNOTSUPP)
28412843 cifs_tcon_dbg(VFS, "%s: ioctl error: rc=%d\n", __func__, rc);
fs/smb/client/smb2pdu.c+16−18
@@ -158,7 +158,7 @@ out: · 157 unmodified lines
158158
159159 static int
160160 smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
161− struct TCP_Server_Info *server)
161+ struct TCP_Server_Info *server, bool from_reconnect)
162162 {
163163 int rc = 0;
164164 struct nls_table *nls_codepage = NULL;
@@ -331,7 +331,7 @@ again: · 166 unmodified lines
331331 * as cifs_put_tcp_session takes a higher lock
332332 * i.e. cifs_tcp_ses_lock
333333 */
334− cifs_put_tcp_session(server, 1);
334+ cifs_put_tcp_session(server, from_reconnect);
335335
336336 server->terminate = true;
337337 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
499499 {
500500 int rc;
501501
502− rc = smb2_reconnect(smb2_command, tcon, server);
502+ rc = smb2_reconnect(smb2_command, tcon, server, false);
503503 if (rc)
504504 return rc;
505505
@@ -3895,6 +3895,15 @@ void smb2_reconnect_server(struct work_struct *work) · 3389 unmodified lines
38953895 int rc;
38963896 bool resched = false;
38973897
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+
38983907 /* If server is a channel, select the primary channel */
38993908 pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
39003909
@@ -3952,11 +3961,10 @@ void smb2_reconnect_server(struct work_struct *work) · 51 unmodified lines
39523961 }
39533962 spin_unlock(&ses->chan_lock);
39543963 }
3955−
39563964 spin_unlock(&cifs_tcp_ses_lock);
39573965
39583966 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);
39603968 if (!rc)
39613969 cifs_reopen_persistent_handles(tcon);
39623970 else
@@ -3989,7 +3997,7 @@ void smb2_reconnect_server(struct work_struct *work) · 26 unmodified lines
39893997 /* now reconnect sessions for necessary channels */
39903998 list_for_each_entry_safe(ses, ses2, &tmp_ses_list, rlist) {
39913999 tcon->ses = ses;
3992− rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server);
4000+ rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server, true);
39934001 if (rc)
39944002 resched = true;
39954003 list_del_init(&ses->rlist);
@@ -3999,13 +4007,8 @@ void smb2_reconnect_server(struct work_struct *work) · 3 unmodified lines
39994007
40004008 done:
40014009 cifs_dbg(FYI, "Reconnecting tcons and channels finished\n");
4002− if (resched) {
4010+ if (resched)
40034011 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− }
40094012 mutex_unlock(&pserver->reconnect_mutex);
40104013
40114014 /* now we can safely release srv struct */
@@ -4029,12 +4032,7 @@ SMB2_echo(struct TCP_Server_Info *server) · 17 unmodified lines
40294032 server->ops->need_neg(server)) {
40304033 spin_unlock(&server->srv_lock);
40314034 /* No need to send echo on newly established connections */
4032− spin_lock(&cifs_tcp_ses_lock);
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−
4035+ mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
40384036 return rc;
40394037 }
40404038 spin_unlock(&server->srv_lock);