fs/xfs/xfs_trans_ail.c

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

File Facts

System
Linux kernel
Corpus path
fs/xfs/xfs_trans_ail.c
Extension
.c
Size
26824 bytes
Lines
981
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

xfs_ail_min_lsn(ailp))) {
		ailp->ail_log_flush = 0;

		XFS_STATS_INC(mp, xs_push_ail_flush);
		xlog_cil_flush(ailp->ail_log);
	}

	spin_lock(&ailp->ail_lock);
	WRITE_ONCE(ailp->ail_target, xfs_ail_calc_push_target(ailp));
	if (ailp->ail_target == NULLCOMMITLSN)
		goto out_done;

	/* we're done if the AIL is empty or our push has reached the end */
	lip = xfs_trans_ail_cursor_first(ailp, &cur, ailp->ail_last_pushed_lsn);
	if (!lip)
		goto out_done_cursor;

	XFS_STATS_INC(mp, xs_push_ail);

	ASSERT(ailp->ail_target != NULLCOMMITLSN);

	lsn = lip->li_lsn;
	while ((XFS_LSN_CMP(lip->li_lsn, ailp->ail_target) <= 0)) {

		if (test_bit(XFS_LI_FLUSHING, &lip->li_flags))
			goto next_item;

		xfsaild_process_logitem(ailp, lip, &stuck, &flushing);
		count++;

		/*
		 * Are there too many items we can't do anything with?
		 *
		 * If we are skipping too many items because we can't flush
		 * them or they are already being flushed, we back off and
		 * given them time to complete whatever operation is being
		 * done. i.e. remove pressure from the AIL while we can't make
		 * progress so traversals don't slow down further inserts and
		 * removals to/from the AIL.
		 *
		 * The value of 100 is an arbitrary magic number based on
		 * observation.
		 */
		if (stuck > 100)
			break;

next_item:
		lip = xfs_trans_ail_cursor_next(ailp, &cur);
		if (lip == NULL)
			break;
		if (lip->li_lsn != lsn && count > 1000)
			break;
		lsn = lip->li_lsn;
	}

out_done_cursor:
	xfs_trans_ail_cursor_done(&cur);
out_done:
	spin_unlock(&ailp->ail_lock);

	if (xfs_buf_delwri_submit_nowait(&ailp->ail_buf_list))
		ailp->ail_log_flush++;

	if (!count || XFS_LSN_CMP(lsn, ailp->ail_target) >= 0) {
		/*
		 * We reached the target or the AIL is empty, so wait a bit
		 * longer for I/O to complete and remove pushed items from the
		 * AIL before we start the next scan from the start of the AIL.
		 */
		tout = 50;
		ailp->ail_last_pushed_lsn = 0;
	} else if (((stuck + flushing) * 100) / count > 90) {
		/*
		 * Either there is a lot of contention on the AIL or we are
		 * stuck due to operations in progress. "Stuck" in this case
		 * is defined as >90% of the items we tried to push were stuck.
		 *
		 * Backoff a bit more to allow some I/O to complete before
		 * restarting from the start of the AIL. This prevents us from
		 * spinning on the same items, and if they are pinned will all
		 * the restart to issue a log force to unpin the stuck items.
		 */
		tout = 20;
		ailp->ail_last_pushed_lsn = 0;
	} else {
		/*
		 * Assume we have more work to do in a short while.
		 */
		tout = 0;
	}

Annotation

Implementation Notes