Skip to content

Commit 0e339ef

Browse files
Brian Fosterdjwong
authored andcommitted
xfs: handle indlen shortage on delalloc extent merge
When a delalloc extent is created, it can be merged with pre-existing, contiguous, delalloc extents. When this occurs, xfs_bmap_add_extent_hole_delay() merges the extents along with the associated indirect block reservations. The expectation here is that the combined worst case indlen reservation is always less than or equal to the indlen reservation for the individual extents. This is not always the case, however, as existing extents can less than the expected indlen reservation if the extent was previously split due to a hole punch. If a new extent merges with such an extent, the total indlen requirement may be larger than the sum of the indlen reservations held by both extents. xfs_bmap_add_extent_hole_delay() assumes that the worst case indlen reservation is always available and assigns it to the merged extent without consideration for the indlen held by the pre-existing extent. As a result, the subsequent xfs_mod_fdblocks() call can attempt an unintentional allocation rather than a free (indicated by an ASSERT() failure). Further, if the allocation happens to fail in this context, the failure goes unhandled and creates a filesystem wide block accounting inconsistency. Fix xfs_bmap_add_extent_hole_delay() to function as designed. Cap the indlen reservation assigned to the merged extent to the sum of the indlen reservations held by each of the individual extents. Signed-off-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
1 parent 9dbddd7 commit 0e339ef

File tree

1 file changed

+6
-3
lines changed

1 file changed

+6
-3
lines changed

fs/xfs/libxfs/xfs_bmap.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2805,7 +2805,8 @@ xfs_bmap_add_extent_hole_delay(
28052805
oldlen = startblockval(left.br_startblock) +
28062806
startblockval(new->br_startblock) +
28072807
startblockval(right.br_startblock);
2808-
newlen = xfs_bmap_worst_indlen(ip, temp);
2808+
newlen = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
2809+
oldlen);
28092810
xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, *idx),
28102811
nullstartblock((int)newlen));
28112812
trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
@@ -2826,7 +2827,8 @@ xfs_bmap_add_extent_hole_delay(
28262827
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx), temp);
28272828
oldlen = startblockval(left.br_startblock) +
28282829
startblockval(new->br_startblock);
2829-
newlen = xfs_bmap_worst_indlen(ip, temp);
2830+
newlen = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
2831+
oldlen);
28302832
xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, *idx),
28312833
nullstartblock((int)newlen));
28322834
trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
@@ -2842,7 +2844,8 @@ xfs_bmap_add_extent_hole_delay(
28422844
temp = new->br_blockcount + right.br_blockcount;
28432845
oldlen = startblockval(new->br_startblock) +
28442846
startblockval(right.br_startblock);
2845-
newlen = xfs_bmap_worst_indlen(ip, temp);
2847+
newlen = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
2848+
oldlen);
28462849
xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, *idx),
28472850
new->br_startoff,
28482851
nullstartblock((int)newlen), temp, right.br_state);

0 commit comments

Comments
 (0)