linux/fs/xfs/scrub/agheader_repair.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (C) 2018-2023 Oracle.  All Rights Reserved.
 * Author: Darrick J. Wong <[email protected]>
 */
#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_btree.h"
#include "xfs_log_format.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_alloc.h"
#include "xfs_alloc_btree.h"
#include "xfs_ialloc.h"
#include "xfs_ialloc_btree.h"
#include "xfs_rmap.h"
#include "xfs_rmap_btree.h"
#include "xfs_refcount_btree.h"
#include "xfs_ag.h"
#include "xfs_inode.h"
#include "xfs_iunlink_item.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/trace.h"
#include "scrub/repair.h"
#include "scrub/bitmap.h"
#include "scrub/agb_bitmap.h"
#include "scrub/agino_bitmap.h"
#include "scrub/reap.h"
#include "scrub/xfile.h"
#include "scrub/xfarray.h"

/* Superblock */

/* Repair the superblock. */
int
xrep_superblock(
	struct xfs_scrub	*sc)
{}

/* AGF */

struct xrep_agf_allocbt {};

/* Record free space shape information. */
STATIC int
xrep_agf_walk_allocbt(
	struct xfs_btree_cur		*cur,
	const struct xfs_alloc_rec_incore *rec,
	void				*priv)
{}

/* Does this AGFL block look sane? */
STATIC int
xrep_agf_check_agfl_block(
	struct xfs_mount	*mp,
	xfs_agblock_t		agbno,
	void			*priv)
{}

/*
 * Offset within the xrep_find_ag_btree array for each btree type.  Avoid the
 * XFS_BTNUM_ names here to avoid creating a sparse array.
 */
enum {};

/* Check a btree root candidate. */
static inline bool
xrep_check_btree_root(
	struct xfs_scrub		*sc,
	struct xrep_find_ag_btree	*fab)
{}

/*
 * Given the btree roots described by *fab, find the roots, check them for
 * sanity, and pass the root data back out via *fab.
 *
 * This is /also/ a chicken and egg problem because we have to use the rmapbt
 * (rooted in the AGF) to find the btrees rooted in the AGF.  We also have no
 * idea if the btrees make any sense.  If we hit obvious corruptions in those
 * btrees we'll bail out.
 */
STATIC int
xrep_agf_find_btrees(
	struct xfs_scrub		*sc,
	struct xfs_buf			*agf_bp,
	struct xrep_find_ag_btree	*fab,
	struct xfs_buf			*agfl_bp)
{}

/*
 * Reinitialize the AGF header, making an in-core copy of the old contents so
 * that we know which in-core state needs to be reinitialized.
 */
STATIC void
xrep_agf_init_header(
	struct xfs_scrub	*sc,
	struct xfs_buf		*agf_bp,
	struct xfs_agf		*old_agf)
{}

/* Set btree root information in an AGF. */
STATIC void
xrep_agf_set_roots(
	struct xfs_scrub		*sc,
	struct xfs_agf			*agf,
	struct xrep_find_ag_btree	*fab)
{}

/* Update all AGF fields which derive from btree contents. */
STATIC int
xrep_agf_calc_from_btrees(
	struct xfs_scrub	*sc,
	struct xfs_buf		*agf_bp)
{}

/* Commit the new AGF and reinitialize the incore state. */
STATIC int
xrep_agf_commit_new(
	struct xfs_scrub	*sc,
	struct xfs_buf		*agf_bp)
{}

/* Repair the AGF. v5 filesystems only. */
int
xrep_agf(
	struct xfs_scrub		*sc)
{}

/* AGFL */

struct xrep_agfl {};

/* Record all OWN_AG (free space btree) information from the rmap data. */
STATIC int
xrep_agfl_walk_rmap(
	struct xfs_btree_cur	*cur,
	const struct xfs_rmap_irec *rec,
	void			*priv)
{}

/* Strike out the blocks that are cross-linked according to the rmapbt. */
STATIC int
xrep_agfl_check_extent(
	uint32_t		agbno,
	uint32_t		len,
	void			*priv)
{}

/*
 * Map out all the non-AGFL OWN_AG space in this AG so that we can deduce
 * which blocks belong to the AGFL.
 *
 * Compute the set of old AGFL blocks by subtracting from the list of OWN_AG
 * blocks the list of blocks owned by all other OWN_AG metadata (bnobt, cntbt,
 * rmapbt).  These are the old AGFL blocks, so return that list and the number
 * of blocks we're actually going to put back on the AGFL.
 */
STATIC int
xrep_agfl_collect_blocks(
	struct xfs_scrub	*sc,
	struct xfs_buf		*agf_bp,
	struct xagb_bitmap	*agfl_extents,
	xfs_agblock_t		*flcount)
{}

/* Update the AGF and reset the in-core state. */
STATIC void
xrep_agfl_update_agf(
	struct xfs_scrub	*sc,
	struct xfs_buf		*agf_bp,
	xfs_agblock_t		flcount)
{}

struct xrep_agfl_fill {};

/* Fill the AGFL with whatever blocks are in this extent. */
static int
xrep_agfl_fill(
	uint32_t		start,
	uint32_t		len,
	void			*priv)
{}

/* Write out a totally new AGFL. */
STATIC int
xrep_agfl_init_header(
	struct xfs_scrub	*sc,
	struct xfs_buf		*agfl_bp,
	struct xagb_bitmap	*agfl_extents,
	xfs_agblock_t		flcount)
{}

/* Repair the AGFL. */
int
xrep_agfl(
	struct xfs_scrub	*sc)
{}

/* AGI */

/*
 * Offset within the xrep_find_ag_btree array for each btree type.  Avoid the
 * XFS_BTNUM_ names here to avoid creating a sparse array.
 */
enum {};

#define XREP_AGI_LOOKUP_BATCH

struct xrep_agi {};

static void
xrep_agi_buf_cleanup(
	void		*buf)
{}

/*
 * 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 xrep_agi			*ragi)
{}

/*
 * Reinitialize the AGI header, making an in-core copy of the old contents so
 * that we know which in-core state needs to be reinitialized.
 */
STATIC void
xrep_agi_init_header(
	struct xrep_agi		*ragi)
{}

/* Set btree root information in an AGI. */
STATIC void
xrep_agi_set_roots(
	struct xrep_agi			*ragi)
{}

/* Update the AGI counters. */
STATIC int
xrep_agi_calc_from_btrees(
	struct xrep_agi		*ragi)
{}

/*
 * Record a forwards unlinked chain pointer from agino -> next_agino in our
 * staging information.
 */
static inline int
xrep_iunlink_store_next(
	struct xrep_agi		*ragi,
	xfs_agino_t		agino,
	xfs_agino_t		next_agino)
{}

/*
 * Record a backwards unlinked chain pointer from prev_ino <- agino in our
 * staging information.
 */
static inline int
xrep_iunlink_store_prev(
	struct xrep_agi		*ragi,
	xfs_agino_t		agino,
	xfs_agino_t		prev_agino)
{}

/*
 * Given an @agino, look up the next inode in the iunlink bucket.  Returns
 * NULLAGINO if we're at the end of the chain, 0 if @agino is not in memory
 * like it should be, or a per-AG inode number.
 */
static inline xfs_agino_t
xrep_iunlink_next(
	struct xfs_scrub	*sc,
	xfs_agino_t		agino)
{}

/*
 * Load the inode @agino into memory, set its i_prev_unlinked, and drop the
 * inode so it can be inactivated.  Returns NULLAGINO if we're at the end of
 * the chain or if we should stop walking the chain due to corruption; or a
 * per-AG inode number.
 */
STATIC xfs_agino_t
xrep_iunlink_reload_next(
	struct xrep_agi		*ragi,
	xfs_agino_t		prev_agino,
	xfs_agino_t		agino)
{}

/*
 * Walk an AGI unlinked bucket's list to load incore any unlinked inodes that
 * still existed at mount time.  This can happen if iunlink processing fails
 * during log recovery.
 */
STATIC int
xrep_iunlink_walk_ondisk_bucket(
	struct xrep_agi		*ragi,
	unsigned int		bucket)
{}

/* Decide if this is an unlinked inode in this AG. */
STATIC bool
xrep_iunlink_igrab(
	struct xfs_perag	*pag,
	struct xfs_inode	*ip)
{}

/*
 * Mark the given inode in the lookup batch in our unlinked inode bitmap, and
 * remember if this inode is the start of the unlinked chain.
 */
STATIC int
xrep_iunlink_visit(
	struct xrep_agi		*ragi,
	unsigned int		batch_idx)
{}

/*
 * Find all incore unlinked inodes so that we can rebuild the unlinked buckets.
 * We hold the AGI so there should not be any modifications to the unlinked
 * list.
 */
STATIC int
xrep_iunlink_mark_incore(
	struct xrep_agi		*ragi)
{}

/* Mark all the unlinked ondisk inodes in this inobt record in iunlink_bmp. */
STATIC int
xrep_iunlink_mark_ondisk_rec(
	struct xfs_btree_cur		*cur,
	const union xfs_btree_rec	*rec,
	void				*priv)
{}

/*
 * Find ondisk inodes that are unlinked and not in cache, and mark them in
 * iunlink_bmp.   We haven't checked the inobt yet, so we don't error out if
 * the btree is corrupt.
 */
STATIC void
xrep_iunlink_mark_ondisk(
	struct xrep_agi		*ragi)
{}

/*
 * Walk an iunlink bucket's inode list.  For each inode that should be on this
 * chain, clear its entry in in iunlink_bmp because it's ok and we don't need
 * to touch it further.
 */
STATIC int
xrep_iunlink_resolve_bucket(
	struct xrep_agi		*ragi,
	unsigned int		bucket)
{}

/* Reinsert this unlinked inode into the head of the staged bucket list. */
STATIC int
xrep_iunlink_add_to_bucket(
	struct xrep_agi		*ragi,
	xfs_agino_t		agino)
{}

/* Reinsert unlinked inodes into the staged iunlink buckets. */
STATIC int
xrep_iunlink_add_lost_inodes(
	uint32_t		start,
	uint32_t		len,
	void			*priv)
{}

/*
 * Figure out the iunlink bucket values and find inodes that need to be
 * reinserted into the list.
 */
STATIC int
xrep_iunlink_rebuild_buckets(
	struct xrep_agi		*ragi)
{}

/* Update i_next_iunlinked for the inode @agino. */
STATIC int
xrep_iunlink_relink_next(
	struct xrep_agi		*ragi,
	xfarray_idx_t		idx,
	xfs_agino_t		next_agino)
{}

/* Update i_prev_iunlinked for the inode @agino. */
STATIC int
xrep_iunlink_relink_prev(
	struct xrep_agi		*ragi,
	xfarray_idx_t		idx,
	xfs_agino_t		prev_agino)
{}

/* Log all the iunlink updates we need to finish regenerating the AGI. */
STATIC int
xrep_iunlink_commit(
	struct xrep_agi		*ragi)
{}

/* Trigger reinitialization of the in-core data. */
STATIC int
xrep_agi_commit_new(
	struct xrep_agi		*ragi)
{}

/* Repair the AGI. */
int
xrep_agi(
	struct xfs_scrub	*sc)
{}