Skip to content

Commit

Permalink
xfs: scrub refcount btrees
Browse files Browse the repository at this point in the history
Plumb in the pieces necessary to check the refcount btree.  If rmap is
available, check the reference count by performing an interval query
against the rmapbt.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
  • Loading branch information
djwong committed Oct 26, 2017
1 parent c7e693d commit edc09b5
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 1 deletion.
1 change: 1 addition & 0 deletions fs/xfs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ xfs-y += $(addprefix scrub/, \
btree.o \
common.o \
ialloc.o \
refcount.o \
rmap.o \
scrub.o \
)
Expand Down
3 changes: 2 additions & 1 deletion fs/xfs/libxfs/xfs_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -493,9 +493,10 @@ struct xfs_scrub_metadata {
#define XFS_SCRUB_TYPE_INOBT 7 /* inode btree */
#define XFS_SCRUB_TYPE_FINOBT 8 /* free inode btree */
#define XFS_SCRUB_TYPE_RMAPBT 9 /* reverse mapping btree */
#define XFS_SCRUB_TYPE_REFCNTBT 10 /* reference count btree */

/* Number of scrub subcommands. */
#define XFS_SCRUB_TYPE_NR 10
#define XFS_SCRUB_TYPE_NR 11

/* i: Repair this metadata. */
#define XFS_SCRUB_IFLAG_REPAIR (1 << 0)
Expand Down
2 changes: 2 additions & 0 deletions fs/xfs/scrub/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ int xfs_scrub_setup_ag_iallocbt(struct xfs_scrub_context *sc,
struct xfs_inode *ip);
int xfs_scrub_setup_ag_rmapbt(struct xfs_scrub_context *sc,
struct xfs_inode *ip);
int xfs_scrub_setup_ag_refcountbt(struct xfs_scrub_context *sc,
struct xfs_inode *ip);


void xfs_scrub_ag_free(struct xfs_scrub_context *sc, struct xfs_scrub_ag *sa);
Expand Down
99 changes: 99 additions & 0 deletions fs/xfs/scrub/refcount.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright (C) 2017 Oracle. All Rights Reserved.
*
* Author: Darrick J. Wong <darrick.wong@oracle.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_shared.h"
#include "xfs_format.h"
#include "xfs_trans_resv.h"
#include "xfs_mount.h"
#include "xfs_defer.h"
#include "xfs_btree.h"
#include "xfs_bit.h"
#include "xfs_log_format.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_alloc.h"
#include "xfs_rmap.h"
#include "scrub/xfs_scrub.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/btree.h"
#include "scrub/trace.h"

/*
* Set us up to scrub reference count btrees.
*/
int
xfs_scrub_setup_ag_refcountbt(
struct xfs_scrub_context *sc,
struct xfs_inode *ip)
{
return xfs_scrub_setup_ag_btree(sc, ip, false);
}

/* Reference count btree scrubber. */

/* Scrub a refcountbt record. */
STATIC int
xfs_scrub_refcountbt_rec(
struct xfs_scrub_btree *bs,
union xfs_btree_rec *rec)
{
struct xfs_mount *mp = bs->cur->bc_mp;
xfs_agnumber_t agno = bs->cur->bc_private.a.agno;
xfs_agblock_t bno;
xfs_extlen_t len;
xfs_nlink_t refcount;
bool has_cowflag;
int error = 0;

bno = be32_to_cpu(rec->refc.rc_startblock);
len = be32_to_cpu(rec->refc.rc_blockcount);
refcount = be32_to_cpu(rec->refc.rc_refcount);

/* Only CoW records can have refcount == 1. */
has_cowflag = (bno & XFS_REFC_COW_START);
if ((refcount == 1 && !has_cowflag) || (refcount != 1 && has_cowflag))
xfs_scrub_btree_set_corrupt(bs->sc, bs->cur, 0);

/* Check the extent. */
bno &= ~XFS_REFC_COW_START;
if (bno + len <= bno ||
!xfs_verify_agbno(mp, agno, bno) ||
!xfs_verify_agbno(mp, agno, bno + len - 1))
xfs_scrub_btree_set_corrupt(bs->sc, bs->cur, 0);

if (refcount == 0)
xfs_scrub_btree_set_corrupt(bs->sc, bs->cur, 0);

return error;
}

/* Scrub the refcount btree for some AG. */
int
xfs_scrub_refcountbt(
struct xfs_scrub_context *sc)
{
struct xfs_owner_info oinfo;

xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_REFC);
return xfs_scrub_btree(sc, sc->sa.refc_cur, xfs_scrub_refcountbt_rec,
&oinfo, NULL);
}
5 changes: 5 additions & 0 deletions fs/xfs/scrub/scrub.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,11 @@ static const struct xfs_scrub_meta_ops meta_scrub_ops[] = {
.scrub = xfs_scrub_rmapbt,
.has = xfs_sb_version_hasrmapbt,
},
{ /* refcountbt */
.setup = xfs_scrub_setup_ag_refcountbt,
.scrub = xfs_scrub_refcountbt,
.has = xfs_sb_version_hasreflink,
},
};

/* This isn't a stable feature, warn once per day. */
Expand Down
1 change: 1 addition & 0 deletions fs/xfs/scrub/scrub.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,6 @@ int xfs_scrub_cntbt(struct xfs_scrub_context *sc);
int xfs_scrub_inobt(struct xfs_scrub_context *sc);
int xfs_scrub_finobt(struct xfs_scrub_context *sc);
int xfs_scrub_rmapbt(struct xfs_scrub_context *sc);
int xfs_scrub_refcountbt(struct xfs_scrub_context *sc);

#endif /* __XFS_SCRUB_SCRUB_H__ */

0 comments on commit edc09b5

Please sign in to comment.