fs/xfs/scrub/rtrefcount.c

Source file repositories/reference/linux-study-clean/fs/xfs/scrub/rtrefcount.c

File Facts

System
Linux kernel
Corpus path
fs/xfs/scrub/rtrefcount.c
Extension
.c
Size
18411 bytes
Lines
661
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

struct xchk_rtrefcnt_frag {
	struct list_head	list;
	struct xfs_rmap_irec	rm;
};

struct xchk_rtrefcnt_check {
	struct xfs_scrub	*sc;
	struct list_head	fragments;

	/* refcount extent we're examining */
	xfs_rgblock_t		bno;
	xfs_extlen_t		len;
	xfs_nlink_t		refcount;

	/* number of owners seen */
	xfs_nlink_t		seen;
};

/*
 * Decide if the given rmap is large enough that we can redeem it
 * towards refcount verification now, or if it's a fragment, in
 * which case we'll hang onto it in the hopes that we'll later
 * discover that we've collected exactly the correct number of
 * fragments as the rtrefcountbt says we should have.
 */
STATIC int
xchk_rtrefcountbt_rmap_check(
	struct xfs_btree_cur		*cur,
	const struct xfs_rmap_irec	*rec,
	void				*priv)
{
	struct xchk_rtrefcnt_check	*refchk = priv;
	struct xchk_rtrefcnt_frag	*frag;
	xfs_rgblock_t			rm_last;
	xfs_rgblock_t			rc_last;
	int				error = 0;

	if (xchk_should_terminate(refchk->sc, &error))
		return error;

	rm_last = rec->rm_startblock + rec->rm_blockcount - 1;
	rc_last = refchk->bno + refchk->len - 1;

	/* Confirm that a single-owner refc extent is a CoW stage. */
	if (refchk->refcount == 1 && rec->rm_owner != XFS_RMAP_OWN_COW) {
		xchk_btree_xref_set_corrupt(refchk->sc, cur, 0);
		return 0;
	}

	if (rec->rm_startblock <= refchk->bno && rm_last >= rc_last) {
		/*
		 * The rmap overlaps the refcount record, so we can confirm
		 * one refcount owner seen.
		 */
		refchk->seen++;
	} else {
		/*
		 * This rmap covers only part of the refcount record, so
		 * save the fragment for later processing.  If the rmapbt
		 * is healthy each rmap_irec we see will be in agbno order
		 * so we don't need insertion sort here.
		 */
		frag = kmalloc_obj(struct xchk_rtrefcnt_frag, XCHK_GFP_FLAGS);
		if (!frag)
			return -ENOMEM;
		memcpy(&frag->rm, rec, sizeof(frag->rm));
		list_add_tail(&frag->list, &refchk->fragments);
	}

	return 0;
}

/*
 * Given a bunch of rmap fragments, iterate through them, keeping
 * a running tally of the refcount.  If this ever deviates from
 * what we expect (which is the rtrefcountbt's refcount minus the
 * number of extents that totally covered the rtrefcountbt extent),
 * we have a rtrefcountbt error.
 */
STATIC void
xchk_rtrefcountbt_process_rmap_fragments(
	struct xchk_rtrefcnt_check	*refchk)
{
	struct list_head		worklist;
	struct xchk_rtrefcnt_frag	*frag;
	struct xchk_rtrefcnt_frag	*n;
	xfs_rgblock_t			bno;
	xfs_rgblock_t			rbno;
	xfs_rgblock_t			next_rbno;
	xfs_nlink_t			nr;

Annotation

Implementation Notes