aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2016-10-20 00:50:07 -0400
committerDave Chinner <david@fromorbit.com>2016-10-20 00:50:07 -0400
commit5faaf4fa0a20d38edc4df57baf24ea35b7e91178 (patch)
tree04fbdf80c31a03ec499bc5628cd0454f128420c4
parentec40759902556f21f37641ad9f19d02c4dd4b555 (diff)
xfs: merge xfs_reflink_remap_range and xfs_file_share_range
There is no clear division of responsibility between those functions, so just merge them into one to keep the code simple. Also move xfs_file_wait_for_io to xfs_reflink.c together with its only caller. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r--fs/xfs/xfs_file.c132
-rw-r--r--fs/xfs/xfs_reflink.c178
-rw-r--r--fs/xfs/xfs_reflink.h7
3 files changed, 143 insertions, 174 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 93729752bccb..6e4f7f900fea 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -909,132 +909,6 @@ out_unlock:
909 return error; 909 return error;
910} 910}
911 911
912/* Hook up to the VFS reflink function */
913STATIC int
914xfs_file_share_range(
915 struct file *file_in,
916 loff_t pos_in,
917 struct file *file_out,
918 loff_t pos_out,
919 u64 len,
920 bool is_dedupe)
921{
922 struct inode *inode_in;
923 struct inode *inode_out;
924 ssize_t ret;
925 loff_t bs;
926 loff_t isize;
927 int same_inode;
928 loff_t blen;
929 unsigned int flags = 0;
930
931 inode_in = file_inode(file_in);
932 inode_out = file_inode(file_out);
933 bs = inode_out->i_sb->s_blocksize;
934
935 /* Lock both files against IO */
936 same_inode = (inode_in == inode_out);
937 if (same_inode) {
938 xfs_ilock(XFS_I(inode_in), XFS_IOLOCK_EXCL);
939 xfs_ilock(XFS_I(inode_in), XFS_MMAPLOCK_EXCL);
940 } else {
941 xfs_lock_two_inodes(XFS_I(inode_in), XFS_I(inode_out),
942 XFS_IOLOCK_EXCL);
943 xfs_lock_two_inodes(XFS_I(inode_in), XFS_I(inode_out),
944 XFS_MMAPLOCK_EXCL);
945 }
946
947 /* Don't touch certain kinds of inodes */
948 ret = -EPERM;
949 if (IS_IMMUTABLE(inode_out))
950 goto out_unlock;
951 ret = -ETXTBSY;
952 if (IS_SWAPFILE(inode_in) || IS_SWAPFILE(inode_out))
953 goto out_unlock;
954
955 /* Don't reflink dirs, pipes, sockets... */
956 ret = -EISDIR;
957 if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))
958 goto out_unlock;
959 ret = -EINVAL;
960 if (S_ISFIFO(inode_in->i_mode) || S_ISFIFO(inode_out->i_mode))
961 goto out_unlock;
962 if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode))
963 goto out_unlock;
964
965 /* Don't share DAX file data for now. */
966 if (IS_DAX(inode_in) || IS_DAX(inode_out))
967 goto out_unlock;
968
969 /* Are we going all the way to the end? */
970 isize = i_size_read(inode_in);
971 if (isize == 0) {
972 ret = 0;
973 goto out_unlock;
974 }
975
976 if (len == 0)
977 len = isize - pos_in;
978
979 /* Ensure offsets don't wrap and the input is inside i_size */
980 if (pos_in + len < pos_in || pos_out + len < pos_out ||
981 pos_in + len > isize)
982 goto out_unlock;
983
984 /* Don't allow dedupe past EOF in the dest file */
985 if (is_dedupe) {
986 loff_t disize;
987
988 disize = i_size_read(inode_out);
989 if (pos_out >= disize || pos_out + len > disize)
990 goto out_unlock;
991 }
992
993 /* If we're linking to EOF, continue to the block boundary. */
994 if (pos_in + len == isize)
995 blen = ALIGN(isize, bs) - pos_in;
996 else
997 blen = len;
998
999 /* Only reflink if we're aligned to block boundaries */
1000 if (!IS_ALIGNED(pos_in, bs) || !IS_ALIGNED(pos_in + blen, bs) ||
1001 !IS_ALIGNED(pos_out, bs) || !IS_ALIGNED(pos_out + blen, bs))
1002 goto out_unlock;
1003
1004 /* Don't allow overlapped reflink within the same file */
1005 if (same_inode && pos_out + blen > pos_in && pos_out < pos_in + blen)
1006 goto out_unlock;
1007
1008 /* Wait for the completion of any pending IOs on both files */
1009 inode_dio_wait(inode_in);
1010 if (!same_inode)
1011 inode_dio_wait(inode_out);
1012
1013 ret = filemap_write_and_wait_range(inode_in->i_mapping,
1014 pos_in, pos_in + len - 1);
1015 if (ret)
1016 goto out_unlock;
1017
1018 ret = filemap_write_and_wait_range(inode_out->i_mapping,
1019 pos_out, pos_out + len - 1);
1020 if (ret)
1021 goto out_unlock;
1022
1023 if (is_dedupe)
1024 flags |= XFS_REFLINK_DEDUPE;
1025 ret = xfs_reflink_remap_range(XFS_I(inode_in), pos_in, XFS_I(inode_out),
1026 pos_out, len, flags);
1027
1028out_unlock:
1029 xfs_iunlock(XFS_I(inode_in), XFS_MMAPLOCK_EXCL);
1030 xfs_iunlock(XFS_I(inode_in), XFS_IOLOCK_EXCL);
1031 if (!same_inode) {
1032 xfs_iunlock(XFS_I(inode_out), XFS_MMAPLOCK_EXCL);
1033 xfs_iunlock(XFS_I(inode_out), XFS_IOLOCK_EXCL);
1034 }
1035 return ret;
1036}
1037
1038STATIC ssize_t 912STATIC ssize_t
1039xfs_file_copy_range( 913xfs_file_copy_range(
1040 struct file *file_in, 914 struct file *file_in,
@@ -1046,7 +920,7 @@ xfs_file_copy_range(
1046{ 920{
1047 int error; 921 int error;
1048 922
1049 error = xfs_file_share_range(file_in, pos_in, file_out, pos_out, 923 error = xfs_reflink_remap_range(file_in, pos_in, file_out, pos_out,
1050 len, false); 924 len, false);
1051 if (error) 925 if (error)
1052 return error; 926 return error;
@@ -1061,7 +935,7 @@ xfs_file_clone_range(
1061 loff_t pos_out, 935 loff_t pos_out,
1062 u64 len) 936 u64 len)
1063{ 937{
1064 return xfs_file_share_range(file_in, pos_in, file_out, pos_out, 938 return xfs_reflink_remap_range(file_in, pos_in, file_out, pos_out,
1065 len, false); 939 len, false);
1066} 940}
1067 941
@@ -1084,7 +958,7 @@ xfs_file_dedupe_range(
1084 if (len > XFS_MAX_DEDUPE_LEN) 958 if (len > XFS_MAX_DEDUPE_LEN)
1085 len = XFS_MAX_DEDUPE_LEN; 959 len = XFS_MAX_DEDUPE_LEN;
1086 960
1087 error = xfs_file_share_range(src_file, loff, dst_file, dst_loff, 961 error = xfs_reflink_remap_range(src_file, loff, dst_file, dst_loff,
1088 len, true); 962 len, true);
1089 if (error) 963 if (error)
1090 return error; 964 return error;
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index 3b1c1a6bb5da..6592daa833a4 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -1312,19 +1312,26 @@ out_error:
1312 */ 1312 */
1313int 1313int
1314xfs_reflink_remap_range( 1314xfs_reflink_remap_range(
1315 struct xfs_inode *src, 1315 struct file *file_in,
1316 xfs_off_t srcoff, 1316 loff_t pos_in,
1317 struct xfs_inode *dest, 1317 struct file *file_out,
1318 xfs_off_t destoff, 1318 loff_t pos_out,
1319 xfs_off_t len, 1319 u64 len,
1320 unsigned int flags) 1320 bool is_dedupe)
1321{ 1321{
1322 struct inode *inode_in = file_inode(file_in);
1323 struct xfs_inode *src = XFS_I(inode_in);
1324 struct inode *inode_out = file_inode(file_out);
1325 struct xfs_inode *dest = XFS_I(inode_out);
1322 struct xfs_mount *mp = src->i_mount; 1326 struct xfs_mount *mp = src->i_mount;
1327 loff_t bs = inode_out->i_sb->s_blocksize;
1328 bool same_inode = (inode_in == inode_out);
1323 xfs_fileoff_t sfsbno, dfsbno; 1329 xfs_fileoff_t sfsbno, dfsbno;
1324 xfs_filblks_t fsblen; 1330 xfs_filblks_t fsblen;
1325 int error;
1326 xfs_extlen_t cowextsize; 1331 xfs_extlen_t cowextsize;
1327 bool is_same; 1332 loff_t isize;
1333 ssize_t ret;
1334 loff_t blen;
1328 1335
1329 if (!xfs_sb_version_hasreflink(&mp->m_sb)) 1336 if (!xfs_sb_version_hasreflink(&mp->m_sb))
1330 return -EOPNOTSUPP; 1337 return -EOPNOTSUPP;
@@ -1332,48 +1339,135 @@ xfs_reflink_remap_range(
1332 if (XFS_FORCED_SHUTDOWN(mp)) 1339 if (XFS_FORCED_SHUTDOWN(mp))
1333 return -EIO; 1340 return -EIO;
1334 1341
1342 /* Lock both files against IO */
1343 if (same_inode) {
1344 xfs_ilock(src, XFS_IOLOCK_EXCL);
1345 xfs_ilock(src, XFS_MMAPLOCK_EXCL);
1346 } else {
1347 xfs_lock_two_inodes(src, dest, XFS_IOLOCK_EXCL);
1348 xfs_lock_two_inodes(src, dest, XFS_MMAPLOCK_EXCL);
1349 }
1350
1351 /* Don't touch certain kinds of inodes */
1352 ret = -EPERM;
1353 if (IS_IMMUTABLE(inode_out))
1354 goto out_unlock;
1355
1356 ret = -ETXTBSY;
1357 if (IS_SWAPFILE(inode_in) || IS_SWAPFILE(inode_out))
1358 goto out_unlock;
1359
1360
1361 /* Don't reflink dirs, pipes, sockets... */
1362 ret = -EISDIR;
1363 if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))
1364 goto out_unlock;
1365 ret = -EINVAL;
1366 if (S_ISFIFO(inode_in->i_mode) || S_ISFIFO(inode_out->i_mode))
1367 goto out_unlock;
1368 if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode))
1369 goto out_unlock;
1370
1335 /* Don't reflink realtime inodes */ 1371 /* Don't reflink realtime inodes */
1336 if (XFS_IS_REALTIME_INODE(src) || XFS_IS_REALTIME_INODE(dest)) 1372 if (XFS_IS_REALTIME_INODE(src) || XFS_IS_REALTIME_INODE(dest))
1337 return -EINVAL; 1373 goto out_unlock;
1374
1375 /* Don't share DAX file data for now. */
1376 if (IS_DAX(inode_in) || IS_DAX(inode_out))
1377 goto out_unlock;
1378
1379 /* Are we going all the way to the end? */
1380 isize = i_size_read(inode_in);
1381 if (isize == 0) {
1382 ret = 0;
1383 goto out_unlock;
1384 }
1385
1386 if (len == 0)
1387 len = isize - pos_in;
1388
1389 /* Ensure offsets don't wrap and the input is inside i_size */
1390 if (pos_in + len < pos_in || pos_out + len < pos_out ||
1391 pos_in + len > isize)
1392 goto out_unlock;
1338 1393
1339 if (flags & ~XFS_REFLINK_ALL) 1394 /* Don't allow dedupe past EOF in the dest file */
1340 return -EINVAL; 1395 if (is_dedupe) {
1396 loff_t disize;
1341 1397
1342 trace_xfs_reflink_remap_range(src, srcoff, len, dest, destoff); 1398 disize = i_size_read(inode_out);
1399 if (pos_out >= disize || pos_out + len > disize)
1400 goto out_unlock;
1401 }
1402
1403 /* If we're linking to EOF, continue to the block boundary. */
1404 if (pos_in + len == isize)
1405 blen = ALIGN(isize, bs) - pos_in;
1406 else
1407 blen = len;
1408
1409 /* Only reflink if we're aligned to block boundaries */
1410 if (!IS_ALIGNED(pos_in, bs) || !IS_ALIGNED(pos_in + blen, bs) ||
1411 !IS_ALIGNED(pos_out, bs) || !IS_ALIGNED(pos_out + blen, bs))
1412 goto out_unlock;
1413
1414 /* Don't allow overlapped reflink within the same file */
1415 if (same_inode) {
1416 if (pos_out + blen > pos_in && pos_out < pos_in + blen)
1417 goto out_unlock;
1418 }
1419
1420 /* Wait for the completion of any pending IOs on both files */
1421 inode_dio_wait(inode_in);
1422 if (!same_inode)
1423 inode_dio_wait(inode_out);
1424
1425 ret = filemap_write_and_wait_range(inode_in->i_mapping,
1426 pos_in, pos_in + len - 1);
1427 if (ret)
1428 goto out_unlock;
1429
1430 ret = filemap_write_and_wait_range(inode_out->i_mapping,
1431 pos_out, pos_out + len - 1);
1432 if (ret)
1433 goto out_unlock;
1434
1435 trace_xfs_reflink_remap_range(src, pos_in, len, dest, pos_out);
1343 1436
1344 /* 1437 /*
1345 * Check that the extents are the same. 1438 * Check that the extents are the same.
1346 */ 1439 */
1347 if (flags & XFS_REFLINK_DEDUPE) { 1440 if (is_dedupe) {
1348 is_same = false; 1441 bool is_same = false;
1349 error = xfs_compare_extents(VFS_I(src), srcoff, VFS_I(dest), 1442
1350 destoff, len, &is_same); 1443 ret = xfs_compare_extents(inode_in, pos_in, inode_out, pos_out,
1351 if (error) 1444 len, &is_same);
1352 goto out_error; 1445 if (ret)
1446 goto out_unlock;
1353 if (!is_same) { 1447 if (!is_same) {
1354 error = -EBADE; 1448 ret = -EBADE;
1355 goto out_error; 1449 goto out_unlock;
1356 } 1450 }
1357 } 1451 }
1358 1452
1359 error = xfs_reflink_set_inode_flag(src, dest); 1453 ret = xfs_reflink_set_inode_flag(src, dest);
1360 if (error) 1454 if (ret)
1361 goto out_error; 1455 goto out_unlock;
1362 1456
1363 /* 1457 /*
1364 * Invalidate the page cache so that we can clear any CoW mappings 1458 * Invalidate the page cache so that we can clear any CoW mappings
1365 * in the destination file. 1459 * in the destination file.
1366 */ 1460 */
1367 truncate_inode_pages_range(&VFS_I(dest)->i_data, destoff, 1461 truncate_inode_pages_range(&inode_out->i_data, pos_out,
1368 PAGE_ALIGN(destoff + len) - 1); 1462 PAGE_ALIGN(pos_out + len) - 1);
1369 1463
1370 dfsbno = XFS_B_TO_FSBT(mp, destoff); 1464 dfsbno = XFS_B_TO_FSBT(mp, pos_out);
1371 sfsbno = XFS_B_TO_FSBT(mp, srcoff); 1465 sfsbno = XFS_B_TO_FSBT(mp, pos_in);
1372 fsblen = XFS_B_TO_FSB(mp, len); 1466 fsblen = XFS_B_TO_FSB(mp, len);
1373 error = xfs_reflink_remap_blocks(src, sfsbno, dest, dfsbno, fsblen, 1467 ret = xfs_reflink_remap_blocks(src, sfsbno, dest, dfsbno, fsblen,
1374 destoff + len); 1468 pos_out + len);
1375 if (error) 1469 if (ret)
1376 goto out_error; 1470 goto out_unlock;
1377 1471
1378 /* 1472 /*
1379 * Carry the cowextsize hint from src to dest if we're sharing the 1473 * Carry the cowextsize hint from src to dest if we're sharing the
@@ -1381,20 +1475,24 @@ xfs_reflink_remap_range(
1381 * has a cowextsize hint, and the destination file does not. 1475 * has a cowextsize hint, and the destination file does not.
1382 */ 1476 */
1383 cowextsize = 0; 1477 cowextsize = 0;
1384 if (srcoff == 0 && len == i_size_read(VFS_I(src)) && 1478 if (pos_in == 0 && len == i_size_read(inode_in) &&
1385 (src->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE) && 1479 (src->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE) &&
1386 destoff == 0 && len >= i_size_read(VFS_I(dest)) && 1480 pos_out == 0 && len >= i_size_read(inode_out) &&
1387 !(dest->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE)) 1481 !(dest->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE))
1388 cowextsize = src->i_d.di_cowextsize; 1482 cowextsize = src->i_d.di_cowextsize;
1389 1483
1390 error = xfs_reflink_update_dest(dest, destoff + len, cowextsize); 1484 ret = xfs_reflink_update_dest(dest, pos_out + len, cowextsize);
1391 if (error)
1392 goto out_error;
1393 1485
1394out_error: 1486out_unlock:
1395 if (error) 1487 xfs_iunlock(src, XFS_MMAPLOCK_EXCL);
1396 trace_xfs_reflink_remap_range_error(dest, error, _RET_IP_); 1488 xfs_iunlock(src, XFS_IOLOCK_EXCL);
1397 return error; 1489 if (src->i_ino != dest->i_ino) {
1490 xfs_iunlock(dest, XFS_MMAPLOCK_EXCL);
1491 xfs_iunlock(dest, XFS_IOLOCK_EXCL);
1492 }
1493 if (ret)
1494 trace_xfs_reflink_remap_range_error(dest, ret, _RET_IP_);
1495 return ret;
1398} 1496}
1399 1497
1400/* 1498/*
diff --git a/fs/xfs/xfs_reflink.h b/fs/xfs/xfs_reflink.h
index 5dc3c8ac12aa..7ddd9f69560d 100644
--- a/fs/xfs/xfs_reflink.h
+++ b/fs/xfs/xfs_reflink.h
@@ -43,11 +43,8 @@ extern int xfs_reflink_cancel_cow_range(struct xfs_inode *ip, xfs_off_t offset,
43extern int xfs_reflink_end_cow(struct xfs_inode *ip, xfs_off_t offset, 43extern int xfs_reflink_end_cow(struct xfs_inode *ip, xfs_off_t offset,
44 xfs_off_t count); 44 xfs_off_t count);
45extern int xfs_reflink_recover_cow(struct xfs_mount *mp); 45extern int xfs_reflink_recover_cow(struct xfs_mount *mp);
46#define XFS_REFLINK_DEDUPE 1 /* only reflink if contents match */ 46extern int xfs_reflink_remap_range(struct file *file_in, loff_t pos_in,
47#define XFS_REFLINK_ALL (XFS_REFLINK_DEDUPE) 47 struct file *file_out, loff_t pos_out, u64 len, bool is_dedupe);
48extern int xfs_reflink_remap_range(struct xfs_inode *src, xfs_off_t srcoff,
49 struct xfs_inode *dest, xfs_off_t destoff, xfs_off_t len,
50 unsigned int flags);
51extern int xfs_reflink_clear_inode_flag(struct xfs_inode *ip, 48extern int xfs_reflink_clear_inode_flag(struct xfs_inode *ip,
52 struct xfs_trans **tpp); 49 struct xfs_trans **tpp);
53extern int xfs_reflink_unshare(struct xfs_inode *ip, xfs_off_t offset, 50extern int xfs_reflink_unshare(struct xfs_inode *ip, xfs_off_t offset,