fs/xfs/libxfs/xfs_refcount.c

Source file repositories/reference/linux-study-clean/fs/xfs/libxfs/xfs_refcount.c

File Facts

System
Linux kernel
Corpus path
fs/xfs/libxfs/xfs_refcount.c
Extension
.c
Size
59931 bytes
Lines
2245
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 xfs_refcount_recovery {
	struct list_head		rr_list;
	struct xfs_refcount_irec	rr_rrec;
};

/* Stuff an extent on the recovery list. */
STATIC int
xfs_refcount_recover_extent(
	struct xfs_btree_cur		*cur,
	const union xfs_btree_rec	*rec,
	void				*priv)
{
	struct list_head		*debris = priv;
	struct xfs_refcount_recovery	*rr;

	if (XFS_IS_CORRUPT(cur->bc_mp,
			   be32_to_cpu(rec->refc.rc_refcount) != 1)) {
		xfs_btree_mark_sick(cur);
		return -EFSCORRUPTED;
	}

	rr = kmalloc_obj(struct xfs_refcount_recovery,
			 GFP_KERNEL | __GFP_NOFAIL);
	INIT_LIST_HEAD(&rr->rr_list);
	xfs_refcount_btrec_to_irec(rec, &rr->rr_rrec);

	if (xfs_refcount_check_btrec(cur, &rr->rr_rrec) != NULL ||
	    XFS_IS_CORRUPT(cur->bc_mp,
			   rr->rr_rrec.rc_domain != XFS_REFC_DOMAIN_COW)) {
		xfs_btree_mark_sick(cur);
		kfree(rr);
		return -EFSCORRUPTED;
	}

	list_add_tail(&rr->rr_list, debris);
	return 0;
}

/* Find and remove leftover CoW reservations. */
int
xfs_refcount_recover_cow_leftovers(
	struct xfs_group		*xg)
{
	struct xfs_mount		*mp = xg->xg_mount;
	bool				isrt = xg->xg_type == XG_TYPE_RTG;
	struct xfs_trans		*tp;
	struct xfs_btree_cur		*cur;
	struct xfs_buf			*agbp = NULL;
	struct xfs_refcount_recovery	*rr, *n;
	struct list_head		debris;
	union xfs_btree_irec		low = {
		.rc.rc_domain		= XFS_REFC_DOMAIN_COW,
	};
	union xfs_btree_irec		high = {
		.rc.rc_domain		= XFS_REFC_DOMAIN_COW,
		.rc.rc_startblock	= -1U,
	};
	xfs_fsblock_t			fsb;
	int				error;

	/* reflink filesystems must not have groups larger than 2^31-1 blocks */
	BUILD_BUG_ON(XFS_MAX_RGBLOCKS >= XFS_REFC_COWFLAG);
	BUILD_BUG_ON(XFS_MAX_CRC_AG_BLOCKS >= XFS_REFC_COWFLAG);

	if (isrt) {
		if (!xfs_has_rtgroups(mp))
			return 0;
		if (xfs_group_max_blocks(xg) >= XFS_MAX_RGBLOCKS)
			return -EOPNOTSUPP;
	} else {
		if (xfs_group_max_blocks(xg) > XFS_MAX_CRC_AG_BLOCKS)
			return -EOPNOTSUPP;
	}

	INIT_LIST_HEAD(&debris);

	/*
	 * In this first part, we use an empty transaction to gather up
	 * all the leftover CoW extents so that we can subsequently
	 * delete them.  The empty transaction is used to avoid
	 * a buffer lock deadlock if there happens to be a loop in the
	 * refcountbt because we're allowed to re-grab a buffer that is
	 * already attached to our transaction.  When we're done
	 * recording the CoW debris we cancel the (empty) transaction
	 * and everything goes away cleanly.
	 */
	tp = xfs_trans_alloc_empty(mp);

	if (isrt) {
		xfs_rtgroup_lock(to_rtg(xg), XFS_RTGLOCK_REFCOUNT);

Annotation

Implementation Notes