Skip to content

Commit d69bee6

Browse files
Christoph HellwigChandan Babu R
authored andcommitted
xfs: fix xfs_bmap_add_extent_delay_real for partial conversions
xfs_bmap_add_extent_delay_real takes parts or all of a delalloc extent and converts them to a real extent. It is written to deal with any potential overlap of the to be converted range with the delalloc extent, but it turns out that currently only converting the entire extents, or a part starting at the beginning is actually exercised, as the only caller always tries to convert the entire delalloc extent, and either succeeds or at least progresses partially from the start. If it only converts a tiny part of a delalloc extent, the indirect block calculation for the new delalloc extent (da_new) might be equivalent to that of the existing delalloc extent (da_old). If this extent conversion now requires allocating an indirect block that gets accounted into da_new, leading to the assert that da_new must be smaller or equal to da_new unless we split the extent to trigger. Except for the assert that case is actually handled by just trying to allocate more space, as that already handled for the split case (which currently can't be reached at all), so just reusing it should be fine. Except that without dipping into the reserved block pool that would make it a bit too easy to trigger a fs shutdown due to ENOSPC. So in addition to adjusting the assert, also dip into the reserved block pool. Note that I could only reproduce the assert with a change to only convert the actually asked range instead of the full delalloc extent from xfs_bmapi_write. Signed-off-by: Christoph Hellwig <[email protected]> Reviewed-by: "Darrick J. Wong" <[email protected]> Signed-off-by: Chandan Babu R <[email protected]>
1 parent a8bb258 commit d69bee6

File tree

1 file changed

+10
-5
lines changed

1 file changed

+10
-5
lines changed

fs/xfs/libxfs/xfs_bmap.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1570,6 +1570,7 @@ xfs_bmap_add_extent_delay_real(
15701570
if (error)
15711571
goto done;
15721572
}
1573+
ASSERT(da_new <= da_old);
15731574
break;
15741575

15751576
case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG:
@@ -1600,6 +1601,7 @@ xfs_bmap_add_extent_delay_real(
16001601
if (error)
16011602
goto done;
16021603
}
1604+
ASSERT(da_new <= da_old);
16031605
break;
16041606

16051607
case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
@@ -1634,6 +1636,7 @@ xfs_bmap_add_extent_delay_real(
16341636
if (error)
16351637
goto done;
16361638
}
1639+
ASSERT(da_new <= da_old);
16371640
break;
16381641

16391642
case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING:
@@ -1668,6 +1671,7 @@ xfs_bmap_add_extent_delay_real(
16681671
goto done;
16691672
}
16701673
}
1674+
ASSERT(da_new <= da_old);
16711675
break;
16721676

16731677
case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG:
@@ -1706,6 +1710,7 @@ xfs_bmap_add_extent_delay_real(
17061710
if (error)
17071711
goto done;
17081712
}
1713+
ASSERT(da_new <= da_old);
17091714
break;
17101715

17111716
case BMAP_LEFT_FILLING:
@@ -1796,6 +1801,7 @@ xfs_bmap_add_extent_delay_real(
17961801
xfs_iext_update_extent(bma->ip, state, &bma->icur, &PREV);
17971802
xfs_iext_next(ifp, &bma->icur);
17981803
xfs_iext_update_extent(bma->ip, state, &bma->icur, &RIGHT);
1804+
ASSERT(da_new <= da_old);
17991805
break;
18001806

18011807
case BMAP_RIGHT_FILLING:
@@ -1845,6 +1851,7 @@ xfs_bmap_add_extent_delay_real(
18451851
PREV.br_blockcount = temp;
18461852
xfs_iext_insert(bma->ip, &bma->icur, &PREV, state);
18471853
xfs_iext_next(ifp, &bma->icur);
1854+
ASSERT(da_new <= da_old);
18481855
break;
18491856

18501857
case 0:
@@ -1967,12 +1974,10 @@ xfs_bmap_add_extent_delay_real(
19671974
}
19681975

19691976
/* adjust for changes in reserved delayed indirect blocks */
1970-
if (da_new < da_old) {
1977+
if (da_new < da_old)
19711978
xfs_add_fdblocks(mp, da_old - da_new);
1972-
} else if (da_new > da_old) {
1973-
ASSERT(state == 0);
1974-
error = xfs_dec_fdblocks(mp, da_new - da_old, false);
1975-
}
1979+
else if (da_new > da_old)
1980+
error = xfs_dec_fdblocks(mp, da_new - da_old, true);
19761981

19771982
xfs_bmap_check_leaf_extents(bma->cur, bma->ip, whichfork);
19781983
done:

0 commit comments

Comments
 (0)