Commit 7fbaab57 authored by Darrick J. Wong's avatar Darrick J. Wong

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: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 7a2192ac
...@@ -7,8 +7,10 @@ ...@@ -7,8 +7,10 @@
#include "xfs_fs.h" #include "xfs_fs.h"
#include "xfs_shared.h" #include "xfs_shared.h"
#include "xfs_format.h" #include "xfs_format.h"
#include "xfs_log_format.h"
#include "xfs_trans_resv.h" #include "xfs_trans_resv.h"
#include "xfs_mount.h" #include "xfs_mount.h"
#include "xfs_trans.h"
#include "xfs_ag.h" #include "xfs_ag.h"
#include "xfs_btree.h" #include "xfs_btree.h"
#include "xfs_rmap.h" #include "xfs_rmap.h"
...@@ -17,6 +19,7 @@ ...@@ -17,6 +19,7 @@
#include "scrub/common.h" #include "scrub/common.h"
#include "scrub/btree.h" #include "scrub/btree.h"
#include "scrub/trace.h" #include "scrub/trace.h"
#include "scrub/repair.h"
/* /*
* Set us up to scrub reference count btrees. * Set us up to scrub reference count btrees.
...@@ -27,6 +30,15 @@ xchk_setup_ag_refcountbt( ...@@ -27,6 +30,15 @@ xchk_setup_ag_refcountbt(
{ {
if (xchk_need_intent_drain(sc)) if (xchk_need_intent_drain(sc))
xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN); 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); return xchk_setup_ag_btree(sc, false);
} }
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include "scrub/xfarray.h" #include "scrub/xfarray.h"
#include "scrub/newbt.h" #include "scrub/newbt.h"
#include "scrub/reap.h" #include "scrub/reap.h"
#include "scrub/rcbag.h"
/* /*
* Rebuilding the Reference Count Btree * Rebuilding the Reference Count Btree
...@@ -98,12 +99,6 @@ ...@@ -98,12 +99,6 @@
* insert all the records. * 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 { struct xrep_refc {
/* refcount extents */ /* refcount extents */
struct xfarray *refcount_records; struct xfarray *refcount_records;
...@@ -123,6 +118,20 @@ struct xrep_refc { ...@@ -123,6 +118,20 @@ struct xrep_refc {
xfs_extlen_t btblocks; 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. */ /* Check for any obvious conflicts with this shared/CoW staging extent. */
STATIC int STATIC int
xrep_refc_check_ext( xrep_refc_check_ext(
...@@ -224,10 +233,9 @@ xrep_refc_rmap_shareable( ...@@ -224,10 +233,9 @@ xrep_refc_rmap_shareable(
STATIC int STATIC int
xrep_refc_walk_rmaps( xrep_refc_walk_rmaps(
struct xrep_refc *rr, struct xrep_refc *rr,
struct xrep_refc_rmap *rrm, struct xfs_rmap_irec *rmap,
bool *have_rec) bool *have_rec)
{ {
struct xfs_rmap_irec rmap;
struct xfs_btree_cur *cur = rr->sc->sa.rmap_cur; struct xfs_btree_cur *cur = rr->sc->sa.rmap_cur;
struct xfs_mount *mp = cur->bc_mp; struct xfs_mount *mp = cur->bc_mp;
int have_gt; int have_gt;
...@@ -251,7 +259,7 @@ xrep_refc_walk_rmaps( ...@@ -251,7 +259,7 @@ xrep_refc_walk_rmaps(
if (!have_gt) if (!have_gt)
return 0; return 0;
error = xfs_rmap_get_rec(cur, &rmap, &have_gt); error = xfs_rmap_get_rec(cur, rmap, &have_gt);
if (error) if (error)
return error; return error;
if (XFS_IS_CORRUPT(mp, !have_gt)) { if (XFS_IS_CORRUPT(mp, !have_gt)) {
...@@ -259,23 +267,22 @@ xrep_refc_walk_rmaps( ...@@ -259,23 +267,22 @@ xrep_refc_walk_rmaps(
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
if (rmap.rm_owner == XFS_RMAP_OWN_COW) { if (rmap->rm_owner == XFS_RMAP_OWN_COW) {
error = xrep_refc_stash_cow(rr, rmap.rm_startblock, error = xrep_refc_stash_cow(rr, rmap->rm_startblock,
rmap.rm_blockcount); rmap->rm_blockcount);
if (error) if (error)
return 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. */ /* 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, error = xagb_bitmap_set(&rr->old_refcountbt_blocks,
rmap.rm_startblock, rmap.rm_blockcount); rmap->rm_startblock,
rmap->rm_blockcount);
if (error) if (error)
return 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; *have_rec = true;
return 0; return 0;
} }
...@@ -357,45 +364,6 @@ xrep_refc_sort_records( ...@@ -357,45 +364,6 @@ xrep_refc_sort_records(
return error; 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 * 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 * @bno in @rmap_bag. These represent the file(s) that share ownership of
...@@ -405,22 +373,21 @@ xrep_refc_next_edge( ...@@ -405,22 +373,21 @@ xrep_refc_next_edge(
static int static int
xrep_refc_push_rmaps_at( xrep_refc_push_rmaps_at(
struct xrep_refc *rr, struct xrep_refc *rr,
struct xfarray *rmap_bag, struct rcbag *rcstack,
xfs_agblock_t bno, xfs_agblock_t bno,
struct xrep_refc_rmap *rrm, struct xfs_rmap_irec *rmap,
bool *have, bool *have)
uint64_t *stack_sz)
{ {
struct xfs_scrub *sc = rr->sc; struct xfs_scrub *sc = rr->sc;
int have_gt; int have_gt;
int error; int error;
while (*have && rrm->startblock == bno) { while (*have && rmap->rm_startblock == bno) {
error = xfarray_store_anywhere(rmap_bag, rrm); error = rcbag_add(rcstack, rr->sc->tp, rmap);
if (error) if (error)
return error; return error;
(*stack_sz)++;
error = xrep_refc_walk_rmaps(rr, rrm, have); error = xrep_refc_walk_rmaps(rr, rmap, have);
if (error) if (error)
return error; return error;
} }
...@@ -441,12 +408,9 @@ STATIC int ...@@ -441,12 +408,9 @@ STATIC int
xrep_refc_find_refcounts( xrep_refc_find_refcounts(
struct xrep_refc *rr) struct xrep_refc *rr)
{ {
struct xrep_refc_rmap rrm;
struct xfs_scrub *sc = rr->sc; struct xfs_scrub *sc = rr->sc;
struct xfarray *rmap_bag; struct rcbag *rcstack;
char *descr; uint64_t old_stack_height;
uint64_t old_stack_sz;
uint64_t stack_sz = 0;
xfs_agblock_t sbno; xfs_agblock_t sbno;
xfs_agblock_t cbno; xfs_agblock_t cbno;
xfs_agblock_t nbno; xfs_agblock_t nbno;
...@@ -456,14 +420,11 @@ xrep_refc_find_refcounts( ...@@ -456,14 +420,11 @@ xrep_refc_find_refcounts(
xrep_ag_btcur_init(sc, &sc->sa); xrep_ag_btcur_init(sc, &sc->sa);
/* /*
* Set up a sparse array to store all the rmap records that we're * Set up a bag to store all the rmap records that we're tracking to
* tracking to generate a reference count record. If this exceeds * generate a reference count record. If the size of the bag exceeds
* MAXREFCOUNT, we clamp rc_refcount. * MAXREFCOUNT, we clamp rc_refcount.
*/ */
descr = xchk_xfile_ag_descr(sc, "rmap record bag"); error = rcbag_init(sc->mp, sc->xmbtp, &rcstack);
error = xfarray_create(descr, 0, sizeof(struct xrep_refc_rmap),
&rmap_bag);
kfree(descr);
if (error) if (error)
goto out_cur; goto out_cur;
...@@ -474,62 +435,54 @@ xrep_refc_find_refcounts( ...@@ -474,62 +435,54 @@ xrep_refc_find_refcounts(
/* Process reverse mappings into refcount data. */ /* Process reverse mappings into refcount data. */
while (xfs_btree_has_more_records(sc->sa.rmap_cur)) { while (xfs_btree_has_more_records(sc->sa.rmap_cur)) {
struct xfs_rmap_irec rmap;
/* Push all rmaps with pblk == sbno onto the stack */ /* 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) if (error)
goto out_bag; goto out_bag;
if (!have) if (!have)
break; break;
sbno = cbno = rrm.startblock; sbno = cbno = rmap.rm_startblock;
error = xrep_refc_push_rmaps_at(rr, rmap_bag, sbno, error = xrep_refc_push_rmaps_at(rr, rcstack, sbno, &rmap,
&rrm, &have, &stack_sz); &have);
if (error) if (error)
goto out_bag; goto out_bag;
/* Set nbno to the bno of the next refcount change */ /* 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) if (error)
goto out_bag; goto out_bag;
ASSERT(nbno > sbno); ASSERT(nbno > sbno);
old_stack_sz = stack_sz; old_stack_height = rcbag_count(rcstack);
/* While stack isn't empty... */ /* While stack isn't empty... */
while (stack_sz) { while (rcbag_count(rcstack) > 0) {
xfarray_idx_t array_cur = XFARRAY_CURSOR_INIT;
/* Pop all rmaps that end at nbno */ /* Pop all rmaps that end at nbno */
while ((error = xfarray_iter(rmap_bag, &array_cur, error = rcbag_remove_ending_at(rcstack, sc->tp, nbno);
&rrm)) == 1) {
if (RRM_NEXT(rrm) != nbno)
continue;
error = xfarray_unset(rmap_bag, array_cur - 1);
if (error)
goto out_bag;
stack_sz--;
}
if (error) if (error)
goto out_bag; goto out_bag;
/* Push array items that start at nbno */ /* 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) if (error)
goto out_bag; goto out_bag;
if (have) { if (have) {
error = xrep_refc_push_rmaps_at(rr, rmap_bag, error = xrep_refc_push_rmaps_at(rr, rcstack,
nbno, &rrm, &have, &stack_sz); nbno, &rmap, &have);
if (error) if (error)
goto out_bag; goto out_bag;
} }
/* Emit refcount if necessary */ /* Emit refcount if necessary */
ASSERT(nbno > cbno); ASSERT(nbno > cbno);
if (stack_sz != old_stack_sz) { if (rcbag_count(rcstack) != old_stack_height) {
if (old_stack_sz > 1) { if (old_stack_height > 1) {
error = xrep_refc_stash(rr, error = xrep_refc_stash(rr,
XFS_REFC_DOMAIN_SHARED, XFS_REFC_DOMAIN_SHARED,
cbno, nbno - cbno, cbno, nbno - cbno,
old_stack_sz); old_stack_height);
if (error) if (error)
goto out_bag; goto out_bag;
} }
...@@ -537,13 +490,13 @@ xrep_refc_find_refcounts( ...@@ -537,13 +490,13 @@ xrep_refc_find_refcounts(
} }
/* Stack empty, go find the next rmap */ /* Stack empty, go find the next rmap */
if (stack_sz == 0) if (rcbag_count(rcstack) == 0)
break; break;
old_stack_sz = stack_sz; old_stack_height = rcbag_count(rcstack);
sbno = nbno; sbno = nbno;
/* Set nbno to the bno of the next refcount change */ /* 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); &nbno);
if (error) if (error)
goto out_bag; goto out_bag;
...@@ -552,14 +505,13 @@ xrep_refc_find_refcounts( ...@@ -552,14 +505,13 @@ xrep_refc_find_refcounts(
} }
} }
ASSERT(stack_sz == 0); ASSERT(rcbag_count(rcstack) == 0);
out_bag: out_bag:
xfarray_destroy(rmap_bag); rcbag_free(&rcstack);
out_cur: out_cur:
xchk_ag_btcur_free(&sc->sa); xchk_ag_btcur_free(&sc->sa);
return error; return error;
} }
#undef RRM_NEXT
/* Retrieve refcountbt data for bulk load. */ /* Retrieve refcountbt data for bulk load. */
STATIC int STATIC int
......
...@@ -89,6 +89,7 @@ int xrep_reset_perag_resv(struct xfs_scrub *sc); ...@@ -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_bmap(struct xfs_scrub *sc, int whichfork, bool allow_unwritten);
int xrep_metadata_inode_forks(struct xfs_scrub *sc); int xrep_metadata_inode_forks(struct xfs_scrub *sc);
int xrep_setup_ag_rmapbt(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 */ /* Repair setup functions */
int xrep_setup_ag_allocbt(struct xfs_scrub *sc); int xrep_setup_ag_allocbt(struct xfs_scrub *sc);
...@@ -186,6 +187,7 @@ xrep_setup_nothing( ...@@ -186,6 +187,7 @@ xrep_setup_nothing(
} }
#define xrep_setup_ag_allocbt xrep_setup_nothing #define xrep_setup_ag_allocbt xrep_setup_nothing
#define xrep_setup_ag_rmapbt 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) #define xrep_setup_inode(sc, imap) ((void)0)
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include "xfs_dahash_test.h" #include "xfs_dahash_test.h"
#include "xfs_rtbitmap.h" #include "xfs_rtbitmap.h"
#include "scrub/stats.h" #include "scrub/stats.h"
#include "scrub/rcbag_btree.h"
#include <linux/magic.h> #include <linux/magic.h>
#include <linux/fs_context.h> #include <linux/fs_context.h>
...@@ -2060,10 +2061,14 @@ xfs_init_caches(void) ...@@ -2060,10 +2061,14 @@ xfs_init_caches(void)
if (error) if (error)
goto out_destroy_log_ticket_cache; goto out_destroy_log_ticket_cache;
error = xfs_defer_init_item_caches(); error = rcbagbt_init_cur_cache();
if (error) if (error)
goto out_destroy_btree_cur_cache; 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", xfs_da_state_cache = kmem_cache_create("xfs_da_state",
sizeof(struct xfs_da_state), sizeof(struct xfs_da_state),
0, 0, NULL); 0, 0, NULL);
...@@ -2220,6 +2225,8 @@ xfs_init_caches(void) ...@@ -2220,6 +2225,8 @@ xfs_init_caches(void)
kmem_cache_destroy(xfs_da_state_cache); kmem_cache_destroy(xfs_da_state_cache);
out_destroy_defer_item_cache: out_destroy_defer_item_cache:
xfs_defer_destroy_item_caches(); xfs_defer_destroy_item_caches();
out_destroy_rcbagbt_cur_cache:
rcbagbt_destroy_cur_cache();
out_destroy_btree_cur_cache: out_destroy_btree_cur_cache:
xfs_btree_destroy_cur_caches(); xfs_btree_destroy_cur_caches();
out_destroy_log_ticket_cache: out_destroy_log_ticket_cache:
...@@ -2257,6 +2264,7 @@ xfs_destroy_caches(void) ...@@ -2257,6 +2264,7 @@ xfs_destroy_caches(void)
kmem_cache_destroy(xfs_ifork_cache); kmem_cache_destroy(xfs_ifork_cache);
kmem_cache_destroy(xfs_da_state_cache); kmem_cache_destroy(xfs_da_state_cache);
xfs_defer_destroy_item_caches(); xfs_defer_destroy_item_caches();
rcbagbt_destroy_cur_cache();
xfs_btree_destroy_cur_caches(); xfs_btree_destroy_cur_caches();
kmem_cache_destroy(xfs_log_ticket_cache); kmem_cache_destroy(xfs_log_ticket_cache);
kmem_cache_destroy(xfs_buf_cache); kmem_cache_destroy(xfs_buf_cache);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment