diff options
Diffstat (limited to 'fs/xfs/xfs_bmap.c')
-rw-r--r-- | fs/xfs/xfs_bmap.c | 85 |
1 files changed, 83 insertions, 2 deletions
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 8abd12e32e13..4111cd3966c7 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
@@ -5471,8 +5471,13 @@ xfs_getbmap( | |||
5471 | if (error) | 5471 | if (error) |
5472 | goto out_unlock_iolock; | 5472 | goto out_unlock_iolock; |
5473 | } | 5473 | } |
5474 | 5474 | /* | |
5475 | ASSERT(ip->i_delayed_blks == 0); | 5475 | * even after flushing the inode, there can still be delalloc |
5476 | * blocks on the inode beyond EOF due to speculative | ||
5477 | * preallocation. These are not removed until the release | ||
5478 | * function is called or the inode is inactivated. Hence we | ||
5479 | * cannot assert here that ip->i_delayed_blks == 0. | ||
5480 | */ | ||
5476 | } | 5481 | } |
5477 | 5482 | ||
5478 | lock = xfs_ilock_map_shared(ip); | 5483 | lock = xfs_ilock_map_shared(ip); |
@@ -6070,3 +6075,79 @@ xfs_bmap_disk_count_leaves( | |||
6070 | *count += xfs_bmbt_disk_get_blockcount(frp); | 6075 | *count += xfs_bmbt_disk_get_blockcount(frp); |
6071 | } | 6076 | } |
6072 | } | 6077 | } |
6078 | |||
6079 | /* | ||
6080 | * dead simple method of punching delalyed allocation blocks from a range in | ||
6081 | * the inode. Walks a block at a time so will be slow, but is only executed in | ||
6082 | * rare error cases so the overhead is not critical. This will alays punch out | ||
6083 | * both the start and end blocks, even if the ranges only partially overlap | ||
6084 | * them, so it is up to the caller to ensure that partial blocks are not | ||
6085 | * passed in. | ||
6086 | */ | ||
6087 | int | ||
6088 | xfs_bmap_punch_delalloc_range( | ||
6089 | struct xfs_inode *ip, | ||
6090 | xfs_fileoff_t start_fsb, | ||
6091 | xfs_fileoff_t length) | ||
6092 | { | ||
6093 | xfs_fileoff_t remaining = length; | ||
6094 | int error = 0; | ||
6095 | |||
6096 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); | ||
6097 | |||
6098 | do { | ||
6099 | int done; | ||
6100 | xfs_bmbt_irec_t imap; | ||
6101 | int nimaps = 1; | ||
6102 | xfs_fsblock_t firstblock; | ||
6103 | xfs_bmap_free_t flist; | ||
6104 | |||
6105 | /* | ||
6106 | * Map the range first and check that it is a delalloc extent | ||
6107 | * before trying to unmap the range. Otherwise we will be | ||
6108 | * trying to remove a real extent (which requires a | ||
6109 | * transaction) or a hole, which is probably a bad idea... | ||
6110 | */ | ||
6111 | error = xfs_bmapi(NULL, ip, start_fsb, 1, | ||
6112 | XFS_BMAPI_ENTIRE, NULL, 0, &imap, | ||
6113 | &nimaps, NULL); | ||
6114 | |||
6115 | if (error) { | ||
6116 | /* something screwed, just bail */ | ||
6117 | if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) { | ||
6118 | xfs_fs_cmn_err(CE_ALERT, ip->i_mount, | ||
6119 | "Failed delalloc mapping lookup ino %lld fsb %lld.", | ||
6120 | ip->i_ino, start_fsb); | ||
6121 | } | ||
6122 | break; | ||
6123 | } | ||
6124 | if (!nimaps) { | ||
6125 | /* nothing there */ | ||
6126 | goto next_block; | ||
6127 | } | ||
6128 | if (imap.br_startblock != DELAYSTARTBLOCK) { | ||
6129 | /* been converted, ignore */ | ||
6130 | goto next_block; | ||
6131 | } | ||
6132 | WARN_ON(imap.br_blockcount == 0); | ||
6133 | |||
6134 | /* | ||
6135 | * Note: while we initialise the firstblock/flist pair, they | ||
6136 | * should never be used because blocks should never be | ||
6137 | * allocated or freed for a delalloc extent and hence we need | ||
6138 | * don't cancel or finish them after the xfs_bunmapi() call. | ||
6139 | */ | ||
6140 | xfs_bmap_init(&flist, &firstblock); | ||
6141 | error = xfs_bunmapi(NULL, ip, start_fsb, 1, 0, 1, &firstblock, | ||
6142 | &flist, &done); | ||
6143 | if (error) | ||
6144 | break; | ||
6145 | |||
6146 | ASSERT(!flist.xbf_count && !flist.xbf_first); | ||
6147 | next_block: | ||
6148 | start_fsb++; | ||
6149 | remaining--; | ||
6150 | } while(remaining > 0); | ||
6151 | |||
6152 | return error; | ||
6153 | } | ||