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

xfs: hoist AGI repair context to a heap object



Save ~460 bytes of stack space by moving all the repair context to a
heap object.  We're going to add even more context data in the next
patch, which is why we really need to do this now.

Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 10d587ec
Loading
Loading
Loading
Loading
+63 −42
Original line number Diff line number Diff line
@@ -796,15 +796,29 @@ enum {
	XREP_AGI_MAX
};

struct xrep_agi {
	struct xfs_scrub		*sc;

	/* AGI buffer, tracked separately */
	struct xfs_buf			*agi_bp;

	/* context for finding btree roots */
	struct xrep_find_ag_btree	fab[XREP_AGI_MAX];

	/* old AGI contents in case we have to revert */
	struct xfs_agi			old_agi;
};

/*
 * Given the inode btree roots described by *fab, find the roots, check them
 * for sanity, and pass the root data back out via *fab.
 */
STATIC int
xrep_agi_find_btrees(
	struct xfs_scrub		*sc,
	struct xrep_find_ag_btree	*fab)
	struct xrep_agi			*ragi)
{
	struct xfs_scrub		*sc = ragi->sc;
	struct xrep_find_ag_btree	*fab = ragi->fab;
	struct xfs_buf			*agf_bp;
	struct xfs_mount		*mp = sc->mp;
	int				error;
@@ -837,10 +851,11 @@ xrep_agi_find_btrees(
 */
STATIC void
xrep_agi_init_header(
	struct xfs_scrub	*sc,
	struct xfs_buf		*agi_bp,
	struct xfs_agi		*old_agi)
	struct xrep_agi		*ragi)
{
	struct xfs_scrub	*sc = ragi->sc;
	struct xfs_buf		*agi_bp = ragi->agi_bp;
	struct xfs_agi		*old_agi = &ragi->old_agi;
	struct xfs_agi		*agi = agi_bp->b_addr;
	struct xfs_perag	*pag = sc->sa.pag;
	struct xfs_mount	*mp = sc->mp;
@@ -868,10 +883,12 @@ xrep_agi_init_header(
/* Set btree root information in an AGI. */
STATIC void
xrep_agi_set_roots(
	struct xfs_scrub		*sc,
	struct xfs_agi			*agi,
	struct xrep_find_ag_btree	*fab)
	struct xrep_agi			*ragi)
{
	struct xfs_scrub		*sc = ragi->sc;
	struct xfs_agi			*agi = ragi->agi_bp->b_addr;
	struct xrep_find_ag_btree	*fab = ragi->fab;

	agi->agi_root = cpu_to_be32(fab[XREP_AGI_INOBT].root);
	agi->agi_level = cpu_to_be32(fab[XREP_AGI_INOBT].height);

@@ -884,9 +901,10 @@ xrep_agi_set_roots(
/* Update the AGI counters. */
STATIC int
xrep_agi_calc_from_btrees(
	struct xfs_scrub	*sc,
	struct xfs_buf		*agi_bp)
	struct xrep_agi		*ragi)
{
	struct xfs_scrub	*sc = ragi->sc;
	struct xfs_buf		*agi_bp = ragi->agi_bp;
	struct xfs_btree_cur	*cur;
	struct xfs_agi		*agi = agi_bp->b_addr;
	struct xfs_mount	*mp = sc->mp;
@@ -931,9 +949,10 @@ xrep_agi_calc_from_btrees(
/* Trigger reinitialization of the in-core data. */
STATIC int
xrep_agi_commit_new(
	struct xfs_scrub	*sc,
	struct xfs_buf		*agi_bp)
	struct xrep_agi		*ragi)
{
	struct xfs_scrub	*sc = ragi->sc;
	struct xfs_buf		*agi_bp = ragi->agi_bp;
	struct xfs_perag	*pag;
	struct xfs_agi		*agi = agi_bp->b_addr;

@@ -958,30 +977,33 @@ int
xrep_agi(
	struct xfs_scrub	*sc)
{
	struct xrep_find_ag_btree	fab[XREP_AGI_MAX] = {
		[XREP_AGI_INOBT] = {
	struct xrep_agi		*ragi;
	struct xfs_mount	*mp = sc->mp;
	int			error;

	/* We require the rmapbt to rebuild anything. */
	if (!xfs_has_rmapbt(mp))
		return -EOPNOTSUPP;

	sc->buf = kzalloc(sizeof(struct xrep_agi), XCHK_GFP_FLAGS);
	if (!sc->buf)
		return -ENOMEM;
	ragi = sc->buf;
	ragi->sc = sc;

	ragi->fab[XREP_AGI_INOBT] = (struct xrep_find_ag_btree){
		.rmap_owner	= XFS_RMAP_OWN_INOBT,
		.buf_ops	= &xfs_inobt_buf_ops,
		.maxlevels	= M_IGEO(sc->mp)->inobt_maxlevels,
		},
		[XREP_AGI_FINOBT] = {
	};
	ragi->fab[XREP_AGI_FINOBT] = (struct xrep_find_ag_btree){
		.rmap_owner	= XFS_RMAP_OWN_INOBT,
		.buf_ops	= &xfs_finobt_buf_ops,
		.maxlevels	= M_IGEO(sc->mp)->inobt_maxlevels,
		},
		[XREP_AGI_END] = {
			.buf_ops = NULL
		},
	};
	struct xfs_agi			old_agi;
	struct xfs_mount		*mp = sc->mp;
	struct xfs_buf			*agi_bp;
	struct xfs_agi			*agi;
	int				error;

	/* We require the rmapbt to rebuild anything. */
	if (!xfs_has_rmapbt(mp))
		return -EOPNOTSUPP;
	ragi->fab[XREP_AGI_END] = (struct xrep_find_ag_btree){
		.buf_ops	= NULL,
	};

	/*
	 * Make sure we have the AGI buffer, as scrub might have decided it
@@ -990,14 +1012,13 @@ xrep_agi(
	error = xfs_trans_read_buf(mp, sc->tp, mp->m_ddev_targp,
			XFS_AG_DADDR(mp, sc->sa.pag->pag_agno,
						XFS_AGI_DADDR(mp)),
			XFS_FSS_TO_BB(mp, 1), 0, &agi_bp, NULL);
			XFS_FSS_TO_BB(mp, 1), 0, &ragi->agi_bp, NULL);
	if (error)
		return error;
	agi_bp->b_ops = &xfs_agi_buf_ops;
	agi = agi_bp->b_addr;
	ragi->agi_bp->b_ops = &xfs_agi_buf_ops;

	/* Find the AGI btree roots. */
	error = xrep_agi_find_btrees(sc, fab);
	error = xrep_agi_find_btrees(ragi);
	if (error)
		return error;

@@ -1006,18 +1027,18 @@ xrep_agi(
		return error;

	/* Start rewriting the header and implant the btrees we found. */
	xrep_agi_init_header(sc, agi_bp, &old_agi);
	xrep_agi_set_roots(sc, agi, fab);
	error = xrep_agi_calc_from_btrees(sc, agi_bp);
	xrep_agi_init_header(ragi);
	xrep_agi_set_roots(ragi);
	error = xrep_agi_calc_from_btrees(ragi);
	if (error)
		goto out_revert;

	/* Reinitialize in-core state. */
	return xrep_agi_commit_new(sc, agi_bp);
	return xrep_agi_commit_new(ragi);

out_revert:
	/* Mark the incore AGI state stale and revert the AGI. */
	clear_bit(XFS_AGSTATE_AGI_INIT, &sc->sa.pag->pag_opstate);
	memcpy(agi, &old_agi, sizeof(old_agi));
	memcpy(ragi->agi_bp->b_addr, &ragi->old_agi, sizeof(struct xfs_agi));
	return error;
}