xfs: port refcount repair to the new refcount bag structure
Port the refcount record generating code to use the new refcount bag data structure. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
parent
7a2192ac10
commit
7fbaab57a8
@ -7,8 +7,10 @@
|
||||
#include "xfs_fs.h"
|
||||
#include "xfs_shared.h"
|
||||
#include "xfs_format.h"
|
||||
#include "xfs_log_format.h"
|
||||
#include "xfs_trans_resv.h"
|
||||
#include "xfs_mount.h"
|
||||
#include "xfs_trans.h"
|
||||
#include "xfs_ag.h"
|
||||
#include "xfs_btree.h"
|
||||
#include "xfs_rmap.h"
|
||||
@ -17,6 +19,7 @@
|
||||
#include "scrub/common.h"
|
||||
#include "scrub/btree.h"
|
||||
#include "scrub/trace.h"
|
||||
#include "scrub/repair.h"
|
||||
|
||||
/*
|
||||
* Set us up to scrub reference count btrees.
|
||||
@ -27,6 +30,15 @@ xchk_setup_ag_refcountbt(
|
||||
{
|
||||
if (xchk_need_intent_drain(sc))
|
||||
xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
|
||||
|
||||
if (xchk_could_repair(sc)) {
|
||||
int error;
|
||||
|
||||
error = xrep_setup_ag_refcountbt(sc);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
return xchk_setup_ag_btree(sc, false);
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "scrub/xfarray.h"
|
||||
#include "scrub/newbt.h"
|
||||
#include "scrub/reap.h"
|
||||
#include "scrub/rcbag.h"
|
||||
|
||||
/*
|
||||
* Rebuilding the Reference Count Btree
|
||||
@ -98,12 +99,6 @@
|
||||
* insert all the records.
|
||||
*/
|
||||
|
||||
/* The only parts of the rmap that we care about for computing refcounts. */
|
||||
struct xrep_refc_rmap {
|
||||
xfs_agblock_t startblock;
|
||||
xfs_extlen_t blockcount;
|
||||
} __packed;
|
||||
|
||||
struct xrep_refc {
|
||||
/* refcount extents */
|
||||
struct xfarray *refcount_records;
|
||||
@ -123,6 +118,20 @@ struct xrep_refc {
|
||||
xfs_extlen_t btblocks;
|
||||
};
|
||||
|
||||
/* Set us up to repair refcount btrees. */
|
||||
int
|
||||
xrep_setup_ag_refcountbt(
|
||||
struct xfs_scrub *sc)
|
||||
{
|
||||
char *descr;
|
||||
int error;
|
||||
|
||||
descr = xchk_xfile_ag_descr(sc, "rmap record bag");
|
||||
error = xrep_setup_xfbtree(sc, descr);
|
||||
kfree(descr);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Check for any obvious conflicts with this shared/CoW staging extent. */
|
||||
STATIC int
|
||||
xrep_refc_check_ext(
|
||||
@ -224,10 +233,9 @@ xrep_refc_rmap_shareable(
|
||||
STATIC int
|
||||
xrep_refc_walk_rmaps(
|
||||
struct xrep_refc *rr,
|
||||
struct xrep_refc_rmap *rrm,
|
||||
struct xfs_rmap_irec *rmap,
|
||||
bool *have_rec)
|
||||
{
|
||||
struct xfs_rmap_irec rmap;
|
||||
struct xfs_btree_cur *cur = rr->sc->sa.rmap_cur;
|
||||
struct xfs_mount *mp = cur->bc_mp;
|
||||
int have_gt;
|
||||
@ -251,7 +259,7 @@ xrep_refc_walk_rmaps(
|
||||
if (!have_gt)
|
||||
return 0;
|
||||
|
||||
error = xfs_rmap_get_rec(cur, &rmap, &have_gt);
|
||||
error = xfs_rmap_get_rec(cur, rmap, &have_gt);
|
||||
if (error)
|
||||
return error;
|
||||
if (XFS_IS_CORRUPT(mp, !have_gt)) {
|
||||
@ -259,23 +267,22 @@ xrep_refc_walk_rmaps(
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
if (rmap.rm_owner == XFS_RMAP_OWN_COW) {
|
||||
error = xrep_refc_stash_cow(rr, rmap.rm_startblock,
|
||||
rmap.rm_blockcount);
|
||||
if (rmap->rm_owner == XFS_RMAP_OWN_COW) {
|
||||
error = xrep_refc_stash_cow(rr, rmap->rm_startblock,
|
||||
rmap->rm_blockcount);
|
||||
if (error)
|
||||
return error;
|
||||
} else if (rmap.rm_owner == XFS_RMAP_OWN_REFC) {
|
||||
} else if (rmap->rm_owner == XFS_RMAP_OWN_REFC) {
|
||||
/* refcountbt block, dump it when we're done. */
|
||||
rr->btblocks += rmap.rm_blockcount;
|
||||
rr->btblocks += rmap->rm_blockcount;
|
||||
error = xagb_bitmap_set(&rr->old_refcountbt_blocks,
|
||||
rmap.rm_startblock, rmap.rm_blockcount);
|
||||
rmap->rm_startblock,
|
||||
rmap->rm_blockcount);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
} while (!xrep_refc_rmap_shareable(mp, &rmap));
|
||||
} while (!xrep_refc_rmap_shareable(mp, rmap));
|
||||
|
||||
rrm->startblock = rmap.rm_startblock;
|
||||
rrm->blockcount = rmap.rm_blockcount;
|
||||
*have_rec = true;
|
||||
return 0;
|
||||
}
|
||||
@ -357,45 +364,6 @@ xrep_refc_sort_records(
|
||||
return error;
|
||||
}
|
||||
|
||||
#define RRM_NEXT(r) ((r).startblock + (r).blockcount)
|
||||
/*
|
||||
* Find the next block where the refcount changes, given the next rmap we
|
||||
* looked at and the ones we're already tracking.
|
||||
*/
|
||||
static inline int
|
||||
xrep_refc_next_edge(
|
||||
struct xfarray *rmap_bag,
|
||||
struct xrep_refc_rmap *next_rrm,
|
||||
bool next_valid,
|
||||
xfs_agblock_t *nbnop)
|
||||
{
|
||||
struct xrep_refc_rmap rrm;
|
||||
xfarray_idx_t array_cur = XFARRAY_CURSOR_INIT;
|
||||
xfs_agblock_t nbno = NULLAGBLOCK;
|
||||
int error;
|
||||
|
||||
if (next_valid)
|
||||
nbno = next_rrm->startblock;
|
||||
|
||||
while ((error = xfarray_iter(rmap_bag, &array_cur, &rrm)) == 1)
|
||||
nbno = min_t(xfs_agblock_t, nbno, RRM_NEXT(rrm));
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* We should have found /something/ because either next_rrm is the next
|
||||
* interesting rmap to look at after emitting this refcount extent, or
|
||||
* there are other rmaps in rmap_bag contributing to the current
|
||||
* sharing count. But if something is seriously wrong, bail out.
|
||||
*/
|
||||
if (nbno == NULLAGBLOCK)
|
||||
return -EFSCORRUPTED;
|
||||
|
||||
*nbnop = nbno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk forward through the rmap btree to collect all rmaps starting at
|
||||
* @bno in @rmap_bag. These represent the file(s) that share ownership of
|
||||
@ -405,22 +373,21 @@ xrep_refc_next_edge(
|
||||
static int
|
||||
xrep_refc_push_rmaps_at(
|
||||
struct xrep_refc *rr,
|
||||
struct xfarray *rmap_bag,
|
||||
struct rcbag *rcstack,
|
||||
xfs_agblock_t bno,
|
||||
struct xrep_refc_rmap *rrm,
|
||||
bool *have,
|
||||
uint64_t *stack_sz)
|
||||
struct xfs_rmap_irec *rmap,
|
||||
bool *have)
|
||||
{
|
||||
struct xfs_scrub *sc = rr->sc;
|
||||
int have_gt;
|
||||
int error;
|
||||
|
||||
while (*have && rrm->startblock == bno) {
|
||||
error = xfarray_store_anywhere(rmap_bag, rrm);
|
||||
while (*have && rmap->rm_startblock == bno) {
|
||||
error = rcbag_add(rcstack, rr->sc->tp, rmap);
|
||||
if (error)
|
||||
return error;
|
||||
(*stack_sz)++;
|
||||
error = xrep_refc_walk_rmaps(rr, rrm, have);
|
||||
|
||||
error = xrep_refc_walk_rmaps(rr, rmap, have);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
@ -441,12 +408,9 @@ STATIC int
|
||||
xrep_refc_find_refcounts(
|
||||
struct xrep_refc *rr)
|
||||
{
|
||||
struct xrep_refc_rmap rrm;
|
||||
struct xfs_scrub *sc = rr->sc;
|
||||
struct xfarray *rmap_bag;
|
||||
char *descr;
|
||||
uint64_t old_stack_sz;
|
||||
uint64_t stack_sz = 0;
|
||||
struct rcbag *rcstack;
|
||||
uint64_t old_stack_height;
|
||||
xfs_agblock_t sbno;
|
||||
xfs_agblock_t cbno;
|
||||
xfs_agblock_t nbno;
|
||||
@ -456,14 +420,11 @@ xrep_refc_find_refcounts(
|
||||
xrep_ag_btcur_init(sc, &sc->sa);
|
||||
|
||||
/*
|
||||
* Set up a sparse array to store all the rmap records that we're
|
||||
* tracking to generate a reference count record. If this exceeds
|
||||
* Set up a bag to store all the rmap records that we're tracking to
|
||||
* generate a reference count record. If the size of the bag exceeds
|
||||
* MAXREFCOUNT, we clamp rc_refcount.
|
||||
*/
|
||||
descr = xchk_xfile_ag_descr(sc, "rmap record bag");
|
||||
error = xfarray_create(descr, 0, sizeof(struct xrep_refc_rmap),
|
||||
&rmap_bag);
|
||||
kfree(descr);
|
||||
error = rcbag_init(sc->mp, sc->xmbtp, &rcstack);
|
||||
if (error)
|
||||
goto out_cur;
|
||||
|
||||
@ -474,62 +435,54 @@ xrep_refc_find_refcounts(
|
||||
|
||||
/* Process reverse mappings into refcount data. */
|
||||
while (xfs_btree_has_more_records(sc->sa.rmap_cur)) {
|
||||
struct xfs_rmap_irec rmap;
|
||||
|
||||
/* Push all rmaps with pblk == sbno onto the stack */
|
||||
error = xrep_refc_walk_rmaps(rr, &rrm, &have);
|
||||
error = xrep_refc_walk_rmaps(rr, &rmap, &have);
|
||||
if (error)
|
||||
goto out_bag;
|
||||
if (!have)
|
||||
break;
|
||||
sbno = cbno = rrm.startblock;
|
||||
error = xrep_refc_push_rmaps_at(rr, rmap_bag, sbno,
|
||||
&rrm, &have, &stack_sz);
|
||||
sbno = cbno = rmap.rm_startblock;
|
||||
error = xrep_refc_push_rmaps_at(rr, rcstack, sbno, &rmap,
|
||||
&have);
|
||||
if (error)
|
||||
goto out_bag;
|
||||
|
||||
/* Set nbno to the bno of the next refcount change */
|
||||
error = xrep_refc_next_edge(rmap_bag, &rrm, have, &nbno);
|
||||
error = rcbag_next_edge(rcstack, sc->tp, &rmap, have, &nbno);
|
||||
if (error)
|
||||
goto out_bag;
|
||||
|
||||
ASSERT(nbno > sbno);
|
||||
old_stack_sz = stack_sz;
|
||||
old_stack_height = rcbag_count(rcstack);
|
||||
|
||||
/* While stack isn't empty... */
|
||||
while (stack_sz) {
|
||||
xfarray_idx_t array_cur = XFARRAY_CURSOR_INIT;
|
||||
|
||||
while (rcbag_count(rcstack) > 0) {
|
||||
/* Pop all rmaps that end at nbno */
|
||||
while ((error = xfarray_iter(rmap_bag, &array_cur,
|
||||
&rrm)) == 1) {
|
||||
if (RRM_NEXT(rrm) != nbno)
|
||||
continue;
|
||||
error = xfarray_unset(rmap_bag, array_cur - 1);
|
||||
if (error)
|
||||
goto out_bag;
|
||||
stack_sz--;
|
||||
}
|
||||
error = rcbag_remove_ending_at(rcstack, sc->tp, nbno);
|
||||
if (error)
|
||||
goto out_bag;
|
||||
|
||||
/* Push array items that start at nbno */
|
||||
error = xrep_refc_walk_rmaps(rr, &rrm, &have);
|
||||
error = xrep_refc_walk_rmaps(rr, &rmap, &have);
|
||||
if (error)
|
||||
goto out_bag;
|
||||
if (have) {
|
||||
error = xrep_refc_push_rmaps_at(rr, rmap_bag,
|
||||
nbno, &rrm, &have, &stack_sz);
|
||||
error = xrep_refc_push_rmaps_at(rr, rcstack,
|
||||
nbno, &rmap, &have);
|
||||
if (error)
|
||||
goto out_bag;
|
||||
}
|
||||
|
||||
/* Emit refcount if necessary */
|
||||
ASSERT(nbno > cbno);
|
||||
if (stack_sz != old_stack_sz) {
|
||||
if (old_stack_sz > 1) {
|
||||
if (rcbag_count(rcstack) != old_stack_height) {
|
||||
if (old_stack_height > 1) {
|
||||
error = xrep_refc_stash(rr,
|
||||
XFS_REFC_DOMAIN_SHARED,
|
||||
cbno, nbno - cbno,
|
||||
old_stack_sz);
|
||||
old_stack_height);
|
||||
if (error)
|
||||
goto out_bag;
|
||||
}
|
||||
@ -537,13 +490,13 @@ xrep_refc_find_refcounts(
|
||||
}
|
||||
|
||||
/* Stack empty, go find the next rmap */
|
||||
if (stack_sz == 0)
|
||||
if (rcbag_count(rcstack) == 0)
|
||||
break;
|
||||
old_stack_sz = stack_sz;
|
||||
old_stack_height = rcbag_count(rcstack);
|
||||
sbno = nbno;
|
||||
|
||||
/* Set nbno to the bno of the next refcount change */
|
||||
error = xrep_refc_next_edge(rmap_bag, &rrm, have,
|
||||
error = rcbag_next_edge(rcstack, sc->tp, &rmap, have,
|
||||
&nbno);
|
||||
if (error)
|
||||
goto out_bag;
|
||||
@ -552,14 +505,13 @@ xrep_refc_find_refcounts(
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(stack_sz == 0);
|
||||
ASSERT(rcbag_count(rcstack) == 0);
|
||||
out_bag:
|
||||
xfarray_destroy(rmap_bag);
|
||||
rcbag_free(&rcstack);
|
||||
out_cur:
|
||||
xchk_ag_btcur_free(&sc->sa);
|
||||
return error;
|
||||
}
|
||||
#undef RRM_NEXT
|
||||
|
||||
/* Retrieve refcountbt data for bulk load. */
|
||||
STATIC int
|
||||
|
@ -89,6 +89,7 @@ int xrep_reset_perag_resv(struct xfs_scrub *sc);
|
||||
int xrep_bmap(struct xfs_scrub *sc, int whichfork, bool allow_unwritten);
|
||||
int xrep_metadata_inode_forks(struct xfs_scrub *sc);
|
||||
int xrep_setup_ag_rmapbt(struct xfs_scrub *sc);
|
||||
int xrep_setup_ag_refcountbt(struct xfs_scrub *sc);
|
||||
|
||||
/* Repair setup functions */
|
||||
int xrep_setup_ag_allocbt(struct xfs_scrub *sc);
|
||||
@ -186,6 +187,7 @@ xrep_setup_nothing(
|
||||
}
|
||||
#define xrep_setup_ag_allocbt xrep_setup_nothing
|
||||
#define xrep_setup_ag_rmapbt xrep_setup_nothing
|
||||
#define xrep_setup_ag_refcountbt xrep_setup_nothing
|
||||
|
||||
#define xrep_setup_inode(sc, imap) ((void)0)
|
||||
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "xfs_dahash_test.h"
|
||||
#include "xfs_rtbitmap.h"
|
||||
#include "scrub/stats.h"
|
||||
#include "scrub/rcbag_btree.h"
|
||||
|
||||
#include <linux/magic.h>
|
||||
#include <linux/fs_context.h>
|
||||
@ -2060,10 +2061,14 @@ xfs_init_caches(void)
|
||||
if (error)
|
||||
goto out_destroy_log_ticket_cache;
|
||||
|
||||
error = xfs_defer_init_item_caches();
|
||||
error = rcbagbt_init_cur_cache();
|
||||
if (error)
|
||||
goto out_destroy_btree_cur_cache;
|
||||
|
||||
error = xfs_defer_init_item_caches();
|
||||
if (error)
|
||||
goto out_destroy_rcbagbt_cur_cache;
|
||||
|
||||
xfs_da_state_cache = kmem_cache_create("xfs_da_state",
|
||||
sizeof(struct xfs_da_state),
|
||||
0, 0, NULL);
|
||||
@ -2220,6 +2225,8 @@ xfs_init_caches(void)
|
||||
kmem_cache_destroy(xfs_da_state_cache);
|
||||
out_destroy_defer_item_cache:
|
||||
xfs_defer_destroy_item_caches();
|
||||
out_destroy_rcbagbt_cur_cache:
|
||||
rcbagbt_destroy_cur_cache();
|
||||
out_destroy_btree_cur_cache:
|
||||
xfs_btree_destroy_cur_caches();
|
||||
out_destroy_log_ticket_cache:
|
||||
@ -2257,6 +2264,7 @@ xfs_destroy_caches(void)
|
||||
kmem_cache_destroy(xfs_ifork_cache);
|
||||
kmem_cache_destroy(xfs_da_state_cache);
|
||||
xfs_defer_destroy_item_caches();
|
||||
rcbagbt_destroy_cur_cache();
|
||||
xfs_btree_destroy_cur_caches();
|
||||
kmem_cache_destroy(xfs_log_ticket_cache);
|
||||
kmem_cache_destroy(xfs_buf_cache);
|
||||
|
Loading…
Reference in New Issue
Block a user