@@ -1196,32 +1196,103 @@ const struct inode_operations cifs_symlink_inode_ops = {
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
/*
@@ -1234,20 +1305,63 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off,
1234
1305
if (len == 0 )
1235
1306
len = src_inode -> i_size - off ;
1236
1307
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" );
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
1351
rc = target_tcon -> ses -> server -> ops -> duplicate_extents (xid ,
1244
1352
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
+ }
1247
1360
1248
1361
/* force revalidate of size and timestamps of target file now
1249
1362
that target is updated on the server */
1250
1363
CIFS_I (target_inode )-> time = 0 ;
1364
+ unlock :
1251
1365
/* although unlocking in the reverse order from locking is not
1252
1366
strictly necessary here it is a little cleaner to be consistent */
1253
1367
unlock_two_nondirectories (src_inode , target_inode );
@@ -1263,10 +1377,12 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
1263
1377
{
1264
1378
struct inode * src_inode = file_inode (src_file );
1265
1379
struct inode * target_inode = file_inode (dst_file );
1380
+ struct cifsInodeInfo * src_cifsi = CIFS_I (src_inode );
1266
1381
struct cifsFileInfo * smb_file_src ;
1267
1382
struct cifsFileInfo * smb_file_target ;
1268
1383
struct cifs_tcon * src_tcon ;
1269
1384
struct cifs_tcon * target_tcon ;
1385
+ unsigned long long destend , fstart , fend ;
1270
1386
ssize_t rc ;
1271
1387
1272
1388
cifs_dbg (FYI , "copychunk range\n" );
@@ -1306,13 +1422,41 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
1306
1422
if (rc )
1307
1423
goto unlock ;
1308
1424
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 );
1311
1452
1312
1453
rc = file_modified (dst_file );
1313
- if (!rc )
1454
+ if (!rc ) {
1314
1455
rc = target_tcon -> ses -> server -> ops -> copychunk_range (xid ,
1315
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
1461
file_accessed (src_file );
1318
1462
0 commit comments