xfs: create helpers to scan an allocation group
Add some helpers to enable us to lock an AG's headers, create btree cursors for all btrees in that allocation group, and clean up afterwards. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Dave Chinner <dchinner@redhat.com>
This commit is contained in:
parent
37f3fa7f16
commit
b6c1beb967
|
@ -44,6 +44,7 @@
|
|||
#include "scrub/scrub.h"
|
||||
#include "scrub/common.h"
|
||||
#include "scrub/trace.h"
|
||||
#include "scrub/btree.h"
|
||||
|
||||
/* Common code for the metadata scrubbers. */
|
||||
|
||||
|
@ -237,6 +238,184 @@ xfs_scrub_set_incomplete(
|
|||
trace_xfs_scrub_incomplete(sc, __return_address);
|
||||
}
|
||||
|
||||
/*
|
||||
* AG scrubbing
|
||||
*
|
||||
* These helpers facilitate locking an allocation group's header
|
||||
* buffers, setting up cursors for all btrees that are present, and
|
||||
* cleaning everything up once we're through.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Grab all the headers for an AG.
|
||||
*
|
||||
* The headers should be released by xfs_scrub_ag_free, but as a fail
|
||||
* safe we attach all the buffers we grab to the scrub transaction so
|
||||
* they'll all be freed when we cancel it.
|
||||
*/
|
||||
int
|
||||
xfs_scrub_ag_read_headers(
|
||||
struct xfs_scrub_context *sc,
|
||||
xfs_agnumber_t agno,
|
||||
struct xfs_buf **agi,
|
||||
struct xfs_buf **agf,
|
||||
struct xfs_buf **agfl)
|
||||
{
|
||||
struct xfs_mount *mp = sc->mp;
|
||||
int error;
|
||||
|
||||
error = xfs_ialloc_read_agi(mp, sc->tp, agno, agi);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
error = xfs_alloc_read_agf(mp, sc->tp, agno, 0, agf);
|
||||
if (error)
|
||||
goto out;
|
||||
if (!*agf) {
|
||||
error = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = xfs_alloc_read_agfl(mp, sc->tp, agno, agfl);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Release all the AG btree cursors. */
|
||||
void
|
||||
xfs_scrub_ag_btcur_free(
|
||||
struct xfs_scrub_ag *sa)
|
||||
{
|
||||
if (sa->refc_cur)
|
||||
xfs_btree_del_cursor(sa->refc_cur, XFS_BTREE_ERROR);
|
||||
if (sa->rmap_cur)
|
||||
xfs_btree_del_cursor(sa->rmap_cur, XFS_BTREE_ERROR);
|
||||
if (sa->fino_cur)
|
||||
xfs_btree_del_cursor(sa->fino_cur, XFS_BTREE_ERROR);
|
||||
if (sa->ino_cur)
|
||||
xfs_btree_del_cursor(sa->ino_cur, XFS_BTREE_ERROR);
|
||||
if (sa->cnt_cur)
|
||||
xfs_btree_del_cursor(sa->cnt_cur, XFS_BTREE_ERROR);
|
||||
if (sa->bno_cur)
|
||||
xfs_btree_del_cursor(sa->bno_cur, XFS_BTREE_ERROR);
|
||||
|
||||
sa->refc_cur = NULL;
|
||||
sa->rmap_cur = NULL;
|
||||
sa->fino_cur = NULL;
|
||||
sa->ino_cur = NULL;
|
||||
sa->bno_cur = NULL;
|
||||
sa->cnt_cur = NULL;
|
||||
}
|
||||
|
||||
/* Initialize all the btree cursors for an AG. */
|
||||
int
|
||||
xfs_scrub_ag_btcur_init(
|
||||
struct xfs_scrub_context *sc,
|
||||
struct xfs_scrub_ag *sa)
|
||||
{
|
||||
struct xfs_mount *mp = sc->mp;
|
||||
xfs_agnumber_t agno = sa->agno;
|
||||
|
||||
if (sa->agf_bp) {
|
||||
/* Set up a bnobt cursor for cross-referencing. */
|
||||
sa->bno_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
|
||||
agno, XFS_BTNUM_BNO);
|
||||
if (!sa->bno_cur)
|
||||
goto err;
|
||||
|
||||
/* Set up a cntbt cursor for cross-referencing. */
|
||||
sa->cnt_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
|
||||
agno, XFS_BTNUM_CNT);
|
||||
if (!sa->cnt_cur)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Set up a inobt cursor for cross-referencing. */
|
||||
if (sa->agi_bp) {
|
||||
sa->ino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
|
||||
agno, XFS_BTNUM_INO);
|
||||
if (!sa->ino_cur)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Set up a finobt cursor for cross-referencing. */
|
||||
if (sa->agi_bp && xfs_sb_version_hasfinobt(&mp->m_sb)) {
|
||||
sa->fino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
|
||||
agno, XFS_BTNUM_FINO);
|
||||
if (!sa->fino_cur)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Set up a rmapbt cursor for cross-referencing. */
|
||||
if (sa->agf_bp && xfs_sb_version_hasrmapbt(&mp->m_sb)) {
|
||||
sa->rmap_cur = xfs_rmapbt_init_cursor(mp, sc->tp, sa->agf_bp,
|
||||
agno);
|
||||
if (!sa->rmap_cur)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Set up a refcountbt cursor for cross-referencing. */
|
||||
if (sa->agf_bp && xfs_sb_version_hasreflink(&mp->m_sb)) {
|
||||
sa->refc_cur = xfs_refcountbt_init_cursor(mp, sc->tp,
|
||||
sa->agf_bp, agno, NULL);
|
||||
if (!sa->refc_cur)
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Release the AG header context and btree cursors. */
|
||||
void
|
||||
xfs_scrub_ag_free(
|
||||
struct xfs_scrub_context *sc,
|
||||
struct xfs_scrub_ag *sa)
|
||||
{
|
||||
xfs_scrub_ag_btcur_free(sa);
|
||||
if (sa->agfl_bp) {
|
||||
xfs_trans_brelse(sc->tp, sa->agfl_bp);
|
||||
sa->agfl_bp = NULL;
|
||||
}
|
||||
if (sa->agf_bp) {
|
||||
xfs_trans_brelse(sc->tp, sa->agf_bp);
|
||||
sa->agf_bp = NULL;
|
||||
}
|
||||
if (sa->agi_bp) {
|
||||
xfs_trans_brelse(sc->tp, sa->agi_bp);
|
||||
sa->agi_bp = NULL;
|
||||
}
|
||||
sa->agno = NULLAGNUMBER;
|
||||
}
|
||||
|
||||
/*
|
||||
* For scrub, grab the AGI and the AGF headers, in that order. Locking
|
||||
* order requires us to get the AGI before the AGF. We use the
|
||||
* transaction to avoid deadlocking on crosslinked metadata buffers;
|
||||
* either the caller passes one in (bmap scrub) or we have to create a
|
||||
* transaction ourselves.
|
||||
*/
|
||||
int
|
||||
xfs_scrub_ag_init(
|
||||
struct xfs_scrub_context *sc,
|
||||
xfs_agnumber_t agno,
|
||||
struct xfs_scrub_ag *sa)
|
||||
{
|
||||
int error;
|
||||
|
||||
sa->agno = agno;
|
||||
error = xfs_scrub_ag_read_headers(sc, agno, &sa->agi_bp,
|
||||
&sa->agf_bp, &sa->agfl_bp);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return xfs_scrub_ag_btcur_init(sc, sa);
|
||||
}
|
||||
|
||||
/* Per-scrubber setup functions */
|
||||
|
||||
/* Set us up with a transaction and an empty context. */
|
||||
|
|
|
@ -77,4 +77,14 @@ void xfs_scrub_set_incomplete(struct xfs_scrub_context *sc);
|
|||
/* Setup functions */
|
||||
int xfs_scrub_setup_fs(struct xfs_scrub_context *sc, struct xfs_inode *ip);
|
||||
|
||||
void xfs_scrub_ag_free(struct xfs_scrub_context *sc, struct xfs_scrub_ag *sa);
|
||||
int xfs_scrub_ag_init(struct xfs_scrub_context *sc, xfs_agnumber_t agno,
|
||||
struct xfs_scrub_ag *sa);
|
||||
int xfs_scrub_ag_read_headers(struct xfs_scrub_context *sc, xfs_agnumber_t agno,
|
||||
struct xfs_buf **agi, struct xfs_buf **agf,
|
||||
struct xfs_buf **agfl);
|
||||
void xfs_scrub_ag_btcur_free(struct xfs_scrub_ag *sa);
|
||||
int xfs_scrub_ag_btcur_init(struct xfs_scrub_context *sc,
|
||||
struct xfs_scrub_ag *sa);
|
||||
|
||||
#endif /* __XFS_SCRUB_COMMON_H__ */
|
||||
|
|
|
@ -44,6 +44,8 @@
|
|||
#include "scrub/scrub.h"
|
||||
#include "scrub/common.h"
|
||||
#include "scrub/trace.h"
|
||||
#include "scrub/scrub.h"
|
||||
#include "scrub/btree.h"
|
||||
|
||||
/*
|
||||
* Online Scrub and Repair
|
||||
|
@ -141,6 +143,7 @@ xfs_scrub_teardown(
|
|||
struct xfs_scrub_context *sc,
|
||||
int error)
|
||||
{
|
||||
xfs_scrub_ag_free(sc, &sc->sa);
|
||||
if (sc->tp) {
|
||||
xfs_trans_cancel(sc->tp);
|
||||
sc->tp = NULL;
|
||||
|
@ -241,6 +244,7 @@ retry_op:
|
|||
sc.sm = sm;
|
||||
sc.ops = ops;
|
||||
sc.try_harder = try_harder;
|
||||
sc.sa.agno = NULLAGNUMBER;
|
||||
error = sc.ops->setup(&sc, ip);
|
||||
if (error)
|
||||
goto out_teardown;
|
||||
|
|
|
@ -34,6 +34,24 @@ struct xfs_scrub_meta_ops {
|
|||
bool (*has)(struct xfs_sb *);
|
||||
};
|
||||
|
||||
/* Buffer pointers and btree cursors for an entire AG. */
|
||||
struct xfs_scrub_ag {
|
||||
xfs_agnumber_t agno;
|
||||
|
||||
/* AG btree roots */
|
||||
struct xfs_buf *agf_bp;
|
||||
struct xfs_buf *agfl_bp;
|
||||
struct xfs_buf *agi_bp;
|
||||
|
||||
/* AG btrees */
|
||||
struct xfs_btree_cur *bno_cur;
|
||||
struct xfs_btree_cur *cnt_cur;
|
||||
struct xfs_btree_cur *ino_cur;
|
||||
struct xfs_btree_cur *fino_cur;
|
||||
struct xfs_btree_cur *rmap_cur;
|
||||
struct xfs_btree_cur *refc_cur;
|
||||
};
|
||||
|
||||
struct xfs_scrub_context {
|
||||
/* General scrub state. */
|
||||
struct xfs_mount *mp;
|
||||
|
@ -42,6 +60,9 @@ struct xfs_scrub_context {
|
|||
struct xfs_trans *tp;
|
||||
struct xfs_inode *ip;
|
||||
bool try_harder;
|
||||
|
||||
/* State tracking for single-AG operations. */
|
||||
struct xfs_scrub_ag sa;
|
||||
};
|
||||
|
||||
/* Metadata scrubbers */
|
||||
|
|
Loading…
Reference in a new issue