Skip to content

Commit 33df3a9

Browse files
committed
xfs: always honor OWN_UNKNOWN rmap removal requests
Calling xfs_rmap_free with an unknown owner is supposed to remove any rmaps covering that range regardless of owner. This is used by the EFI recovery code to say "we're freeing this, it mustn't be owned by anything anymore", but for whatever reason xfs_free_ag_extent filters them out. Therefore, remove the filter and make xfs_rmap_unmap actually treat it as a wildcard owner -- free anything that's already there, and if there's no owner at all then that's fine too. There are two existing callers of bmap_add_free that take care the rmap deferred ops themselves and use OWN_UNKNOWN to skip the EFI-based rmap cleanup; convert these to use OWN_NULL (via helpers), and now we really require that an RUI (if any) gets added to the defer ops before any EFI. Lastly, now that xfs_free_extent filters out OWN_NULL rmap free requests, growfs will have to consult directly with the rmap to ensure that there aren't any rmaps in the grown region. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
1 parent 0525e95 commit 33df3a9

File tree

5 files changed

+48
-4
lines changed

5 files changed

+48
-4
lines changed

fs/xfs/libxfs/xfs_alloc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,7 @@ xfs_alloc_ag_vextent(
702702
ASSERT(args->agbno % args->alignment == 0);
703703

704704
/* if not file data, insert new block into the reverse map btree */
705-
if (args->oinfo.oi_owner != XFS_RMAP_OWN_UNKNOWN) {
705+
if (!xfs_rmap_should_skip_owner_update(&args->oinfo)) {
706706
error = xfs_rmap_alloc(args->tp, args->agbp, args->agno,
707707
args->agbno, args->len, &args->oinfo);
708708
if (error)
@@ -1682,7 +1682,7 @@ xfs_free_ag_extent(
16821682
bno_cur = cnt_cur = NULL;
16831683
mp = tp->t_mountp;
16841684

1685-
if (oinfo->oi_owner != XFS_RMAP_OWN_UNKNOWN) {
1685+
if (!xfs_rmap_should_skip_owner_update(oinfo)) {
16861686
error = xfs_rmap_free(tp, agbp, agno, bno, len, oinfo);
16871687
if (error)
16881688
goto error0;

fs/xfs/libxfs/xfs_rmap.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,30 @@ xfs_rmap_unmap(
444444
goto out_done;
445445
}
446446

447+
/*
448+
* If we're doing an unknown-owner removal for EFI recovery, we expect
449+
* to find the full range in the rmapbt or nothing at all. If we
450+
* don't find any rmaps overlapping either end of the range, we're
451+
* done. Hopefully this means that the EFI creator already queued
452+
* (and finished) a RUI to remove the rmap.
453+
*/
454+
if (owner == XFS_RMAP_OWN_UNKNOWN &&
455+
ltrec.rm_startblock + ltrec.rm_blockcount <= bno) {
456+
struct xfs_rmap_irec rtrec;
457+
458+
error = xfs_btree_increment(cur, 0, &i);
459+
if (error)
460+
goto out_error;
461+
if (i == 0)
462+
goto out_done;
463+
error = xfs_rmap_get_rec(cur, &rtrec, &i);
464+
if (error)
465+
goto out_error;
466+
XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
467+
if (rtrec.rm_startblock >= bno + len)
468+
goto out_done;
469+
}
470+
447471
/* Make sure the unwritten flag matches. */
448472
XFS_WANT_CORRUPTED_GOTO(mp, (flags & XFS_RMAP_UNWRITTEN) ==
449473
(ltrec.rm_flags & XFS_RMAP_UNWRITTEN), out_error);
@@ -664,6 +688,7 @@ xfs_rmap_map(
664688
flags |= XFS_RMAP_UNWRITTEN;
665689
trace_xfs_rmap_map(mp, cur->bc_private.a.agno, bno, len,
666690
unwritten, oinfo);
691+
ASSERT(!xfs_rmap_should_skip_owner_update(oinfo));
667692

668693
/*
669694
* For the initial lookup, look for an exact match or the left-adjacent

fs/xfs/libxfs/xfs_rmap.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,21 @@ static inline void
6161
xfs_rmap_skip_owner_update(
6262
struct xfs_owner_info *oi)
6363
{
64-
oi->oi_owner = XFS_RMAP_OWN_UNKNOWN;
64+
xfs_rmap_ag_owner(oi, XFS_RMAP_OWN_NULL);
65+
}
66+
67+
static inline bool
68+
xfs_rmap_should_skip_owner_update(
69+
struct xfs_owner_info *oi)
70+
{
71+
return oi->oi_owner == XFS_RMAP_OWN_NULL;
72+
}
73+
74+
static inline void
75+
xfs_rmap_any_owner_update(
76+
struct xfs_owner_info *oi)
77+
{
78+
xfs_rmap_ag_owner(oi, XFS_RMAP_OWN_UNKNOWN);
6579
}
6680

6781
/* Reverse mapping functions. */

fs/xfs/xfs_extfree_item.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ xfs_efi_recover(
538538
return error;
539539
efdp = xfs_trans_get_efd(tp, efip, efip->efi_format.efi_nextents);
540540

541-
xfs_rmap_skip_owner_update(&oinfo);
541+
xfs_rmap_any_owner_update(&oinfo);
542542
for (i = 0; i < efip->efi_format.efi_nextents; i++) {
543543
extp = &efip->efi_format.efi_extents[i];
544544
error = xfs_trans_free_extent(tp, efdp, extp->ext_start,

fs/xfs/xfs_fsops.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,11 @@ xfs_growfs_data_private(
571571
* this doesn't actually exist in the rmap btree.
572572
*/
573573
xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_NULL);
574+
error = xfs_rmap_free(tp, bp, agno,
575+
be32_to_cpu(agf->agf_length) - new,
576+
new, &oinfo);
577+
if (error)
578+
goto error0;
574579
error = xfs_free_extent(tp,
575580
XFS_AGB_TO_FSB(mp, agno,
576581
be32_to_cpu(agf->agf_length) - new),

0 commit comments

Comments
 (0)