diff options
| -rw-r--r-- | fs/xfs/xfs_bmap_util.c | 85 |
1 files changed, 32 insertions, 53 deletions
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c index c35009a86699..c195b9d857af 100644 --- a/fs/xfs/xfs_bmap_util.c +++ b/fs/xfs/xfs_bmap_util.c | |||
| @@ -685,12 +685,10 @@ out_unlock_iolock: | |||
| 685 | } | 685 | } |
| 686 | 686 | ||
| 687 | /* | 687 | /* |
| 688 | * dead simple method of punching delalyed allocation blocks from a range in | 688 | * Dead simple method of punching delalyed allocation blocks from a range in |
| 689 | * the inode. Walks a block at a time so will be slow, but is only executed in | 689 | * the inode. This will always punch out both the start and end blocks, even |
| 690 | * rare error cases so the overhead is not critical. This will always punch out | 690 | * if the ranges only partially overlap them, so it is up to the caller to |
| 691 | * both the start and end blocks, even if the ranges only partially overlap | 691 | * ensure that partial blocks are not passed in. |
| 692 | * them, so it is up to the caller to ensure that partial blocks are not | ||
| 693 | * passed in. | ||
| 694 | */ | 692 | */ |
| 695 | int | 693 | int |
| 696 | xfs_bmap_punch_delalloc_range( | 694 | xfs_bmap_punch_delalloc_range( |
| @@ -698,63 +696,44 @@ xfs_bmap_punch_delalloc_range( | |||
| 698 | xfs_fileoff_t start_fsb, | 696 | xfs_fileoff_t start_fsb, |
| 699 | xfs_fileoff_t length) | 697 | xfs_fileoff_t length) |
| 700 | { | 698 | { |
| 701 | xfs_fileoff_t remaining = length; | 699 | struct xfs_ifork *ifp = &ip->i_df; |
| 700 | xfs_fileoff_t end_fsb = start_fsb + length; | ||
| 701 | struct xfs_bmbt_irec got, del; | ||
| 702 | struct xfs_iext_cursor icur; | ||
| 702 | int error = 0; | 703 | int error = 0; |
| 703 | 704 | ||
| 704 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); | 705 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); |
| 705 | 706 | ||
| 706 | do { | 707 | if (!(ifp->if_flags & XFS_IFEXTENTS)) { |
| 707 | int done; | 708 | error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK); |
| 708 | xfs_bmbt_irec_t imap; | 709 | if (error) |
| 709 | int nimaps = 1; | 710 | return error; |
| 710 | xfs_fsblock_t firstblock; | 711 | } |
| 711 | struct xfs_defer_ops dfops; | ||
| 712 | 712 | ||
| 713 | /* | 713 | if (!xfs_iext_lookup_extent_before(ip, ifp, &end_fsb, &icur, &got)) |
| 714 | * Map the range first and check that it is a delalloc extent | 714 | return 0; |
| 715 | * before trying to unmap the range. Otherwise we will be | ||
| 716 | * trying to remove a real extent (which requires a | ||
| 717 | * transaction) or a hole, which is probably a bad idea... | ||
| 718 | */ | ||
| 719 | error = xfs_bmapi_read(ip, start_fsb, 1, &imap, &nimaps, | ||
| 720 | XFS_BMAPI_ENTIRE); | ||
| 721 | 715 | ||
| 722 | if (error) { | 716 | while (got.br_startoff + got.br_blockcount > start_fsb) { |
| 723 | /* something screwed, just bail */ | 717 | del = got; |
| 724 | if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) { | 718 | xfs_trim_extent(&del, start_fsb, length); |
| 725 | xfs_alert(ip->i_mount, | ||
| 726 | "Failed delalloc mapping lookup ino %lld fsb %lld.", | ||
| 727 | ip->i_ino, start_fsb); | ||
| 728 | } | ||
| 729 | break; | ||
| 730 | } | ||
| 731 | if (!nimaps) { | ||
| 732 | /* nothing there */ | ||
| 733 | goto next_block; | ||
| 734 | } | ||
| 735 | if (imap.br_startblock != DELAYSTARTBLOCK) { | ||
| 736 | /* been converted, ignore */ | ||
| 737 | goto next_block; | ||
| 738 | } | ||
| 739 | WARN_ON(imap.br_blockcount == 0); | ||
| 740 | 719 | ||
| 741 | /* | 720 | /* |
| 742 | * Note: while we initialise the firstblock/dfops pair, they | 721 | * A delete can push the cursor forward. Step back to the |
| 743 | * should never be used because blocks should never be | 722 | * previous extent on non-delalloc or extents outside the |
| 744 | * allocated or freed for a delalloc extent and hence we need | 723 | * target range. |
| 745 | * don't cancel or finish them after the xfs_bunmapi() call. | ||
| 746 | */ | 724 | */ |
| 747 | xfs_defer_init(&dfops, &firstblock); | 725 | if (!del.br_blockcount || |
| 748 | error = xfs_bunmapi(NULL, ip, start_fsb, 1, 0, 1, &firstblock, | 726 | !isnullstartblock(del.br_startblock)) { |
| 749 | &dfops, &done); | 727 | if (!xfs_iext_prev_extent(ifp, &icur, &got)) |
| 750 | if (error) | 728 | break; |
| 751 | break; | 729 | continue; |
| 730 | } | ||
| 752 | 731 | ||
| 753 | ASSERT(!xfs_defer_has_unfinished_work(&dfops)); | 732 | error = xfs_bmap_del_extent_delay(ip, XFS_DATA_FORK, &icur, |
| 754 | next_block: | 733 | &got, &del); |
| 755 | start_fsb++; | 734 | if (error || !xfs_iext_get_extent(ifp, &icur, &got)) |
| 756 | remaining--; | 735 | break; |
| 757 | } while(remaining > 0); | 736 | } |
| 758 | 737 | ||
| 759 | return error; | 738 | return error; |
| 760 | } | 739 | } |
