linux/fs/xfs/scrub/cow_repair.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (C) 2022-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_defer.h"
#include "xfs_btree.h"
#include "xfs_log_format.h"
#include "xfs_trans.h"
#include "xfs_inode.h"
#include "xfs_inode_fork.h"
#include "xfs_alloc.h"
#include "xfs_bmap.h"
#include "xfs_rmap.h"
#include "xfs_refcount.h"
#include "xfs_quota.h"
#include "xfs_ialloc.h"
#include "xfs_ag.h"
#include "xfs_error.h"
#include "xfs_errortag.h"
#include "xfs_icache.h"
#include "xfs_refcount_btree.h"
#include "scrub/xfs_scrub.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/trace.h"
#include "scrub/repair.h"
#include "scrub/bitmap.h"
#include "scrub/off_bitmap.h"
#include "scrub/fsb_bitmap.h"
#include "scrub/reap.h"

/*
 * CoW Fork Mapping Repair
 * =======================
 *
 * Although CoW staging extents are owned by incore CoW inode forks, on disk
 * they are owned by the refcount btree.  The ondisk metadata does not record
 * any ownership information, which limits what we can do to repair the
 * mappings in the CoW fork.  At most, we can replace ifork mappings that lack
 * an entry in the refcount btree or are described by a reverse mapping record
 * whose owner is not OWN_COW.
 *
 * Replacing extents is also tricky -- we can't touch written CoW fork extents
 * since they are undergoing writeback, and delalloc extents do not require
 * repair since they only exist incore.  Hence the most we can do is find the
 * bad parts of unwritten mappings, allocate a replacement set of blocks, and
 * replace the incore mapping.  We use the regular reaping process to unmap
 * or free the discarded blocks, as appropriate.
 */
struct xrep_cow {};

/* CoW staging extent. */
struct xrep_cow_extent {};

/*
 * Mark the part of the file range that corresponds to the given physical
 * space.  Caller must ensure that the physical range is within xc->irec.
 */
STATIC int
xrep_cow_mark_file_range(
	struct xrep_cow		*xc,
	xfs_fsblock_t		startblock,
	xfs_filblks_t		blockcount)
{}

/*
 * Trim @src to fit within the CoW fork mapping being examined, and put the
 * result in @dst.
 */
static inline void
xrep_cow_trim_refcount(
	struct xrep_cow			*xc,
	struct xfs_refcount_irec	*dst,
	const struct xfs_refcount_irec	*src)
{}

/* Mark any shared CoW staging extents. */
STATIC int
xrep_cow_mark_shared_staging(
	struct xfs_btree_cur		*cur,
	const struct xfs_refcount_irec	*rec,
	void				*priv)
{}

/*
 * Mark any portion of the CoW fork file offset range where there is not a CoW
 * staging extent record in the refcountbt, and keep a record of where we did
 * find correct refcountbt records.  Staging records are always cleaned out at
 * mount time, so any two inodes trying to map the same staging area would have
 * already taken the fs down due to refcount btree verifier errors.  Hence this
 * inode should be the sole creator of the staging extent records ondisk.
 */
STATIC int
xrep_cow_mark_missing_staging(
	struct xfs_btree_cur		*cur,
	const struct xfs_refcount_irec	*rec,
	void				*priv)
{}

/*
 * Mark any area that does not correspond to a CoW staging rmap.  These are
 * cross-linked areas that must be avoided.
 */
STATIC int
xrep_cow_mark_missing_staging_rmap(
	struct xfs_btree_cur		*cur,
	const struct xfs_rmap_irec	*rec,
	void				*priv)
{}

/*
 * Find any part of the CoW fork mapping that isn't a single-owner CoW staging
 * extent and mark the corresponding part of the file range in the bitmap.
 */
STATIC int
xrep_cow_find_bad(
	struct xrep_cow			*xc)
{}

/*
 * Allocate a replacement CoW staging extent of up to the given number of
 * blocks, and fill out the mapping.
 */
STATIC int
xrep_cow_alloc(
	struct xfs_scrub	*sc,
	xfs_extlen_t		maxlen,
	struct xrep_cow_extent	*repl)
{}

/*
 * Look up the current CoW fork mapping so that we only allocate enough to
 * replace a single mapping.  If we don't find a mapping that covers the start
 * of the file range, or we find a delalloc or written extent, something is
 * seriously wrong, since we didn't drop the ILOCK.
 */
static inline int
xrep_cow_find_mapping(
	struct xrep_cow		*xc,
	struct xfs_iext_cursor	*icur,
	xfs_fileoff_t		startoff,
	struct xfs_bmbt_irec	*got)
{}

#define REPLACE_LEFT_SIDE
#define REPLACE_RIGHT_SIDE

/*
 * Given a CoW fork mapping @got and a replacement mapping @repl, remap the
 * beginning of @got with the space described by @rep.
 */
static inline void
xrep_cow_replace_mapping(
	struct xfs_inode		*ip,
	struct xfs_iext_cursor		*icur,
	const struct xfs_bmbt_irec	*got,
	const struct xrep_cow_extent	*repl)
{}

/*
 * Replace the unwritten CoW staging extent backing the given file range with a
 * new space extent that isn't as problematic.
 */
STATIC int
xrep_cow_replace_range(
	struct xrep_cow		*xc,
	xfs_fileoff_t		startoff,
	xfs_extlen_t		*blockcount)
{}

/*
 * Replace a bad part of an unwritten CoW staging extent with a fresh delalloc
 * reservation.
 */
STATIC int
xrep_cow_replace(
	uint64_t		startoff,
	uint64_t		blockcount,
	void			*priv)
{}

/*
 * Repair an inode's CoW fork.  The CoW fork is an in-core structure, so
 * there's no btree to rebuid.  Instead, we replace any mappings that are
 * cross-linked or lack ondisk CoW fork records in the refcount btree.
 */
int
xrep_bmap_cow(
	struct xfs_scrub	*sc)
{}