aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/xfs_bmap_util.c85
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 */
695int 693int
696xfs_bmap_punch_delalloc_range( 694xfs_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,
754next_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}