Skip to content

Commit 0525e95

Browse files
committed
xfs: queue deferred rmap ops for cow staging extent alloc/free in the right order
Under the deferred rmap operation scheme, there's a certain order in which the rmap deferred ops have to be queued to maintain integrity during log replay. For alloc/map operations that order is cui -> rui; for free/unmap operations that order is cui -> rui -> efi. However, the initial refcount code got the ordering wrong in the free side of things because it queued refcount free op and an EFI and the refcount free op queued a rmap free op, resulting in the order cui -> efi -> rui. If we fail before the efd finishes, the efi recovery will try to do a wildcard rmap removal and the subsequent rui will fail to find the rmap and blow up. This didn't ever happen due to other screws up in handling unknown owner rmap removals, but those other screw ups broke recovery in other ways, so fix the ordering to follow the intended rules. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
1 parent 86d692b commit 0525e95

File tree

1 file changed

+19
-33
lines changed

1 file changed

+19
-33
lines changed

fs/xfs/libxfs/xfs_refcount.c

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,27 +1488,12 @@ __xfs_refcount_cow_alloc(
14881488
xfs_extlen_t aglen,
14891489
struct xfs_defer_ops *dfops)
14901490
{
1491-
int error;
1492-
14931491
trace_xfs_refcount_cow_increase(rcur->bc_mp, rcur->bc_private.a.agno,
14941492
agbno, aglen);
14951493

14961494
/* Add refcount btree reservation */
1497-
error = xfs_refcount_adjust_cow(rcur, agbno, aglen,
1495+
return xfs_refcount_adjust_cow(rcur, agbno, aglen,
14981496
XFS_REFCOUNT_ADJUST_COW_ALLOC, dfops);
1499-
if (error)
1500-
return error;
1501-
1502-
/* Add rmap entry */
1503-
if (xfs_sb_version_hasrmapbt(&rcur->bc_mp->m_sb)) {
1504-
error = xfs_rmap_alloc_extent(rcur->bc_mp, dfops,
1505-
rcur->bc_private.a.agno,
1506-
agbno, aglen, XFS_RMAP_OWN_COW);
1507-
if (error)
1508-
return error;
1509-
}
1510-
1511-
return error;
15121497
}
15131498

15141499
/*
@@ -1521,27 +1506,12 @@ __xfs_refcount_cow_free(
15211506
xfs_extlen_t aglen,
15221507
struct xfs_defer_ops *dfops)
15231508
{
1524-
int error;
1525-
15261509
trace_xfs_refcount_cow_decrease(rcur->bc_mp, rcur->bc_private.a.agno,
15271510
agbno, aglen);
15281511

15291512
/* Remove refcount btree reservation */
1530-
error = xfs_refcount_adjust_cow(rcur, agbno, aglen,
1513+
return xfs_refcount_adjust_cow(rcur, agbno, aglen,
15311514
XFS_REFCOUNT_ADJUST_COW_FREE, dfops);
1532-
if (error)
1533-
return error;
1534-
1535-
/* Remove rmap entry */
1536-
if (xfs_sb_version_hasrmapbt(&rcur->bc_mp->m_sb)) {
1537-
error = xfs_rmap_free_extent(rcur->bc_mp, dfops,
1538-
rcur->bc_private.a.agno,
1539-
agbno, aglen, XFS_RMAP_OWN_COW);
1540-
if (error)
1541-
return error;
1542-
}
1543-
1544-
return error;
15451515
}
15461516

15471517
/* Record a CoW staging extent in the refcount btree. */
@@ -1552,11 +1522,19 @@ xfs_refcount_alloc_cow_extent(
15521522
xfs_fsblock_t fsb,
15531523
xfs_extlen_t len)
15541524
{
1525+
int error;
1526+
15551527
if (!xfs_sb_version_hasreflink(&mp->m_sb))
15561528
return 0;
15571529

1558-
return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_ALLOC_COW,
1530+
error = __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_ALLOC_COW,
15591531
fsb, len);
1532+
if (error)
1533+
return error;
1534+
1535+
/* Add rmap entry */
1536+
return xfs_rmap_alloc_extent(mp, dfops, XFS_FSB_TO_AGNO(mp, fsb),
1537+
XFS_FSB_TO_AGBNO(mp, fsb), len, XFS_RMAP_OWN_COW);
15601538
}
15611539

15621540
/* Forget a CoW staging event in the refcount btree. */
@@ -1567,9 +1545,17 @@ xfs_refcount_free_cow_extent(
15671545
xfs_fsblock_t fsb,
15681546
xfs_extlen_t len)
15691547
{
1548+
int error;
1549+
15701550
if (!xfs_sb_version_hasreflink(&mp->m_sb))
15711551
return 0;
15721552

1553+
/* Remove rmap entry */
1554+
error = xfs_rmap_free_extent(mp, dfops, XFS_FSB_TO_AGNO(mp, fsb),
1555+
XFS_FSB_TO_AGBNO(mp, fsb), len, XFS_RMAP_OWN_COW);
1556+
if (error)
1557+
return error;
1558+
15731559
return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_FREE_COW,
15741560
fsb, len);
15751561
}

0 commit comments

Comments
 (0)