fs/xfs/xfs_discard.c

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

File Facts

System
Linux kernel
Corpus path
fs/xfs/xfs_discard.c
Extension
.c
Size
23938 bytes
Lines
887
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_trim_cur {
	xfs_agblock_t	start;
	xfs_extlen_t	count;
	xfs_agblock_t	end;
	xfs_extlen_t	minlen;
	bool		by_bno;
};

static int
xfs_trim_gather_extents(
	struct xfs_perag	*pag,
	struct xfs_trim_cur	*tcur,
	struct xfs_busy_extents	*extents)
{
	struct xfs_mount	*mp = pag_mount(pag);
	struct xfs_trans	*tp;
	struct xfs_btree_cur	*cur;
	struct xfs_buf		*agbp;
	int			error;
	int			i;
	int			batch = XFS_DISCARD_MAX_EXAMINE;

	/*
	 * Force out the log.  This means any transactions that might have freed
	 * space before we take the AGF buffer lock are now on disk, and the
	 * volatile disk cache is flushed.
	 */
	xfs_log_force(mp, XFS_LOG_SYNC);

	tp = xfs_trans_alloc_empty(mp);

	error = xfs_alloc_read_agf(pag, tp, 0, &agbp);
	if (error)
		goto out_trans_cancel;

	/*
	 * First time through tcur->count will not have been initialised as
	 * pag->pagf_longest is not guaranteed to be valid before we read
	 * the AGF buffer above.
	 */
	if (!tcur->count)
		tcur->count = pag->pagf_longest;

	if (tcur->by_bno) {
		/* sub-AG discard request always starts at tcur->start */
		cur = xfs_bnobt_init_cursor(mp, tp, agbp, pag);
		error = xfs_alloc_lookup_le(cur, tcur->start, 0, &i);
		if (!error && !i)
			error = xfs_alloc_lookup_ge(cur, tcur->start, 0, &i);
	} else if (tcur->start == 0) {
		/* first time through a by-len starts with max length */
		cur = xfs_cntbt_init_cursor(mp, tp, agbp, pag);
		error = xfs_alloc_lookup_ge(cur, 0, tcur->count, &i);
	} else {
		/* nth time through a by-len starts where we left off */
		cur = xfs_cntbt_init_cursor(mp, tp, agbp, pag);
		error = xfs_alloc_lookup_le(cur, tcur->start, tcur->count, &i);
	}
	if (error)
		goto out_del_cursor;
	if (i == 0) {
		/* nothing of that length left in the AG, we are done */
		tcur->count = 0;
		goto out_del_cursor;
	}

	/*
	 * Loop until we are done with all extents that are large
	 * enough to be worth discarding or we hit batch limits.
	 */
	while (i) {
		xfs_agblock_t	fbno;
		xfs_extlen_t	flen;

		error = xfs_alloc_get_rec(cur, &fbno, &flen, &i);
		if (error)
			break;
		if (XFS_IS_CORRUPT(mp, i != 1)) {
			xfs_btree_mark_sick(cur);
			error = -EFSCORRUPTED;
			break;
		}

		if (--batch <= 0) {
			/*
			 * Update the cursor to point at this extent so we
			 * restart the next batch from this extent.
			 */
			tcur->start = fbno;
			tcur->count = flen;

Annotation

Implementation Notes