mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-04 09:34:12 +08:00
xfs: check btree block ownership with bnobt/rmapbt when scrubbing btree
When scanning a metadata btree block, cross-reference the block location with the free space btree and the reverse mapping btree to ensure that the rmapbt knows about the block and the bnobt does not. Add a mechanism to defer checks when we happen to be scanning the bnobt/rmapbt itself because it's less efficient to repeatedly clone and destroy the cursor. This patch provides the framework to make btree block owner checks happen; the actual meat will be added in subsequent patches. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Dave Chinner <dchinner@redhat.com>
This commit is contained in:
parent
9a7e269566
commit
858333dcf0
@ -361,6 +361,80 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
struct check_owner {
|
||||
struct list_head list;
|
||||
xfs_daddr_t daddr;
|
||||
int level;
|
||||
};
|
||||
|
||||
/*
|
||||
* Make sure this btree block isn't in the free list and that there's
|
||||
* an rmap record for it.
|
||||
*/
|
||||
STATIC int
|
||||
xfs_scrub_btree_check_block_owner(
|
||||
struct xfs_scrub_btree *bs,
|
||||
int level,
|
||||
xfs_daddr_t daddr)
|
||||
{
|
||||
xfs_agnumber_t agno;
|
||||
bool init_sa;
|
||||
int error = 0;
|
||||
|
||||
if (!bs->cur)
|
||||
return 0;
|
||||
|
||||
agno = xfs_daddr_to_agno(bs->cur->bc_mp, daddr);
|
||||
|
||||
init_sa = bs->cur->bc_flags & XFS_BTREE_LONG_PTRS;
|
||||
if (init_sa) {
|
||||
error = xfs_scrub_ag_init(bs->sc, agno, &bs->sc->sa);
|
||||
if (!xfs_scrub_btree_xref_process_error(bs->sc, bs->cur,
|
||||
level, &error))
|
||||
return error;
|
||||
}
|
||||
|
||||
if (init_sa)
|
||||
xfs_scrub_ag_free(bs->sc, &bs->sc->sa);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Check the owner of a btree block. */
|
||||
STATIC int
|
||||
xfs_scrub_btree_check_owner(
|
||||
struct xfs_scrub_btree *bs,
|
||||
int level,
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
struct xfs_btree_cur *cur = bs->cur;
|
||||
struct check_owner *co;
|
||||
|
||||
if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && bp == NULL)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* We want to cross-reference each btree block with the bnobt
|
||||
* and the rmapbt. We cannot cross-reference the bnobt or
|
||||
* rmapbt while scanning the bnobt or rmapbt, respectively,
|
||||
* because we cannot alter the cursor and we'd prefer not to
|
||||
* duplicate cursors. Therefore, save the buffer daddr for
|
||||
* later scanning.
|
||||
*/
|
||||
if (cur->bc_btnum == XFS_BTNUM_BNO || cur->bc_btnum == XFS_BTNUM_RMAP) {
|
||||
co = kmem_alloc(sizeof(struct check_owner),
|
||||
KM_MAYFAIL | KM_NOFS);
|
||||
if (!co)
|
||||
return -ENOMEM;
|
||||
co->level = level;
|
||||
co->daddr = XFS_BUF_ADDR(bp);
|
||||
list_add_tail(&co->list, &bs->to_check);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return xfs_scrub_btree_check_block_owner(bs, level, XFS_BUF_ADDR(bp));
|
||||
}
|
||||
|
||||
/*
|
||||
* Grab and scrub a btree block given a btree pointer. Returns block
|
||||
* and buffer pointers (if applicable) if they're ok to use.
|
||||
@ -396,6 +470,14 @@ xfs_scrub_btree_get_block(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the block's owner; this function absorbs error codes
|
||||
* for us.
|
||||
*/
|
||||
error = xfs_scrub_btree_check_owner(bs, level, *pbp);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* Check the block's siblings; this function absorbs error codes
|
||||
* for us.
|
||||
@ -467,6 +549,8 @@ xfs_scrub_btree(
|
||||
struct xfs_btree_block *block;
|
||||
int level;
|
||||
struct xfs_buf *bp;
|
||||
struct check_owner *co;
|
||||
struct check_owner *n;
|
||||
int i;
|
||||
int error = 0;
|
||||
|
||||
@ -558,5 +642,14 @@ xfs_scrub_btree(
|
||||
}
|
||||
|
||||
out:
|
||||
/* Process deferred owner checks on btree blocks. */
|
||||
list_for_each_entry_safe(co, n, &bs.to_check, list) {
|
||||
if (!error && bs.cur)
|
||||
error = xfs_scrub_btree_check_block_owner(&bs,
|
||||
co->level, co->daddr);
|
||||
list_del(&co->list);
|
||||
kmem_free(co);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user