@@ -1196,32 +1196,103 @@ const struct inode_operations cifs_symlink_inode_ops = {
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+
11991265static 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,
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,
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,
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
0 commit comments