Commit 98e63b91 authored by Chandan Babu R's avatar Chandan Babu R
Browse files

Merge tag 'repair-file-mappings-6.8_2023-12-15' of...

Merge tag 'repair-file-mappings-6.8_2023-12-15' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux

 into xfs-6.8-mergeB

xfs: online repair of file fork mappings

In this series, online repair gains the ability to rebuild data and attr
fork mappings from the reverse mapping information.  It is at this point
where we reintroduce the ability to reap file extents.

Repair of CoW forks is a little different -- on disk, CoW staging
extents are owned by the refcount btree and cannot be mapped back to
individual files.  Hence we can only detect staging extents that don't
quite look right (missing reverse mappings, shared staging extents) and
replace them with fresh allocations.

Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Signed-off-by: default avatarChandan Babu R <chandanbabu@kernel.org>

* tag 'repair-file-mappings-6.8_2023-12-15' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux:
  xfs: repair problems in CoW forks
  xfs: create a ranged query function for refcount btrees
  xfs: refactor repair forcing tests into a repair.c helper
  xfs: repair inode fork block mapping data structures
  xfs: reintroduce reaping of file metadata blocks to xrep_reap_extents
parents 7b63ce86 dbbdbd00
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -183,6 +183,8 @@ ifeq ($(CONFIG_XFS_ONLINE_REPAIR),y)
xfs-y				+= $(addprefix scrub/, \
				   agheader_repair.o \
				   alloc_repair.o \
				   bmap_repair.o \
				   cow_repair.o \
				   ialloc_repair.o \
				   inode_repair.o \
				   newbt.o \
+101 −20
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include "xfs_trans.h"
#include "xfs_alloc.h"
#include "xfs_btree.h"
#include "xfs_btree_staging.h"
#include "xfs_bmap_btree.h"
#include "xfs_bmap.h"
#include "xfs_error.h"
@@ -288,10 +289,7 @@ xfs_bmbt_get_minrecs(
	int			level)
{
	if (level == cur->bc_nlevels - 1) {
		struct xfs_ifork	*ifp;

		ifp = xfs_ifork_ptr(cur->bc_ino.ip,
				    cur->bc_ino.whichfork);
		struct xfs_ifork	*ifp = xfs_btree_ifork_ptr(cur);

		return xfs_bmbt_maxrecs(cur->bc_mp,
					ifp->if_broot_bytes, level == 0) / 2;
@@ -306,10 +304,7 @@ xfs_bmbt_get_maxrecs(
	int			level)
{
	if (level == cur->bc_nlevels - 1) {
		struct xfs_ifork	*ifp;

		ifp = xfs_ifork_ptr(cur->bc_ino.ip,
				    cur->bc_ino.whichfork);
		struct xfs_ifork	*ifp = xfs_btree_ifork_ptr(cur);

		return xfs_bmbt_maxrecs(cur->bc_mp,
					ifp->if_broot_bytes, level == 0);
@@ -543,23 +538,19 @@ static const struct xfs_btree_ops xfs_bmbt_ops = {
	.keys_contiguous	= xfs_bmbt_keys_contiguous,
};

/*
 * Allocate a new bmap btree cursor.
 */
struct xfs_btree_cur *				/* new bmap btree cursor */
xfs_bmbt_init_cursor(
	struct xfs_mount	*mp,		/* file system mount point */
	struct xfs_trans	*tp,		/* transaction pointer */
	struct xfs_inode	*ip,		/* inode owning the btree */
	int			whichfork)	/* data or attr fork */
static struct xfs_btree_cur *
xfs_bmbt_init_common(
	struct xfs_mount	*mp,
	struct xfs_trans	*tp,
	struct xfs_inode	*ip,
	int			whichfork)
{
	struct xfs_ifork	*ifp = xfs_ifork_ptr(ip, whichfork);
	struct xfs_btree_cur	*cur;

	ASSERT(whichfork != XFS_COW_FORK);

	cur = xfs_btree_alloc_cursor(mp, tp, XFS_BTNUM_BMAP,
			mp->m_bm_maxlevels[whichfork], xfs_bmbt_cur_cache);
	cur->bc_nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1;
	cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_bmbt_2);

	cur->bc_ops = &xfs_bmbt_ops;
@@ -567,10 +558,30 @@ xfs_bmbt_init_cursor(
	if (xfs_has_crc(mp))
		cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;

	cur->bc_ino.forksize = xfs_inode_fork_size(ip, whichfork);
	cur->bc_ino.ip = ip;
	cur->bc_ino.allocated = 0;
	cur->bc_ino.flags = 0;

	return cur;
}

/*
 * Allocate a new bmap btree cursor.
 */
struct xfs_btree_cur *
xfs_bmbt_init_cursor(
	struct xfs_mount	*mp,
	struct xfs_trans	*tp,
	struct xfs_inode	*ip,
	int			whichfork)
{
	struct xfs_ifork	*ifp = xfs_ifork_ptr(ip, whichfork);
	struct xfs_btree_cur	*cur;

	cur = xfs_bmbt_init_common(mp, tp, ip, whichfork);

	cur->bc_nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1;
	cur->bc_ino.forksize = xfs_inode_fork_size(ip, whichfork);
	cur->bc_ino.whichfork = whichfork;

	return cur;
@@ -587,6 +598,76 @@ xfs_bmbt_block_maxrecs(
	return blocklen / (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t));
}

/*
 * Allocate a new bmap btree cursor for reloading an inode block mapping data
 * structure.  Note that callers can use the staged cursor to reload extents
 * format inode forks if they rebuild the iext tree and commit the staged
 * cursor immediately.
 */
struct xfs_btree_cur *
xfs_bmbt_stage_cursor(
	struct xfs_mount	*mp,
	struct xfs_inode	*ip,
	struct xbtree_ifakeroot	*ifake)
{
	struct xfs_btree_cur	*cur;
	struct xfs_btree_ops	*ops;

	/* data fork always has larger maxheight */
	cur = xfs_bmbt_init_common(mp, NULL, ip, XFS_DATA_FORK);
	cur->bc_nlevels = ifake->if_levels;
	cur->bc_ino.forksize = ifake->if_fork_size;

	/* Don't let anyone think we're attached to the real fork yet. */
	cur->bc_ino.whichfork = -1;
	xfs_btree_stage_ifakeroot(cur, ifake, &ops);
	ops->update_cursor = NULL;
	return cur;
}

/*
 * Swap in the new inode fork root.  Once we pass this point the newly rebuilt
 * mappings are in place and we have to kill off any old btree blocks.
 */
void
xfs_bmbt_commit_staged_btree(
	struct xfs_btree_cur	*cur,
	struct xfs_trans	*tp,
	int			whichfork)
{
	struct xbtree_ifakeroot	*ifake = cur->bc_ino.ifake;
	struct xfs_ifork	*ifp;
	static const short	brootflag[2] = {XFS_ILOG_DBROOT, XFS_ILOG_ABROOT};
	static const short	extflag[2] = {XFS_ILOG_DEXT, XFS_ILOG_AEXT};
	int			flags = XFS_ILOG_CORE;

	ASSERT(cur->bc_flags & XFS_BTREE_STAGING);
	ASSERT(whichfork != XFS_COW_FORK);

	/*
	 * Free any resources hanging off the real fork, then shallow-copy the
	 * staging fork's contents into the real fork to transfer everything
	 * we just built.
	 */
	ifp = xfs_ifork_ptr(cur->bc_ino.ip, whichfork);
	xfs_idestroy_fork(ifp);
	memcpy(ifp, ifake->if_fork, sizeof(struct xfs_ifork));

	switch (ifp->if_format) {
	case XFS_DINODE_FMT_EXTENTS:
		flags |= extflag[whichfork];
		break;
	case XFS_DINODE_FMT_BTREE:
		flags |= brootflag[whichfork];
		break;
	default:
		ASSERT(0);
		break;
	}
	xfs_trans_log_inode(tp, cur->bc_ino.ip, flags);
	xfs_btree_commit_ifakeroot(cur, tp, whichfork, &xfs_bmbt_ops);
}

/*
 * Calculate number of records in a bmap btree block.
 */
+5 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ struct xfs_btree_block;
struct xfs_mount;
struct xfs_inode;
struct xfs_trans;
struct xbtree_ifakeroot;

/*
 * Btree block header size depends on a superblock flag.
@@ -106,6 +107,10 @@ extern int xfs_bmbt_change_owner(struct xfs_trans *tp, struct xfs_inode *ip,

extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *,
		struct xfs_trans *, struct xfs_inode *, int);
struct xfs_btree_cur *xfs_bmbt_stage_cursor(struct xfs_mount *mp,
		struct xfs_inode *ip, struct xbtree_ifakeroot *ifake);
void xfs_bmbt_commit_staged_btree(struct xfs_btree_cur *cur,
		struct xfs_trans *tp, int whichfork);

extern unsigned long long xfs_bmbt_calc_size(struct xfs_mount *mp,
		unsigned long long len);
+9 −2
Original line number Diff line number Diff line
@@ -405,7 +405,7 @@ xfs_btree_bload_prep_block(
		ASSERT(*bpp == NULL);

		/* Allocate a new incore btree root block. */
		new_size = bbl->iroot_size(cur, nr_this_block, priv);
		new_size = bbl->iroot_size(cur, level, nr_this_block, priv);
		ifp->if_broot = kmem_zalloc(new_size, 0);
		ifp->if_broot_bytes = (int)new_size;

@@ -596,6 +596,13 @@ xfs_btree_bload_level_geometry(
	unsigned int		desired_npb;
	unsigned int		maxnr;

	/*
	 * Compute the absolute maximum number of records that we can store in
	 * the ondisk block or inode root.
	 */
	if (cur->bc_ops->get_dmaxrecs)
		maxnr = cur->bc_ops->get_dmaxrecs(cur, level);
	else
		maxnr = cur->bc_ops->get_maxrecs(cur, level);

	/*
+1 −1
Original line number Diff line number Diff line
@@ -53,7 +53,7 @@ typedef int (*xfs_btree_bload_get_records_fn)(struct xfs_btree_cur *cur,
typedef int (*xfs_btree_bload_claim_block_fn)(struct xfs_btree_cur *cur,
		union xfs_btree_ptr *ptr, void *priv);
typedef size_t (*xfs_btree_bload_iroot_size_fn)(struct xfs_btree_cur *cur,
		unsigned int nr_this_level, void *priv);
		unsigned int level, unsigned int nr_this_level, void *priv);

struct xfs_btree_bload {
	/*
Loading