diff options
Diffstat (limited to 'fs/xfs/xfs_bmap_util.c')
-rw-r--r-- | fs/xfs/xfs_bmap_util.c | 97 |
1 files changed, 96 insertions, 1 deletions
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c index f264616080ca..01f6a646caa1 100644 --- a/fs/xfs/xfs_bmap_util.c +++ b/fs/xfs/xfs_bmap_util.c | |||
@@ -1349,7 +1349,6 @@ xfs_free_file_space( | |||
1349 | * the freeing of the space succeeds at ENOSPC. | 1349 | * the freeing of the space succeeds at ENOSPC. |
1350 | */ | 1350 | */ |
1351 | tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); | 1351 | tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); |
1352 | tp->t_flags |= XFS_TRANS_RESERVE; | ||
1353 | error = xfs_trans_reserve(tp, &M_RES(mp)->tr_write, resblks, 0); | 1352 | error = xfs_trans_reserve(tp, &M_RES(mp)->tr_write, resblks, 0); |
1354 | 1353 | ||
1355 | /* | 1354 | /* |
@@ -1468,6 +1467,102 @@ out: | |||
1468 | } | 1467 | } |
1469 | 1468 | ||
1470 | /* | 1469 | /* |
1470 | * xfs_collapse_file_space() | ||
1471 | * This routine frees disk space and shift extent for the given file. | ||
1472 | * The first thing we do is to free data blocks in the specified range | ||
1473 | * by calling xfs_free_file_space(). It would also sync dirty data | ||
1474 | * and invalidate page cache over the region on which collapse range | ||
1475 | * is working. And Shift extent records to the left to cover a hole. | ||
1476 | * RETURNS: | ||
1477 | * 0 on success | ||
1478 | * errno on error | ||
1479 | * | ||
1480 | */ | ||
1481 | int | ||
1482 | xfs_collapse_file_space( | ||
1483 | struct xfs_inode *ip, | ||
1484 | xfs_off_t offset, | ||
1485 | xfs_off_t len) | ||
1486 | { | ||
1487 | int done = 0; | ||
1488 | struct xfs_mount *mp = ip->i_mount; | ||
1489 | struct xfs_trans *tp; | ||
1490 | int error; | ||
1491 | xfs_extnum_t current_ext = 0; | ||
1492 | struct xfs_bmap_free free_list; | ||
1493 | xfs_fsblock_t first_block; | ||
1494 | int committed; | ||
1495 | xfs_fileoff_t start_fsb; | ||
1496 | xfs_fileoff_t shift_fsb; | ||
1497 | |||
1498 | ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); | ||
1499 | |||
1500 | trace_xfs_collapse_file_space(ip); | ||
1501 | |||
1502 | start_fsb = XFS_B_TO_FSB(mp, offset + len); | ||
1503 | shift_fsb = XFS_B_TO_FSB(mp, len); | ||
1504 | |||
1505 | error = xfs_free_file_space(ip, offset, len); | ||
1506 | if (error) | ||
1507 | return error; | ||
1508 | |||
1509 | while (!error && !done) { | ||
1510 | tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); | ||
1511 | tp->t_flags |= XFS_TRANS_RESERVE; | ||
1512 | /* | ||
1513 | * We would need to reserve permanent block for transaction. | ||
1514 | * This will come into picture when after shifting extent into | ||
1515 | * hole we found that adjacent extents can be merged which | ||
1516 | * may lead to freeing of a block during record update. | ||
1517 | */ | ||
1518 | error = xfs_trans_reserve(tp, &M_RES(mp)->tr_write, | ||
1519 | XFS_DIOSTRAT_SPACE_RES(mp, 0), 0); | ||
1520 | if (error) { | ||
1521 | ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp)); | ||
1522 | xfs_trans_cancel(tp, 0); | ||
1523 | break; | ||
1524 | } | ||
1525 | |||
1526 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
1527 | error = xfs_trans_reserve_quota(tp, mp, ip->i_udquot, | ||
1528 | ip->i_gdquot, ip->i_pdquot, | ||
1529 | XFS_DIOSTRAT_SPACE_RES(mp, 0), 0, | ||
1530 | XFS_QMOPT_RES_REGBLKS); | ||
1531 | if (error) | ||
1532 | goto out; | ||
1533 | |||
1534 | xfs_trans_ijoin(tp, ip, 0); | ||
1535 | |||
1536 | xfs_bmap_init(&free_list, &first_block); | ||
1537 | |||
1538 | /* | ||
1539 | * We are using the write transaction in which max 2 bmbt | ||
1540 | * updates are allowed | ||
1541 | */ | ||
1542 | error = xfs_bmap_shift_extents(tp, ip, &done, start_fsb, | ||
1543 | shift_fsb, ¤t_ext, | ||
1544 | &first_block, &free_list, | ||
1545 | XFS_BMAP_MAX_SHIFT_EXTENTS); | ||
1546 | if (error) | ||
1547 | goto out; | ||
1548 | |||
1549 | error = xfs_bmap_finish(&tp, &free_list, &committed); | ||
1550 | if (error) | ||
1551 | goto out; | ||
1552 | |||
1553 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | ||
1554 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
1555 | } | ||
1556 | |||
1557 | return error; | ||
1558 | |||
1559 | out: | ||
1560 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); | ||
1561 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
1562 | return error; | ||
1563 | } | ||
1564 | |||
1565 | /* | ||
1471 | * We need to check that the format of the data fork in the temporary inode is | 1566 | * We need to check that the format of the data fork in the temporary inode is |
1472 | * valid for the target inode before doing the swap. This is not a problem with | 1567 | * valid for the target inode before doing the swap. This is not a problem with |
1473 | * attr1 because of the fixed fork offset, but attr2 has a dynamically sized | 1568 | * attr1 because of the fixed fork offset, but attr2 has a dynamically sized |