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

xfs: add rtgroup-based realtime scrubbing context management



Create a state tracking structure and helpers to initialize the tracking
structure so that we can check metadata records against the realtime
space management metadata.  Right now this is limited to grabbing the
incore rtgroup object, but we'll eventually add to the tracking
structure the ILOCK state and btree cursors.

Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 65b1231b
Loading
Loading
Loading
Loading
+78 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#include "xfs_quota.h"
#include "xfs_exchmaps.h"
#include "xfs_rtbitmap.h"
#include "xfs_rtgroup.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/trace.h"
@@ -121,6 +122,17 @@ xchk_process_error(
			XFS_SCRUB_OFLAG_CORRUPT, __return_address);
}

bool
xchk_process_rt_error(
	struct xfs_scrub	*sc,
	xfs_rgnumber_t		rgno,
	xfs_rgblock_t		rgbno,
	int			*error)
{
	return __xchk_process_error(sc, rgno, rgbno, error,
			XFS_SCRUB_OFLAG_CORRUPT, __return_address);
}

bool
xchk_xref_process_error(
	struct xfs_scrub	*sc,
@@ -684,6 +696,72 @@ xchk_ag_init(
	return 0;
}

#ifdef CONFIG_XFS_RT
/*
 * For scrubbing a realtime group, grab all the in-core resources we'll need to
 * check the metadata, which means taking the ILOCK of the realtime group's
 * metadata inodes.  Callers must not join these inodes to the transaction with
 * non-zero lockflags or concurrency problems will result.  The @rtglock_flags
 * argument takes XFS_RTGLOCK_* flags.
 */
int
xchk_rtgroup_init(
	struct xfs_scrub	*sc,
	xfs_rgnumber_t		rgno,
	struct xchk_rt		*sr)
{
	ASSERT(sr->rtg == NULL);
	ASSERT(sr->rtlock_flags == 0);

	sr->rtg = xfs_rtgroup_get(sc->mp, rgno);
	if (!sr->rtg)
		return -ENOENT;
	return 0;
}

void
xchk_rtgroup_lock(
	struct xchk_rt		*sr,
	unsigned int		rtglock_flags)
{
	xfs_rtgroup_lock(sr->rtg, rtglock_flags);
	sr->rtlock_flags = rtglock_flags;
}

/*
 * Unlock the realtime group.  This must be done /after/ committing (or
 * cancelling) the scrub transaction.
 */
static void
xchk_rtgroup_unlock(
	struct xchk_rt		*sr)
{
	ASSERT(sr->rtg != NULL);

	if (sr->rtlock_flags) {
		xfs_rtgroup_unlock(sr->rtg, sr->rtlock_flags);
		sr->rtlock_flags = 0;
	}
}

/*
 * Unlock the realtime group and release its resources.  This must be done
 * /after/ committing (or cancelling) the scrub transaction.
 */
void
xchk_rtgroup_free(
	struct xfs_scrub	*sc,
	struct xchk_rt		*sr)
{
	ASSERT(sr->rtg != NULL);

	xchk_rtgroup_unlock(sr);

	xfs_rtgroup_put(sr->rtg);
	sr->rtg = NULL;
}
#endif /* CONFIG_XFS_RT */

/* Per-scrubber setup functions */

void
+30 −0
Original line number Diff line number Diff line
@@ -12,6 +12,8 @@ void xchk_trans_cancel(struct xfs_scrub *sc);

bool xchk_process_error(struct xfs_scrub *sc, xfs_agnumber_t agno,
		xfs_agblock_t bno, int *error);
bool xchk_process_rt_error(struct xfs_scrub *sc, xfs_rgnumber_t rgno,
		xfs_rgblock_t rgbno, int *error);
bool xchk_fblock_process_error(struct xfs_scrub *sc, int whichfork,
		xfs_fileoff_t offset, int *error);

@@ -118,6 +120,34 @@ xchk_ag_init_existing(
	return error == -ENOENT ? -EFSCORRUPTED : error;
}

#ifdef CONFIG_XFS_RT

/* All the locks we need to check an rtgroup. */
#define XCHK_RTGLOCK_ALL	(XFS_RTGLOCK_BITMAP)

int xchk_rtgroup_init(struct xfs_scrub *sc, xfs_rgnumber_t rgno,
		struct xchk_rt *sr);

static inline int
xchk_rtgroup_init_existing(
	struct xfs_scrub	*sc,
	xfs_rgnumber_t		rgno,
	struct xchk_rt		*sr)
{
	int			error = xchk_rtgroup_init(sc, rgno, sr);

	return error == -ENOENT ? -EFSCORRUPTED : error;
}

void xchk_rtgroup_lock(struct xchk_rt *sr, unsigned int rtglock_flags);
void xchk_rtgroup_free(struct xfs_scrub *sc, struct xchk_rt *sr);
#else
# define xchk_rtgroup_init(sc, rgno, sr)		(-EFSCORRUPTED)
# define xchk_rtgroup_init_existing(sc, rgno, sr)	(-EFSCORRUPTED)
# define xchk_rtgroup_lock(sc, lockflags)		do { } while (0)
# define xchk_rtgroup_free(sc, sr)			do { } while (0)
#endif /* CONFIG_XFS_RT */

int xchk_ag_read_headers(struct xfs_scrub *sc, xfs_agnumber_t agno,
		struct xchk_ag *sa);
void xchk_ag_btcur_free(struct xchk_ag *sa);
+24 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include "xfs_rmap.h"
#include "xfs_rmap_btree.h"
#include "xfs_refcount_btree.h"
#include "xfs_rtgroup.h"
#include "xfs_extent_busy.h"
#include "xfs_ag.h"
#include "xfs_ag_resv.h"
@@ -952,6 +953,29 @@ xrep_ag_init(
	return 0;
}

#ifdef CONFIG_XFS_RT
/*
 * Given a reference to a rtgroup structure, lock rtgroup btree inodes and
 * create btree cursors.  Must only be called to repair a regular rt file.
 */
int
xrep_rtgroup_init(
	struct xfs_scrub	*sc,
	struct xfs_rtgroup	*rtg,
	struct xchk_rt		*sr,
	unsigned int		rtglock_flags)
{
	ASSERT(sr->rtg == NULL);

	xfs_rtgroup_lock(rtg, rtglock_flags);
	sr->rtlock_flags = rtglock_flags;

	/* Grab our own passive reference from the caller's ref. */
	sr->rtg = xfs_rtgroup_hold(rtg);
	return 0;
}
#endif /* CONFIG_XFS_RT */

/* Reinitialize the per-AG block reservation for the AG we just fixed. */
int
xrep_reset_perag_resv(
+7 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@

#include "xfs_quota_defs.h"

struct xfs_rtgroup;
struct xchk_stats_run;

static inline int xrep_notsupported(struct xfs_scrub *sc)
@@ -106,6 +107,12 @@ int xrep_setup_inode(struct xfs_scrub *sc, const struct xfs_imap *imap);
void xrep_ag_btcur_init(struct xfs_scrub *sc, struct xchk_ag *sa);
int xrep_ag_init(struct xfs_scrub *sc, struct xfs_perag *pag,
		struct xchk_ag *sa);
#ifdef CONFIG_XFS_RT
int xrep_rtgroup_init(struct xfs_scrub *sc, struct xfs_rtgroup *rtg,
		struct xchk_rt *sr, unsigned int rtglock_flags);
#else
# define xrep_rtgroup_init(sc, rtg, sr, lockflags)	(-ENOSYS)
#endif /* CONFIG_XFS_RT */

/* Metadata revalidators */

+29 −0
Original line number Diff line number Diff line
@@ -225,6 +225,8 @@ xchk_teardown(
			xfs_trans_cancel(sc->tp);
		sc->tp = NULL;
	}
	if (sc->sr.rtg)
		xchk_rtgroup_free(sc, &sc->sr);
	if (sc->ip) {
		if (sc->ilock_flags)
			xchk_iunlock(sc, sc->ilock_flags);
@@ -498,6 +500,33 @@ xchk_validate_inputs(
		break;
	case ST_GENERIC:
		break;
	case ST_RTGROUP:
		if (sm->sm_ino || sm->sm_gen)
			goto out;
		if (xfs_has_rtgroups(mp)) {
			/*
			 * On a rtgroups filesystem, there won't be an rtbitmap
			 * or rtsummary file for group 0 unless there's
			 * actually a realtime volume attached.  However, older
			 * xfs_scrub always calls the rtbitmap/rtsummary
			 * scrubbers with sm_agno==0 so transform the error
			 * code to ENOENT.
			 */
			if (sm->sm_agno >= mp->m_sb.sb_rgcount) {
				if (sm->sm_agno == 0)
					error = -ENOENT;
				goto out;
			}
		} else {
			/*
			 * Prior to rtgroups, the rtbitmap/rtsummary scrubbers
			 * accepted sm_agno==0, so we still accept that for
			 * scrubbing pre-rtgroups filesystems.
			 */
			if (sm->sm_agno != 0)
				goto out;
		}
		break;
	default:
		goto out;
	}
Loading