Commit 32080a9b authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

xfs: repair the rmapbt



Rebuild the reverse mapping btree from all primary metadata.  This first
patch establishes the bare mechanics of finding records and putting
together a new ondisk tree; more complex pieces are needed to make it
work properly.

Link: Documentation/filesystems/xfs-online-fsck-design.rst
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent e4fd1def
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -201,6 +201,7 @@ xfs-y += $(addprefix scrub/, \
				   reap.o \
				   refcount_repair.o \
				   repair.o \
				   rmap_repair.o \
				   )

xfs-$(CONFIG_XFS_RT)		+= $(addprefix scrub/, \
+1 −0
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@ struct xfs_perag {
	uint8_t		pagf_repair_bno_level;
	uint8_t		pagf_repair_cnt_level;
	uint8_t		pagf_repair_refcount_level;
	uint8_t		pagf_repair_rmap_level;
#endif

	spinlock_t	pag_state_lock;
+43 −0
Original line number Diff line number Diff line
@@ -6379,3 +6379,46 @@ xfs_bunmapi_range(
out:
	return error;
}

struct xfs_bmap_query_range {
	xfs_bmap_query_range_fn	fn;
	void			*priv;
};

/* Format btree record and pass to our callback. */
STATIC int
xfs_bmap_query_range_helper(
	struct xfs_btree_cur		*cur,
	const union xfs_btree_rec	*rec,
	void				*priv)
{
	struct xfs_bmap_query_range	*query = priv;
	struct xfs_bmbt_irec		irec;
	xfs_failaddr_t			fa;

	xfs_bmbt_disk_get_all(&rec->bmbt, &irec);
	fa = xfs_bmap_validate_extent(cur->bc_ino.ip, cur->bc_ino.whichfork,
			&irec);
	if (fa) {
		xfs_btree_mark_sick(cur);
		return xfs_bmap_complain_bad_rec(cur->bc_ino.ip,
				cur->bc_ino.whichfork, fa, &irec);
	}

	return query->fn(cur, &irec, query->priv);
}

/* Find all bmaps. */
int
xfs_bmap_query_all(
	struct xfs_btree_cur		*cur,
	xfs_bmap_query_range_fn		fn,
	void				*priv)
{
	struct xfs_bmap_query_range	query = {
		.priv			= priv,
		.fn			= fn,
	};

	return xfs_btree_query_all(cur, xfs_bmap_query_range_helper, &query);
}
+8 −0
Original line number Diff line number Diff line
@@ -280,4 +280,12 @@ extern struct kmem_cache *xfs_bmap_intent_cache;
int __init xfs_bmap_intent_init_cache(void);
void xfs_bmap_intent_destroy_cache(void);

typedef int (*xfs_bmap_query_range_fn)(
	struct xfs_btree_cur	*cur,
	struct xfs_bmbt_irec	*rec,
	void			*priv);

int xfs_bmap_query_all(struct xfs_btree_cur *cur, xfs_bmap_query_range_fn fn,
		void *priv);

#endif	/* __XFS_BMAP_H__ */
+6 −6
Original line number Diff line number Diff line
@@ -215,10 +215,10 @@ xfs_rmap_btrec_to_irec(
/* Simple checks for rmap records. */
xfs_failaddr_t
xfs_rmap_check_irec(
	struct xfs_btree_cur		*cur,
	struct xfs_perag		*pag,
	const struct xfs_rmap_irec	*irec)
{
	struct xfs_mount		*mp = cur->bc_mp;
	struct xfs_mount		*mp = pag->pag_mount;
	bool				is_inode;
	bool				is_unwritten;
	bool				is_bmbt;
@@ -233,7 +233,7 @@ xfs_rmap_check_irec(
			return __this_address;
	} else {
		/* check for valid extent range, including overflow */
		if (!xfs_verify_agbext(cur->bc_ag.pag, irec->rm_startblock,
		if (!xfs_verify_agbext(pag, irec->rm_startblock,
					    irec->rm_blockcount))
			return __this_address;
	}
@@ -307,7 +307,7 @@ xfs_rmap_get_rec(

	fa = xfs_rmap_btrec_to_irec(rec, irec);
	if (!fa)
		fa = xfs_rmap_check_irec(cur, irec);
		fa = xfs_rmap_check_irec(cur->bc_ag.pag, irec);
	if (fa)
		return xfs_rmap_complain_bad_rec(cur, fa, irec);

@@ -2442,7 +2442,7 @@ xfs_rmap_query_range_helper(

	fa = xfs_rmap_btrec_to_irec(rec, &irec);
	if (!fa)
		fa = xfs_rmap_check_irec(cur, &irec);
		fa = xfs_rmap_check_irec(cur->bc_ag.pag, &irec);
	if (fa)
		return xfs_rmap_complain_bad_rec(cur, fa, &irec);

Loading