diff options
author | Darrick J. Wong <darrick.wong@oracle.com> | 2020-02-19 17:01:41 -0800 |
---|---|---|
committer | Darrick J. Wong <darrick.wong@oracle.com> | 2020-03-03 18:47:36 -0800 |
commit | bfe307c643833b2ed00aff63ae2cc4f327cf5057 (patch) | |
tree | 69487a0ea9fe359e7645aea7948510e24c053833 /fs/xfs/scrub/repair.c | |
parent | 3d3e299b2abd59895db2903ce329d4268023f9e0 (diff) |
xfs: log EFIs for all btree blocks being used to stage a btreerepair-prep-for-bulk-loading_2020-03-03
We need to log EFIs for every extent that we allocate for the purpose of
staging a new btree so that if we fail then the blocks will be freed
during log recovery.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Diffstat (limited to 'fs/xfs/scrub/repair.c')
-rw-r--r-- | fs/xfs/scrub/repair.c | 63 |
1 files changed, 61 insertions, 2 deletions
diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c index 135fcca515e1..806ab61f51ee 100644 --- a/fs/xfs/scrub/repair.c +++ b/fs/xfs/scrub/repair.c @@ -25,6 +25,8 @@ #include "xfs_ag_resv.h" #include "xfs_quota.h" #include "xfs_bmap.h" +#include "xfs_defer.h" +#include "xfs_extfree_item.h" #include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/trace.h" @@ -413,7 +415,8 @@ int xrep_newbt_add_blocks( struct xrep_newbt *xnr, xfs_fsblock_t fsbno, - xfs_extlen_t len) + xfs_extlen_t len, + void *priv) { struct xrep_newbt_resv *resv; @@ -425,10 +428,55 @@ xrep_newbt_add_blocks( resv->fsbno = fsbno; resv->len = len; resv->used = 0; + resv->priv = priv; list_add_tail(&resv->list, &xnr->resv_list); return 0; } +/* + * Set up automatic reaping of the blocks reserved for btree reconstruction in + * case we crash by logging a deferred free item for each extent we allocate so + * that we can get all of the space back if we crash before we can commit the + * new btree. This function returns a token that can be used to cancel + * automatic reaping if repair is successful. + */ +static void * +xrep_newbt_schedule_reap( + struct xfs_trans *tp, + struct xfs_owner_info *oinfo, + xfs_fsblock_t fsbno, + xfs_extlen_t len) +{ + struct xfs_extent_free_item efi_item = { + .xefi_startblock = fsbno, + .xefi_blockcount = len, + .xefi_oinfo = *oinfo, /* struct copy */ + .xefi_skip_discard = true, + }; + struct xfs_efi_log_item *efi; + + INIT_LIST_HEAD(&efi_item.xefi_list); + efi = xfs_extent_free_defer_type.create_intent(tp, 1); + xfs_extent_free_defer_type.log_item(tp, efi, &efi_item.xefi_list); + return efi; +} + +/* + * Cancel a previously scheduled automatic reap (see above) by logging a + * deferred free done for each extent we allocated. We cheat since we know + * that log recovery has never looked at the extents attached to an EFD. + */ +static void +xrep_newbt_cancel_reap( + struct xfs_trans *tp, + void *token) +{ + struct xfs_efd_log_item *efd; + + efd = xfs_extent_free_defer_type.create_done(tp, token, 0); + set_bit(XFS_LI_DIRTY, &efd->efd_item.li_flags); +} + /* Allocate disk space for our new btree. */ int xrep_newbt_alloc_blocks( @@ -458,6 +506,7 @@ xrep_newbt_alloc_blocks( .prod = 1, .resv = xnr->resv, }; + void *token; error = xfs_alloc_vextent(&args); if (error) @@ -470,7 +519,9 @@ xrep_newbt_alloc_blocks( XFS_FSB_TO_AGBNO(sc->mp, args.fsbno), args.len, xnr->oinfo.oi_owner); - error = xrep_newbt_add_blocks(xnr, args.fsbno, args.len); + token = xrep_newbt_schedule_reap(sc->tp, &xnr->oinfo, + args.fsbno, args.len); + error = xrep_newbt_add_blocks(xnr, args.fsbno, args.len, token); if (error) break; @@ -515,6 +566,13 @@ xrep_newbt_destroy_reservation( } /* + * Since we succeeded in rebuilding the btree, we need to log an EFD + * for every extent we reserved to prevent log recovery from freeing + * them mistakenly. + */ + xrep_newbt_cancel_reap(sc->tp, resv->priv); + + /* * Use the deferred freeing mechanism to schedule for deletion any * blocks we didn't use to rebuild the tree. This enables us to log * them all in the same transaction as the root change. @@ -568,6 +626,7 @@ junkit: * reservations. */ list_for_each_entry_safe(resv, n, &xnr->resv_list, list) { + xfs_extent_free_defer_type.abort_intent(resv->priv); list_del(&resv->list); kmem_free(resv); } |