mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 10:49:33 +00:00
xfs: use per-AG bitmaps to reap unused AG metadata blocks during repair
The AGFL repair code uses a series of bitmaps to figure out where there are OWN_AG blocks that are not claimed by the free space and rmap btrees. These blocks become the new AGFL, and any overflow is reaped. The bitmaps current track xfs_fsblock_t even though we already know the AG number. In the last patch, we introduced a new bitmap "type" for tracking xfs_agblock_t extents. Port the reaping code and the AGFL repair to use this new type, which makes it very obvious what we're tracking. This also eliminates a bunch of unnecessary agblock <-> fsblock conversions. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com>
This commit is contained in:
parent
1c7ce115e5
commit
014ad53732
5 changed files with 45 additions and 95 deletions
|
@ -445,13 +445,13 @@ xrep_agf(
|
|||
|
||||
struct xrep_agfl {
|
||||
/* Bitmap of alleged AGFL blocks that we're not going to add. */
|
||||
struct xbitmap crossed;
|
||||
struct xagb_bitmap crossed;
|
||||
|
||||
/* Bitmap of other OWN_AG metadata blocks. */
|
||||
struct xbitmap agmetablocks;
|
||||
struct xagb_bitmap agmetablocks;
|
||||
|
||||
/* Bitmap of free space. */
|
||||
struct xbitmap *freesp;
|
||||
struct xagb_bitmap *freesp;
|
||||
|
||||
/* rmapbt cursor for finding crosslinked blocks */
|
||||
struct xfs_btree_cur *rmap_cur;
|
||||
|
@ -467,7 +467,6 @@ xrep_agfl_walk_rmap(
|
|||
void *priv)
|
||||
{
|
||||
struct xrep_agfl *ra = priv;
|
||||
xfs_fsblock_t fsb;
|
||||
int error = 0;
|
||||
|
||||
if (xchk_should_terminate(ra->sc, &error))
|
||||
|
@ -475,14 +474,13 @@ xrep_agfl_walk_rmap(
|
|||
|
||||
/* Record all the OWN_AG blocks. */
|
||||
if (rec->rm_owner == XFS_RMAP_OWN_AG) {
|
||||
fsb = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.pag->pag_agno,
|
||||
rec->rm_startblock);
|
||||
error = xbitmap_set(ra->freesp, fsb, rec->rm_blockcount);
|
||||
error = xagb_bitmap_set(ra->freesp, rec->rm_startblock,
|
||||
rec->rm_blockcount);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
return xbitmap_set_btcur_path(&ra->agmetablocks, cur);
|
||||
return xagb_bitmap_set_btcur_path(&ra->agmetablocks, cur);
|
||||
}
|
||||
|
||||
/* Strike out the blocks that are cross-linked according to the rmapbt. */
|
||||
|
@ -493,12 +491,10 @@ xrep_agfl_check_extent(
|
|||
void *priv)
|
||||
{
|
||||
struct xrep_agfl *ra = priv;
|
||||
xfs_agblock_t agbno = XFS_FSB_TO_AGBNO(ra->sc->mp, start);
|
||||
xfs_agblock_t agbno = start;
|
||||
xfs_agblock_t last_agbno = agbno + len - 1;
|
||||
int error;
|
||||
|
||||
ASSERT(XFS_FSB_TO_AGNO(ra->sc->mp, start) == ra->sc->sa.pag->pag_agno);
|
||||
|
||||
while (agbno <= last_agbno) {
|
||||
bool other_owners;
|
||||
|
||||
|
@ -508,7 +504,7 @@ xrep_agfl_check_extent(
|
|||
return error;
|
||||
|
||||
if (other_owners) {
|
||||
error = xbitmap_set(&ra->crossed, agbno, 1);
|
||||
error = xagb_bitmap_set(&ra->crossed, agbno, 1);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
@ -534,7 +530,7 @@ STATIC int
|
|||
xrep_agfl_collect_blocks(
|
||||
struct xfs_scrub *sc,
|
||||
struct xfs_buf *agf_bp,
|
||||
struct xbitmap *agfl_extents,
|
||||
struct xagb_bitmap *agfl_extents,
|
||||
xfs_agblock_t *flcount)
|
||||
{
|
||||
struct xrep_agfl ra;
|
||||
|
@ -544,8 +540,8 @@ xrep_agfl_collect_blocks(
|
|||
|
||||
ra.sc = sc;
|
||||
ra.freesp = agfl_extents;
|
||||
xbitmap_init(&ra.agmetablocks);
|
||||
xbitmap_init(&ra.crossed);
|
||||
xagb_bitmap_init(&ra.agmetablocks);
|
||||
xagb_bitmap_init(&ra.crossed);
|
||||
|
||||
/* Find all space used by the free space btrees & rmapbt. */
|
||||
cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag);
|
||||
|
@ -557,7 +553,7 @@ xrep_agfl_collect_blocks(
|
|||
/* Find all blocks currently being used by the bnobt. */
|
||||
cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
|
||||
sc->sa.pag, XFS_BTNUM_BNO);
|
||||
error = xbitmap_set_btblocks(&ra.agmetablocks, cur);
|
||||
error = xagb_bitmap_set_btblocks(&ra.agmetablocks, cur);
|
||||
xfs_btree_del_cursor(cur, error);
|
||||
if (error)
|
||||
goto out_bmp;
|
||||
|
@ -565,7 +561,7 @@ xrep_agfl_collect_blocks(
|
|||
/* Find all blocks currently being used by the cntbt. */
|
||||
cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
|
||||
sc->sa.pag, XFS_BTNUM_CNT);
|
||||
error = xbitmap_set_btblocks(&ra.agmetablocks, cur);
|
||||
error = xagb_bitmap_set_btblocks(&ra.agmetablocks, cur);
|
||||
xfs_btree_del_cursor(cur, error);
|
||||
if (error)
|
||||
goto out_bmp;
|
||||
|
@ -574,17 +570,17 @@ xrep_agfl_collect_blocks(
|
|||
* Drop the freesp meta blocks that are in use by btrees.
|
||||
* The remaining blocks /should/ be AGFL blocks.
|
||||
*/
|
||||
error = xbitmap_disunion(agfl_extents, &ra.agmetablocks);
|
||||
error = xagb_bitmap_disunion(agfl_extents, &ra.agmetablocks);
|
||||
if (error)
|
||||
goto out_bmp;
|
||||
|
||||
/* Strike out the blocks that are cross-linked. */
|
||||
ra.rmap_cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag);
|
||||
error = xbitmap_walk(agfl_extents, xrep_agfl_check_extent, &ra);
|
||||
error = xagb_bitmap_walk(agfl_extents, xrep_agfl_check_extent, &ra);
|
||||
xfs_btree_del_cursor(ra.rmap_cur, error);
|
||||
if (error)
|
||||
goto out_bmp;
|
||||
error = xbitmap_disunion(agfl_extents, &ra.crossed);
|
||||
error = xagb_bitmap_disunion(agfl_extents, &ra.crossed);
|
||||
if (error)
|
||||
goto out_bmp;
|
||||
|
||||
|
@ -592,12 +588,12 @@ xrep_agfl_collect_blocks(
|
|||
* Calculate the new AGFL size. If we found more blocks than fit in
|
||||
* the AGFL we'll free them later.
|
||||
*/
|
||||
*flcount = min_t(uint64_t, xbitmap_hweight(agfl_extents),
|
||||
*flcount = min_t(uint64_t, xagb_bitmap_hweight(agfl_extents),
|
||||
xfs_agfl_size(mp));
|
||||
|
||||
out_bmp:
|
||||
xbitmap_destroy(&ra.crossed);
|
||||
xbitmap_destroy(&ra.agmetablocks);
|
||||
xagb_bitmap_destroy(&ra.crossed);
|
||||
xagb_bitmap_destroy(&ra.agmetablocks);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -627,7 +623,7 @@ xrep_agfl_update_agf(
|
|||
}
|
||||
|
||||
struct xrep_agfl_fill {
|
||||
struct xbitmap used_extents;
|
||||
struct xagb_bitmap used_extents;
|
||||
struct xfs_scrub *sc;
|
||||
__be32 *agfl_bno;
|
||||
xfs_agblock_t flcount;
|
||||
|
@ -643,17 +639,15 @@ xrep_agfl_fill(
|
|||
{
|
||||
struct xrep_agfl_fill *af = priv;
|
||||
struct xfs_scrub *sc = af->sc;
|
||||
xfs_fsblock_t fsbno = start;
|
||||
xfs_agblock_t agbno = start;
|
||||
int error;
|
||||
|
||||
trace_xrep_agfl_insert(sc->sa.pag, XFS_FSB_TO_AGBNO(sc->mp, start),
|
||||
len);
|
||||
trace_xrep_agfl_insert(sc->sa.pag, agbno, len);
|
||||
|
||||
while (fsbno < start + len && af->fl_off < af->flcount)
|
||||
af->agfl_bno[af->fl_off++] =
|
||||
cpu_to_be32(XFS_FSB_TO_AGBNO(sc->mp, fsbno++));
|
||||
while (agbno < start + len && af->fl_off < af->flcount)
|
||||
af->agfl_bno[af->fl_off++] = cpu_to_be32(agbno++);
|
||||
|
||||
error = xbitmap_set(&af->used_extents, start, fsbno - 1);
|
||||
error = xagb_bitmap_set(&af->used_extents, start, agbno - 1);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -668,7 +662,7 @@ STATIC int
|
|||
xrep_agfl_init_header(
|
||||
struct xfs_scrub *sc,
|
||||
struct xfs_buf *agfl_bp,
|
||||
struct xbitmap *agfl_extents,
|
||||
struct xagb_bitmap *agfl_extents,
|
||||
xfs_agblock_t flcount)
|
||||
{
|
||||
struct xrep_agfl_fill af = {
|
||||
|
@ -696,17 +690,17 @@ xrep_agfl_init_header(
|
|||
* blocks than fit in the AGFL, they will be freed in a subsequent
|
||||
* step.
|
||||
*/
|
||||
xbitmap_init(&af.used_extents);
|
||||
xagb_bitmap_init(&af.used_extents);
|
||||
af.agfl_bno = xfs_buf_to_agfl_bno(agfl_bp),
|
||||
xbitmap_walk(agfl_extents, xrep_agfl_fill, &af);
|
||||
error = xbitmap_disunion(agfl_extents, &af.used_extents);
|
||||
xagb_bitmap_walk(agfl_extents, xrep_agfl_fill, &af);
|
||||
error = xagb_bitmap_disunion(agfl_extents, &af.used_extents);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* Write new AGFL to disk. */
|
||||
xfs_trans_buf_set_type(sc->tp, agfl_bp, XFS_BLFT_AGFL_BUF);
|
||||
xfs_trans_log_buf(sc->tp, agfl_bp, 0, BBTOB(agfl_bp->b_length) - 1);
|
||||
xbitmap_destroy(&af.used_extents);
|
||||
xagb_bitmap_destroy(&af.used_extents);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -715,7 +709,7 @@ int
|
|||
xrep_agfl(
|
||||
struct xfs_scrub *sc)
|
||||
{
|
||||
struct xbitmap agfl_extents;
|
||||
struct xagb_bitmap agfl_extents;
|
||||
struct xfs_mount *mp = sc->mp;
|
||||
struct xfs_buf *agf_bp;
|
||||
struct xfs_buf *agfl_bp;
|
||||
|
@ -726,7 +720,7 @@ xrep_agfl(
|
|||
if (!xfs_has_rmapbt(mp))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
xbitmap_init(&agfl_extents);
|
||||
xagb_bitmap_init(&agfl_extents);
|
||||
|
||||
/*
|
||||
* Read the AGF so that we can query the rmapbt. We hope that there's
|
||||
|
@ -775,10 +769,10 @@ xrep_agfl(
|
|||
goto err;
|
||||
|
||||
/* Dump any AGFL overflow. */
|
||||
error = xrep_reap_ag_metadata(sc, &agfl_extents, &XFS_RMAP_OINFO_AG,
|
||||
error = xrep_reap_agblocks(sc, &agfl_extents, &XFS_RMAP_OINFO_AG,
|
||||
XFS_AG_RESV_AGFL);
|
||||
err:
|
||||
xbitmap_destroy(&agfl_extents);
|
||||
xagb_bitmap_destroy(&agfl_extents);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
|
@ -301,21 +301,15 @@ xagb_bitmap_set_btblocks(
|
|||
* blocks going from the leaf towards the root.
|
||||
*/
|
||||
int
|
||||
xbitmap_set_btcur_path(
|
||||
struct xbitmap *bitmap,
|
||||
xagb_bitmap_set_btcur_path(
|
||||
struct xagb_bitmap *bitmap,
|
||||
struct xfs_btree_cur *cur)
|
||||
{
|
||||
struct xfs_buf *bp;
|
||||
xfs_fsblock_t fsb;
|
||||
int i;
|
||||
int error;
|
||||
|
||||
for (i = 0; i < cur->bc_nlevels && cur->bc_levels[i].ptr == 1; i++) {
|
||||
xfs_btree_get_block(cur, i, &bp);
|
||||
if (!bp)
|
||||
continue;
|
||||
fsb = XFS_DADDR_TO_FSB(cur->bc_mp, xfs_buf_daddr(bp));
|
||||
error = xbitmap_set(bitmap, fsb, 1);
|
||||
error = xagb_bitmap_visit_btblock(cur, i, bitmap);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
@ -323,35 +317,6 @@ xbitmap_set_btcur_path(
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Collect a btree's block in the bitmap. */
|
||||
STATIC int
|
||||
xbitmap_collect_btblock(
|
||||
struct xfs_btree_cur *cur,
|
||||
int level,
|
||||
void *priv)
|
||||
{
|
||||
struct xbitmap *bitmap = priv;
|
||||
struct xfs_buf *bp;
|
||||
xfs_fsblock_t fsbno;
|
||||
|
||||
xfs_btree_get_block(cur, level, &bp);
|
||||
if (!bp)
|
||||
return 0;
|
||||
|
||||
fsbno = XFS_DADDR_TO_FSB(cur->bc_mp, xfs_buf_daddr(bp));
|
||||
return xbitmap_set(bitmap, fsbno, 1);
|
||||
}
|
||||
|
||||
/* Walk the btree and mark the bitmap wherever a btree block is found. */
|
||||
int
|
||||
xbitmap_set_btblocks(
|
||||
struct xbitmap *bitmap,
|
||||
struct xfs_btree_cur *cur)
|
||||
{
|
||||
return xfs_btree_visit_blocks(cur, xbitmap_collect_btblock,
|
||||
XFS_BTREE_VISIT_ALL, bitmap);
|
||||
}
|
||||
|
||||
/* How many bits are set in this bitmap? */
|
||||
uint64_t
|
||||
xbitmap_hweight(
|
||||
|
|
|
@ -16,10 +16,6 @@ void xbitmap_destroy(struct xbitmap *bitmap);
|
|||
int xbitmap_clear(struct xbitmap *bitmap, uint64_t start, uint64_t len);
|
||||
int xbitmap_set(struct xbitmap *bitmap, uint64_t start, uint64_t len);
|
||||
int xbitmap_disunion(struct xbitmap *bitmap, struct xbitmap *sub);
|
||||
int xbitmap_set_btcur_path(struct xbitmap *bitmap,
|
||||
struct xfs_btree_cur *cur);
|
||||
int xbitmap_set_btblocks(struct xbitmap *bitmap,
|
||||
struct xfs_btree_cur *cur);
|
||||
uint64_t xbitmap_hweight(struct xbitmap *bitmap);
|
||||
|
||||
/*
|
||||
|
@ -106,5 +102,7 @@ static inline int xagb_bitmap_walk(struct xagb_bitmap *bitmap,
|
|||
|
||||
int xagb_bitmap_set_btblocks(struct xagb_bitmap *bitmap,
|
||||
struct xfs_btree_cur *cur);
|
||||
int xagb_bitmap_set_btcur_path(struct xagb_bitmap *bitmap,
|
||||
struct xfs_btree_cur *cur);
|
||||
|
||||
#endif /* __XFS_SCRUB_BITMAP_H__ */
|
||||
|
|
|
@ -431,19 +431,13 @@ xreap_agmeta_extent(
|
|||
{
|
||||
struct xreap_state *rs = priv;
|
||||
struct xfs_scrub *sc = rs->sc;
|
||||
xfs_agnumber_t agno = XFS_FSB_TO_AGNO(sc->mp, fsbno);
|
||||
xfs_agblock_t agbno = XFS_FSB_TO_AGBNO(sc->mp, fsbno);
|
||||
xfs_agblock_t agbno = fsbno;
|
||||
xfs_agblock_t agbno_next = agbno + len;
|
||||
int error = 0;
|
||||
|
||||
ASSERT(len <= XFS_MAX_BMBT_EXTLEN);
|
||||
ASSERT(sc->ip == NULL);
|
||||
|
||||
if (agno != sc->sa.pag->pag_agno) {
|
||||
ASSERT(sc->sa.pag->pag_agno == agno);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
while (agbno < agbno_next) {
|
||||
xfs_extlen_t aglen;
|
||||
bool crosslinked;
|
||||
|
@ -477,9 +471,9 @@ xreap_agmeta_extent(
|
|||
|
||||
/* Dispose of every block of every AG metadata extent in the bitmap. */
|
||||
int
|
||||
xrep_reap_ag_metadata(
|
||||
xrep_reap_agblocks(
|
||||
struct xfs_scrub *sc,
|
||||
struct xbitmap *bitmap,
|
||||
struct xagb_bitmap *bitmap,
|
||||
const struct xfs_owner_info *oinfo,
|
||||
enum xfs_ag_resv_type type)
|
||||
{
|
||||
|
@ -493,7 +487,7 @@ xrep_reap_ag_metadata(
|
|||
ASSERT(xfs_has_rmapbt(sc->mp));
|
||||
ASSERT(sc->ip == NULL);
|
||||
|
||||
error = xbitmap_walk(bitmap, xreap_agmeta_extent, &rs);
|
||||
error = xagb_bitmap_walk(bitmap, xreap_agmeta_extent, &rs);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
#ifndef __XFS_SCRUB_REAP_H__
|
||||
#define __XFS_SCRUB_REAP_H__
|
||||
|
||||
int xrep_reap_ag_metadata(struct xfs_scrub *sc, struct xbitmap *bitmap,
|
||||
const struct xfs_owner_info *oinfo,
|
||||
enum xfs_ag_resv_type type);
|
||||
int xrep_reap_agblocks(struct xfs_scrub *sc, struct xagb_bitmap *bitmap,
|
||||
const struct xfs_owner_info *oinfo, enum xfs_ag_resv_type type);
|
||||
|
||||
#endif /* __XFS_SCRUB_REAP_H__ */
|
||||
|
|
Loading…
Reference in a new issue