162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
462306a36Sopenharmony_ci * Copyright (c) 2008 Dave Chinner
562306a36Sopenharmony_ci * All Rights Reserved.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include "xfs.h"
862306a36Sopenharmony_ci#include "xfs_fs.h"
962306a36Sopenharmony_ci#include "xfs_shared.h"
1062306a36Sopenharmony_ci#include "xfs_format.h"
1162306a36Sopenharmony_ci#include "xfs_log_format.h"
1262306a36Sopenharmony_ci#include "xfs_trans_resv.h"
1362306a36Sopenharmony_ci#include "xfs_mount.h"
1462306a36Sopenharmony_ci#include "xfs_trans.h"
1562306a36Sopenharmony_ci#include "xfs_trans_priv.h"
1662306a36Sopenharmony_ci#include "xfs_trace.h"
1762306a36Sopenharmony_ci#include "xfs_errortag.h"
1862306a36Sopenharmony_ci#include "xfs_error.h"
1962306a36Sopenharmony_ci#include "xfs_log.h"
2062306a36Sopenharmony_ci#include "xfs_log_priv.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#ifdef DEBUG
2362306a36Sopenharmony_ci/*
2462306a36Sopenharmony_ci * Check that the list is sorted as it should be.
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * Called with the ail lock held, but we don't want to assert fail with it
2762306a36Sopenharmony_ci * held otherwise we'll lock everything up and won't be able to debug the
2862306a36Sopenharmony_ci * cause. Hence we sample and check the state under the AIL lock and return if
2962306a36Sopenharmony_ci * everything is fine, otherwise we drop the lock and run the ASSERT checks.
3062306a36Sopenharmony_ci * Asserts may not be fatal, so pick the lock back up and continue onwards.
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_ciSTATIC void
3362306a36Sopenharmony_cixfs_ail_check(
3462306a36Sopenharmony_ci	struct xfs_ail		*ailp,
3562306a36Sopenharmony_ci	struct xfs_log_item	*lip)
3662306a36Sopenharmony_ci	__must_hold(&ailp->ail_lock)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	struct xfs_log_item	*prev_lip;
3962306a36Sopenharmony_ci	struct xfs_log_item	*next_lip;
4062306a36Sopenharmony_ci	xfs_lsn_t		prev_lsn = NULLCOMMITLSN;
4162306a36Sopenharmony_ci	xfs_lsn_t		next_lsn = NULLCOMMITLSN;
4262306a36Sopenharmony_ci	xfs_lsn_t		lsn;
4362306a36Sopenharmony_ci	bool			in_ail;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	if (list_empty(&ailp->ail_head))
4762306a36Sopenharmony_ci		return;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	/*
5062306a36Sopenharmony_ci	 * Sample then check the next and previous entries are valid.
5162306a36Sopenharmony_ci	 */
5262306a36Sopenharmony_ci	in_ail = test_bit(XFS_LI_IN_AIL, &lip->li_flags);
5362306a36Sopenharmony_ci	prev_lip = list_entry(lip->li_ail.prev, struct xfs_log_item, li_ail);
5462306a36Sopenharmony_ci	if (&prev_lip->li_ail != &ailp->ail_head)
5562306a36Sopenharmony_ci		prev_lsn = prev_lip->li_lsn;
5662306a36Sopenharmony_ci	next_lip = list_entry(lip->li_ail.next, struct xfs_log_item, li_ail);
5762306a36Sopenharmony_ci	if (&next_lip->li_ail != &ailp->ail_head)
5862306a36Sopenharmony_ci		next_lsn = next_lip->li_lsn;
5962306a36Sopenharmony_ci	lsn = lip->li_lsn;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	if (in_ail &&
6262306a36Sopenharmony_ci	    (prev_lsn == NULLCOMMITLSN || XFS_LSN_CMP(prev_lsn, lsn) <= 0) &&
6362306a36Sopenharmony_ci	    (next_lsn == NULLCOMMITLSN || XFS_LSN_CMP(next_lsn, lsn) >= 0))
6462306a36Sopenharmony_ci		return;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	spin_unlock(&ailp->ail_lock);
6762306a36Sopenharmony_ci	ASSERT(in_ail);
6862306a36Sopenharmony_ci	ASSERT(prev_lsn == NULLCOMMITLSN || XFS_LSN_CMP(prev_lsn, lsn) <= 0);
6962306a36Sopenharmony_ci	ASSERT(next_lsn == NULLCOMMITLSN || XFS_LSN_CMP(next_lsn, lsn) >= 0);
7062306a36Sopenharmony_ci	spin_lock(&ailp->ail_lock);
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci#else /* !DEBUG */
7362306a36Sopenharmony_ci#define	xfs_ail_check(a,l)
7462306a36Sopenharmony_ci#endif /* DEBUG */
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci/*
7762306a36Sopenharmony_ci * Return a pointer to the last item in the AIL.  If the AIL is empty, then
7862306a36Sopenharmony_ci * return NULL.
7962306a36Sopenharmony_ci */
8062306a36Sopenharmony_cistatic struct xfs_log_item *
8162306a36Sopenharmony_cixfs_ail_max(
8262306a36Sopenharmony_ci	struct xfs_ail  *ailp)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	if (list_empty(&ailp->ail_head))
8562306a36Sopenharmony_ci		return NULL;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	return list_entry(ailp->ail_head.prev, struct xfs_log_item, li_ail);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/*
9162306a36Sopenharmony_ci * Return a pointer to the item which follows the given item in the AIL.  If
9262306a36Sopenharmony_ci * the given item is the last item in the list, then return NULL.
9362306a36Sopenharmony_ci */
9462306a36Sopenharmony_cistatic struct xfs_log_item *
9562306a36Sopenharmony_cixfs_ail_next(
9662306a36Sopenharmony_ci	struct xfs_ail		*ailp,
9762306a36Sopenharmony_ci	struct xfs_log_item	*lip)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	if (lip->li_ail.next == &ailp->ail_head)
10062306a36Sopenharmony_ci		return NULL;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	return list_first_entry(&lip->li_ail, struct xfs_log_item, li_ail);
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/*
10662306a36Sopenharmony_ci * This is called by the log manager code to determine the LSN of the tail of
10762306a36Sopenharmony_ci * the log.  This is exactly the LSN of the first item in the AIL.  If the AIL
10862306a36Sopenharmony_ci * is empty, then this function returns 0.
10962306a36Sopenharmony_ci *
11062306a36Sopenharmony_ci * We need the AIL lock in order to get a coherent read of the lsn of the last
11162306a36Sopenharmony_ci * item in the AIL.
11262306a36Sopenharmony_ci */
11362306a36Sopenharmony_cistatic xfs_lsn_t
11462306a36Sopenharmony_ci__xfs_ail_min_lsn(
11562306a36Sopenharmony_ci	struct xfs_ail		*ailp)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	struct xfs_log_item	*lip = xfs_ail_min(ailp);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	if (lip)
12062306a36Sopenharmony_ci		return lip->li_lsn;
12162306a36Sopenharmony_ci	return 0;
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cixfs_lsn_t
12562306a36Sopenharmony_cixfs_ail_min_lsn(
12662306a36Sopenharmony_ci	struct xfs_ail		*ailp)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	xfs_lsn_t		lsn;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	spin_lock(&ailp->ail_lock);
13162306a36Sopenharmony_ci	lsn = __xfs_ail_min_lsn(ailp);
13262306a36Sopenharmony_ci	spin_unlock(&ailp->ail_lock);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	return lsn;
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/*
13862306a36Sopenharmony_ci * Return the maximum lsn held in the AIL, or zero if the AIL is empty.
13962306a36Sopenharmony_ci */
14062306a36Sopenharmony_cistatic xfs_lsn_t
14162306a36Sopenharmony_cixfs_ail_max_lsn(
14262306a36Sopenharmony_ci	struct xfs_ail		*ailp)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	xfs_lsn_t       	lsn = 0;
14562306a36Sopenharmony_ci	struct xfs_log_item	*lip;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	spin_lock(&ailp->ail_lock);
14862306a36Sopenharmony_ci	lip = xfs_ail_max(ailp);
14962306a36Sopenharmony_ci	if (lip)
15062306a36Sopenharmony_ci		lsn = lip->li_lsn;
15162306a36Sopenharmony_ci	spin_unlock(&ailp->ail_lock);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	return lsn;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/*
15762306a36Sopenharmony_ci * The cursor keeps track of where our current traversal is up to by tracking
15862306a36Sopenharmony_ci * the next item in the list for us. However, for this to be safe, removing an
15962306a36Sopenharmony_ci * object from the AIL needs to invalidate any cursor that points to it. hence
16062306a36Sopenharmony_ci * the traversal cursor needs to be linked to the struct xfs_ail so that
16162306a36Sopenharmony_ci * deletion can search all the active cursors for invalidation.
16262306a36Sopenharmony_ci */
16362306a36Sopenharmony_ciSTATIC void
16462306a36Sopenharmony_cixfs_trans_ail_cursor_init(
16562306a36Sopenharmony_ci	struct xfs_ail		*ailp,
16662306a36Sopenharmony_ci	struct xfs_ail_cursor	*cur)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	cur->item = NULL;
16962306a36Sopenharmony_ci	list_add_tail(&cur->list, &ailp->ail_cursors);
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci/*
17362306a36Sopenharmony_ci * Get the next item in the traversal and advance the cursor.  If the cursor
17462306a36Sopenharmony_ci * was invalidated (indicated by a lip of 1), restart the traversal.
17562306a36Sopenharmony_ci */
17662306a36Sopenharmony_cistruct xfs_log_item *
17762306a36Sopenharmony_cixfs_trans_ail_cursor_next(
17862306a36Sopenharmony_ci	struct xfs_ail		*ailp,
17962306a36Sopenharmony_ci	struct xfs_ail_cursor	*cur)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	struct xfs_log_item	*lip = cur->item;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	if ((uintptr_t)lip & 1)
18462306a36Sopenharmony_ci		lip = xfs_ail_min(ailp);
18562306a36Sopenharmony_ci	if (lip)
18662306a36Sopenharmony_ci		cur->item = xfs_ail_next(ailp, lip);
18762306a36Sopenharmony_ci	return lip;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci/*
19162306a36Sopenharmony_ci * When the traversal is complete, we need to remove the cursor from the list
19262306a36Sopenharmony_ci * of traversing cursors.
19362306a36Sopenharmony_ci */
19462306a36Sopenharmony_civoid
19562306a36Sopenharmony_cixfs_trans_ail_cursor_done(
19662306a36Sopenharmony_ci	struct xfs_ail_cursor	*cur)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	cur->item = NULL;
19962306a36Sopenharmony_ci	list_del_init(&cur->list);
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci/*
20362306a36Sopenharmony_ci * Invalidate any cursor that is pointing to this item. This is called when an
20462306a36Sopenharmony_ci * item is removed from the AIL. Any cursor pointing to this object is now
20562306a36Sopenharmony_ci * invalid and the traversal needs to be terminated so it doesn't reference a
20662306a36Sopenharmony_ci * freed object. We set the low bit of the cursor item pointer so we can
20762306a36Sopenharmony_ci * distinguish between an invalidation and the end of the list when getting the
20862306a36Sopenharmony_ci * next item from the cursor.
20962306a36Sopenharmony_ci */
21062306a36Sopenharmony_ciSTATIC void
21162306a36Sopenharmony_cixfs_trans_ail_cursor_clear(
21262306a36Sopenharmony_ci	struct xfs_ail		*ailp,
21362306a36Sopenharmony_ci	struct xfs_log_item	*lip)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	struct xfs_ail_cursor	*cur;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	list_for_each_entry(cur, &ailp->ail_cursors, list) {
21862306a36Sopenharmony_ci		if (cur->item == lip)
21962306a36Sopenharmony_ci			cur->item = (struct xfs_log_item *)
22062306a36Sopenharmony_ci					((uintptr_t)cur->item | 1);
22162306a36Sopenharmony_ci	}
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci/*
22562306a36Sopenharmony_ci * Find the first item in the AIL with the given @lsn by searching in ascending
22662306a36Sopenharmony_ci * LSN order and initialise the cursor to point to the next item for a
22762306a36Sopenharmony_ci * ascending traversal.  Pass a @lsn of zero to initialise the cursor to the
22862306a36Sopenharmony_ci * first item in the AIL. Returns NULL if the list is empty.
22962306a36Sopenharmony_ci */
23062306a36Sopenharmony_cistruct xfs_log_item *
23162306a36Sopenharmony_cixfs_trans_ail_cursor_first(
23262306a36Sopenharmony_ci	struct xfs_ail		*ailp,
23362306a36Sopenharmony_ci	struct xfs_ail_cursor	*cur,
23462306a36Sopenharmony_ci	xfs_lsn_t		lsn)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	struct xfs_log_item	*lip;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	xfs_trans_ail_cursor_init(ailp, cur);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	if (lsn == 0) {
24162306a36Sopenharmony_ci		lip = xfs_ail_min(ailp);
24262306a36Sopenharmony_ci		goto out;
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	list_for_each_entry(lip, &ailp->ail_head, li_ail) {
24662306a36Sopenharmony_ci		if (XFS_LSN_CMP(lip->li_lsn, lsn) >= 0)
24762306a36Sopenharmony_ci			goto out;
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci	return NULL;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ciout:
25262306a36Sopenharmony_ci	if (lip)
25362306a36Sopenharmony_ci		cur->item = xfs_ail_next(ailp, lip);
25462306a36Sopenharmony_ci	return lip;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic struct xfs_log_item *
25862306a36Sopenharmony_ci__xfs_trans_ail_cursor_last(
25962306a36Sopenharmony_ci	struct xfs_ail		*ailp,
26062306a36Sopenharmony_ci	xfs_lsn_t		lsn)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	struct xfs_log_item	*lip;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	list_for_each_entry_reverse(lip, &ailp->ail_head, li_ail) {
26562306a36Sopenharmony_ci		if (XFS_LSN_CMP(lip->li_lsn, lsn) <= 0)
26662306a36Sopenharmony_ci			return lip;
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci	return NULL;
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci/*
27262306a36Sopenharmony_ci * Find the last item in the AIL with the given @lsn by searching in descending
27362306a36Sopenharmony_ci * LSN order and initialise the cursor to point to that item.  If there is no
27462306a36Sopenharmony_ci * item with the value of @lsn, then it sets the cursor to the last item with an
27562306a36Sopenharmony_ci * LSN lower than @lsn.  Returns NULL if the list is empty.
27662306a36Sopenharmony_ci */
27762306a36Sopenharmony_cistruct xfs_log_item *
27862306a36Sopenharmony_cixfs_trans_ail_cursor_last(
27962306a36Sopenharmony_ci	struct xfs_ail		*ailp,
28062306a36Sopenharmony_ci	struct xfs_ail_cursor	*cur,
28162306a36Sopenharmony_ci	xfs_lsn_t		lsn)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	xfs_trans_ail_cursor_init(ailp, cur);
28462306a36Sopenharmony_ci	cur->item = __xfs_trans_ail_cursor_last(ailp, lsn);
28562306a36Sopenharmony_ci	return cur->item;
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci/*
28962306a36Sopenharmony_ci * Splice the log item list into the AIL at the given LSN. We splice to the
29062306a36Sopenharmony_ci * tail of the given LSN to maintain insert order for push traversals. The
29162306a36Sopenharmony_ci * cursor is optional, allowing repeated updates to the same LSN to avoid
29262306a36Sopenharmony_ci * repeated traversals.  This should not be called with an empty list.
29362306a36Sopenharmony_ci */
29462306a36Sopenharmony_cistatic void
29562306a36Sopenharmony_cixfs_ail_splice(
29662306a36Sopenharmony_ci	struct xfs_ail		*ailp,
29762306a36Sopenharmony_ci	struct xfs_ail_cursor	*cur,
29862306a36Sopenharmony_ci	struct list_head	*list,
29962306a36Sopenharmony_ci	xfs_lsn_t		lsn)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	struct xfs_log_item	*lip;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	ASSERT(!list_empty(list));
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	/*
30662306a36Sopenharmony_ci	 * Use the cursor to determine the insertion point if one is
30762306a36Sopenharmony_ci	 * provided.  If not, or if the one we got is not valid,
30862306a36Sopenharmony_ci	 * find the place in the AIL where the items belong.
30962306a36Sopenharmony_ci	 */
31062306a36Sopenharmony_ci	lip = cur ? cur->item : NULL;
31162306a36Sopenharmony_ci	if (!lip || (uintptr_t)lip & 1)
31262306a36Sopenharmony_ci		lip = __xfs_trans_ail_cursor_last(ailp, lsn);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	/*
31562306a36Sopenharmony_ci	 * If a cursor is provided, we know we're processing the AIL
31662306a36Sopenharmony_ci	 * in lsn order, and future items to be spliced in will
31762306a36Sopenharmony_ci	 * follow the last one being inserted now.  Update the
31862306a36Sopenharmony_ci	 * cursor to point to that last item, now while we have a
31962306a36Sopenharmony_ci	 * reliable pointer to it.
32062306a36Sopenharmony_ci	 */
32162306a36Sopenharmony_ci	if (cur)
32262306a36Sopenharmony_ci		cur->item = list_entry(list->prev, struct xfs_log_item, li_ail);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	/*
32562306a36Sopenharmony_ci	 * Finally perform the splice.  Unless the AIL was empty,
32662306a36Sopenharmony_ci	 * lip points to the item in the AIL _after_ which the new
32762306a36Sopenharmony_ci	 * items should go.  If lip is null the AIL was empty, so
32862306a36Sopenharmony_ci	 * the new items go at the head of the AIL.
32962306a36Sopenharmony_ci	 */
33062306a36Sopenharmony_ci	if (lip)
33162306a36Sopenharmony_ci		list_splice(list, &lip->li_ail);
33262306a36Sopenharmony_ci	else
33362306a36Sopenharmony_ci		list_splice(list, &ailp->ail_head);
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci/*
33762306a36Sopenharmony_ci * Delete the given item from the AIL.  Return a pointer to the item.
33862306a36Sopenharmony_ci */
33962306a36Sopenharmony_cistatic void
34062306a36Sopenharmony_cixfs_ail_delete(
34162306a36Sopenharmony_ci	struct xfs_ail		*ailp,
34262306a36Sopenharmony_ci	struct xfs_log_item	*lip)
34362306a36Sopenharmony_ci{
34462306a36Sopenharmony_ci	xfs_ail_check(ailp, lip);
34562306a36Sopenharmony_ci	list_del(&lip->li_ail);
34662306a36Sopenharmony_ci	xfs_trans_ail_cursor_clear(ailp, lip);
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci/*
35062306a36Sopenharmony_ci * Requeue a failed buffer for writeback.
35162306a36Sopenharmony_ci *
35262306a36Sopenharmony_ci * We clear the log item failed state here as well, but we have to be careful
35362306a36Sopenharmony_ci * about reference counts because the only active reference counts on the buffer
35462306a36Sopenharmony_ci * may be the failed log items. Hence if we clear the log item failed state
35562306a36Sopenharmony_ci * before queuing the buffer for IO we can release all active references to
35662306a36Sopenharmony_ci * the buffer and free it, leading to use after free problems in
35762306a36Sopenharmony_ci * xfs_buf_delwri_queue. It makes no difference to the buffer or log items which
35862306a36Sopenharmony_ci * order we process them in - the buffer is locked, and we own the buffer list
35962306a36Sopenharmony_ci * so nothing on them is going to change while we are performing this action.
36062306a36Sopenharmony_ci *
36162306a36Sopenharmony_ci * Hence we can safely queue the buffer for IO before we clear the failed log
36262306a36Sopenharmony_ci * item state, therefore  always having an active reference to the buffer and
36362306a36Sopenharmony_ci * avoiding the transient zero-reference state that leads to use-after-free.
36462306a36Sopenharmony_ci */
36562306a36Sopenharmony_cistatic inline int
36662306a36Sopenharmony_cixfsaild_resubmit_item(
36762306a36Sopenharmony_ci	struct xfs_log_item	*lip,
36862306a36Sopenharmony_ci	struct list_head	*buffer_list)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	struct xfs_buf		*bp = lip->li_buf;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (!xfs_buf_trylock(bp))
37362306a36Sopenharmony_ci		return XFS_ITEM_LOCKED;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	if (!xfs_buf_delwri_queue(bp, buffer_list)) {
37662306a36Sopenharmony_ci		xfs_buf_unlock(bp);
37762306a36Sopenharmony_ci		return XFS_ITEM_FLUSHING;
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	/* protected by ail_lock */
38162306a36Sopenharmony_ci	list_for_each_entry(lip, &bp->b_li_list, li_bio_list) {
38262306a36Sopenharmony_ci		if (bp->b_flags & _XBF_INODES)
38362306a36Sopenharmony_ci			clear_bit(XFS_LI_FAILED, &lip->li_flags);
38462306a36Sopenharmony_ci		else
38562306a36Sopenharmony_ci			xfs_clear_li_failed(lip);
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	xfs_buf_unlock(bp);
38962306a36Sopenharmony_ci	return XFS_ITEM_SUCCESS;
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic inline uint
39362306a36Sopenharmony_cixfsaild_push_item(
39462306a36Sopenharmony_ci	struct xfs_ail		*ailp,
39562306a36Sopenharmony_ci	struct xfs_log_item	*lip)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	/*
39862306a36Sopenharmony_ci	 * If log item pinning is enabled, skip the push and track the item as
39962306a36Sopenharmony_ci	 * pinned. This can help induce head-behind-tail conditions.
40062306a36Sopenharmony_ci	 */
40162306a36Sopenharmony_ci	if (XFS_TEST_ERROR(false, ailp->ail_log->l_mp, XFS_ERRTAG_LOG_ITEM_PIN))
40262306a36Sopenharmony_ci		return XFS_ITEM_PINNED;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	/*
40562306a36Sopenharmony_ci	 * Consider the item pinned if a push callback is not defined so the
40662306a36Sopenharmony_ci	 * caller will force the log. This should only happen for intent items
40762306a36Sopenharmony_ci	 * as they are unpinned once the associated done item is committed to
40862306a36Sopenharmony_ci	 * the on-disk log.
40962306a36Sopenharmony_ci	 */
41062306a36Sopenharmony_ci	if (!lip->li_ops->iop_push)
41162306a36Sopenharmony_ci		return XFS_ITEM_PINNED;
41262306a36Sopenharmony_ci	if (test_bit(XFS_LI_FAILED, &lip->li_flags))
41362306a36Sopenharmony_ci		return xfsaild_resubmit_item(lip, &ailp->ail_buf_list);
41462306a36Sopenharmony_ci	return lip->li_ops->iop_push(lip, &ailp->ail_buf_list);
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_cistatic long
41862306a36Sopenharmony_cixfsaild_push(
41962306a36Sopenharmony_ci	struct xfs_ail		*ailp)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	struct xfs_mount	*mp = ailp->ail_log->l_mp;
42262306a36Sopenharmony_ci	struct xfs_ail_cursor	cur;
42362306a36Sopenharmony_ci	struct xfs_log_item	*lip;
42462306a36Sopenharmony_ci	xfs_lsn_t		lsn;
42562306a36Sopenharmony_ci	xfs_lsn_t		target = NULLCOMMITLSN;
42662306a36Sopenharmony_ci	long			tout;
42762306a36Sopenharmony_ci	int			stuck = 0;
42862306a36Sopenharmony_ci	int			flushing = 0;
42962306a36Sopenharmony_ci	int			count = 0;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	/*
43262306a36Sopenharmony_ci	 * If we encountered pinned items or did not finish writing out all
43362306a36Sopenharmony_ci	 * buffers the last time we ran, force a background CIL push to get the
43462306a36Sopenharmony_ci	 * items unpinned in the near future. We do not wait on the CIL push as
43562306a36Sopenharmony_ci	 * that could stall us for seconds if there is enough background IO
43662306a36Sopenharmony_ci	 * load. Stalling for that long when the tail of the log is pinned and
43762306a36Sopenharmony_ci	 * needs flushing will hard stop the transaction subsystem when log
43862306a36Sopenharmony_ci	 * space runs out.
43962306a36Sopenharmony_ci	 */
44062306a36Sopenharmony_ci	if (ailp->ail_log_flush && ailp->ail_last_pushed_lsn == 0 &&
44162306a36Sopenharmony_ci	    (!list_empty_careful(&ailp->ail_buf_list) ||
44262306a36Sopenharmony_ci	     xfs_ail_min_lsn(ailp))) {
44362306a36Sopenharmony_ci		ailp->ail_log_flush = 0;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		XFS_STATS_INC(mp, xs_push_ail_flush);
44662306a36Sopenharmony_ci		xlog_cil_flush(ailp->ail_log);
44762306a36Sopenharmony_ci	}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	spin_lock(&ailp->ail_lock);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	/*
45262306a36Sopenharmony_ci	 * If we have a sync push waiter, we always have to push till the AIL is
45362306a36Sopenharmony_ci	 * empty. Update the target to point to the end of the AIL so that
45462306a36Sopenharmony_ci	 * capture updates that occur after the sync push waiter has gone to
45562306a36Sopenharmony_ci	 * sleep.
45662306a36Sopenharmony_ci	 */
45762306a36Sopenharmony_ci	if (waitqueue_active(&ailp->ail_empty)) {
45862306a36Sopenharmony_ci		lip = xfs_ail_max(ailp);
45962306a36Sopenharmony_ci		if (lip)
46062306a36Sopenharmony_ci			target = lip->li_lsn;
46162306a36Sopenharmony_ci	} else {
46262306a36Sopenharmony_ci		/* barrier matches the ail_target update in xfs_ail_push() */
46362306a36Sopenharmony_ci		smp_rmb();
46462306a36Sopenharmony_ci		target = ailp->ail_target;
46562306a36Sopenharmony_ci		ailp->ail_target_prev = target;
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	/* we're done if the AIL is empty or our push has reached the end */
46962306a36Sopenharmony_ci	lip = xfs_trans_ail_cursor_first(ailp, &cur, ailp->ail_last_pushed_lsn);
47062306a36Sopenharmony_ci	if (!lip)
47162306a36Sopenharmony_ci		goto out_done;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	XFS_STATS_INC(mp, xs_push_ail);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	ASSERT(target != NULLCOMMITLSN);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	lsn = lip->li_lsn;
47862306a36Sopenharmony_ci	while ((XFS_LSN_CMP(lip->li_lsn, target) <= 0)) {
47962306a36Sopenharmony_ci		int	lock_result;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci		/*
48262306a36Sopenharmony_ci		 * Note that iop_push may unlock and reacquire the AIL lock.  We
48362306a36Sopenharmony_ci		 * rely on the AIL cursor implementation to be able to deal with
48462306a36Sopenharmony_ci		 * the dropped lock.
48562306a36Sopenharmony_ci		 */
48662306a36Sopenharmony_ci		lock_result = xfsaild_push_item(ailp, lip);
48762306a36Sopenharmony_ci		switch (lock_result) {
48862306a36Sopenharmony_ci		case XFS_ITEM_SUCCESS:
48962306a36Sopenharmony_ci			XFS_STATS_INC(mp, xs_push_ail_success);
49062306a36Sopenharmony_ci			trace_xfs_ail_push(lip);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci			ailp->ail_last_pushed_lsn = lsn;
49362306a36Sopenharmony_ci			break;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci		case XFS_ITEM_FLUSHING:
49662306a36Sopenharmony_ci			/*
49762306a36Sopenharmony_ci			 * The item or its backing buffer is already being
49862306a36Sopenharmony_ci			 * flushed.  The typical reason for that is that an
49962306a36Sopenharmony_ci			 * inode buffer is locked because we already pushed the
50062306a36Sopenharmony_ci			 * updates to it as part of inode clustering.
50162306a36Sopenharmony_ci			 *
50262306a36Sopenharmony_ci			 * We do not want to stop flushing just because lots
50362306a36Sopenharmony_ci			 * of items are already being flushed, but we need to
50462306a36Sopenharmony_ci			 * re-try the flushing relatively soon if most of the
50562306a36Sopenharmony_ci			 * AIL is being flushed.
50662306a36Sopenharmony_ci			 */
50762306a36Sopenharmony_ci			XFS_STATS_INC(mp, xs_push_ail_flushing);
50862306a36Sopenharmony_ci			trace_xfs_ail_flushing(lip);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci			flushing++;
51162306a36Sopenharmony_ci			ailp->ail_last_pushed_lsn = lsn;
51262306a36Sopenharmony_ci			break;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci		case XFS_ITEM_PINNED:
51562306a36Sopenharmony_ci			XFS_STATS_INC(mp, xs_push_ail_pinned);
51662306a36Sopenharmony_ci			trace_xfs_ail_pinned(lip);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci			stuck++;
51962306a36Sopenharmony_ci			ailp->ail_log_flush++;
52062306a36Sopenharmony_ci			break;
52162306a36Sopenharmony_ci		case XFS_ITEM_LOCKED:
52262306a36Sopenharmony_ci			XFS_STATS_INC(mp, xs_push_ail_locked);
52362306a36Sopenharmony_ci			trace_xfs_ail_locked(lip);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci			stuck++;
52662306a36Sopenharmony_ci			break;
52762306a36Sopenharmony_ci		default:
52862306a36Sopenharmony_ci			ASSERT(0);
52962306a36Sopenharmony_ci			break;
53062306a36Sopenharmony_ci		}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci		count++;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci		/*
53562306a36Sopenharmony_ci		 * Are there too many items we can't do anything with?
53662306a36Sopenharmony_ci		 *
53762306a36Sopenharmony_ci		 * If we are skipping too many items because we can't flush
53862306a36Sopenharmony_ci		 * them or they are already being flushed, we back off and
53962306a36Sopenharmony_ci		 * given them time to complete whatever operation is being
54062306a36Sopenharmony_ci		 * done. i.e. remove pressure from the AIL while we can't make
54162306a36Sopenharmony_ci		 * progress so traversals don't slow down further inserts and
54262306a36Sopenharmony_ci		 * removals to/from the AIL.
54362306a36Sopenharmony_ci		 *
54462306a36Sopenharmony_ci		 * The value of 100 is an arbitrary magic number based on
54562306a36Sopenharmony_ci		 * observation.
54662306a36Sopenharmony_ci		 */
54762306a36Sopenharmony_ci		if (stuck > 100)
54862306a36Sopenharmony_ci			break;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci		lip = xfs_trans_ail_cursor_next(ailp, &cur);
55162306a36Sopenharmony_ci		if (lip == NULL)
55262306a36Sopenharmony_ci			break;
55362306a36Sopenharmony_ci		lsn = lip->li_lsn;
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ciout_done:
55762306a36Sopenharmony_ci	xfs_trans_ail_cursor_done(&cur);
55862306a36Sopenharmony_ci	spin_unlock(&ailp->ail_lock);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	if (xfs_buf_delwri_submit_nowait(&ailp->ail_buf_list))
56162306a36Sopenharmony_ci		ailp->ail_log_flush++;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	if (!count || XFS_LSN_CMP(lsn, target) >= 0) {
56462306a36Sopenharmony_ci		/*
56562306a36Sopenharmony_ci		 * We reached the target or the AIL is empty, so wait a bit
56662306a36Sopenharmony_ci		 * longer for I/O to complete and remove pushed items from the
56762306a36Sopenharmony_ci		 * AIL before we start the next scan from the start of the AIL.
56862306a36Sopenharmony_ci		 */
56962306a36Sopenharmony_ci		tout = 50;
57062306a36Sopenharmony_ci		ailp->ail_last_pushed_lsn = 0;
57162306a36Sopenharmony_ci	} else if (((stuck + flushing) * 100) / count > 90) {
57262306a36Sopenharmony_ci		/*
57362306a36Sopenharmony_ci		 * Either there is a lot of contention on the AIL or we are
57462306a36Sopenharmony_ci		 * stuck due to operations in progress. "Stuck" in this case
57562306a36Sopenharmony_ci		 * is defined as >90% of the items we tried to push were stuck.
57662306a36Sopenharmony_ci		 *
57762306a36Sopenharmony_ci		 * Backoff a bit more to allow some I/O to complete before
57862306a36Sopenharmony_ci		 * restarting from the start of the AIL. This prevents us from
57962306a36Sopenharmony_ci		 * spinning on the same items, and if they are pinned will all
58062306a36Sopenharmony_ci		 * the restart to issue a log force to unpin the stuck items.
58162306a36Sopenharmony_ci		 */
58262306a36Sopenharmony_ci		tout = 20;
58362306a36Sopenharmony_ci		ailp->ail_last_pushed_lsn = 0;
58462306a36Sopenharmony_ci	} else {
58562306a36Sopenharmony_ci		/*
58662306a36Sopenharmony_ci		 * Assume we have more work to do in a short while.
58762306a36Sopenharmony_ci		 */
58862306a36Sopenharmony_ci		tout = 10;
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	return tout;
59262306a36Sopenharmony_ci}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_cistatic int
59562306a36Sopenharmony_cixfsaild(
59662306a36Sopenharmony_ci	void		*data)
59762306a36Sopenharmony_ci{
59862306a36Sopenharmony_ci	struct xfs_ail	*ailp = data;
59962306a36Sopenharmony_ci	long		tout = 0;	/* milliseconds */
60062306a36Sopenharmony_ci	unsigned int	noreclaim_flag;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	noreclaim_flag = memalloc_noreclaim_save();
60362306a36Sopenharmony_ci	set_freezable();
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	while (1) {
60662306a36Sopenharmony_ci		if (tout && tout <= 20)
60762306a36Sopenharmony_ci			set_current_state(TASK_KILLABLE|TASK_FREEZABLE);
60862306a36Sopenharmony_ci		else
60962306a36Sopenharmony_ci			set_current_state(TASK_INTERRUPTIBLE|TASK_FREEZABLE);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci		/*
61262306a36Sopenharmony_ci		 * Check kthread_should_stop() after we set the task state to
61362306a36Sopenharmony_ci		 * guarantee that we either see the stop bit and exit or the
61462306a36Sopenharmony_ci		 * task state is reset to runnable such that it's not scheduled
61562306a36Sopenharmony_ci		 * out indefinitely and detects the stop bit at next iteration.
61662306a36Sopenharmony_ci		 * A memory barrier is included in above task state set to
61762306a36Sopenharmony_ci		 * serialize again kthread_stop().
61862306a36Sopenharmony_ci		 */
61962306a36Sopenharmony_ci		if (kthread_should_stop()) {
62062306a36Sopenharmony_ci			__set_current_state(TASK_RUNNING);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci			/*
62362306a36Sopenharmony_ci			 * The caller forces out the AIL before stopping the
62462306a36Sopenharmony_ci			 * thread in the common case, which means the delwri
62562306a36Sopenharmony_ci			 * queue is drained. In the shutdown case, the queue may
62662306a36Sopenharmony_ci			 * still hold relogged buffers that haven't been
62762306a36Sopenharmony_ci			 * submitted because they were pinned since added to the
62862306a36Sopenharmony_ci			 * queue.
62962306a36Sopenharmony_ci			 *
63062306a36Sopenharmony_ci			 * Log I/O error processing stales the underlying buffer
63162306a36Sopenharmony_ci			 * and clears the delwri state, expecting the buf to be
63262306a36Sopenharmony_ci			 * removed on the next submission attempt. That won't
63362306a36Sopenharmony_ci			 * happen if we're shutting down, so this is the last
63462306a36Sopenharmony_ci			 * opportunity to release such buffers from the queue.
63562306a36Sopenharmony_ci			 */
63662306a36Sopenharmony_ci			ASSERT(list_empty(&ailp->ail_buf_list) ||
63762306a36Sopenharmony_ci			       xlog_is_shutdown(ailp->ail_log));
63862306a36Sopenharmony_ci			xfs_buf_delwri_cancel(&ailp->ail_buf_list);
63962306a36Sopenharmony_ci			break;
64062306a36Sopenharmony_ci		}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci		spin_lock(&ailp->ail_lock);
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci		/*
64562306a36Sopenharmony_ci		 * Idle if the AIL is empty and we are not racing with a target
64662306a36Sopenharmony_ci		 * update. We check the AIL after we set the task to a sleep
64762306a36Sopenharmony_ci		 * state to guarantee that we either catch an ail_target update
64862306a36Sopenharmony_ci		 * or that a wake_up resets the state to TASK_RUNNING.
64962306a36Sopenharmony_ci		 * Otherwise, we run the risk of sleeping indefinitely.
65062306a36Sopenharmony_ci		 *
65162306a36Sopenharmony_ci		 * The barrier matches the ail_target update in xfs_ail_push().
65262306a36Sopenharmony_ci		 */
65362306a36Sopenharmony_ci		smp_rmb();
65462306a36Sopenharmony_ci		if (!xfs_ail_min(ailp) &&
65562306a36Sopenharmony_ci		    ailp->ail_target == ailp->ail_target_prev &&
65662306a36Sopenharmony_ci		    list_empty(&ailp->ail_buf_list)) {
65762306a36Sopenharmony_ci			spin_unlock(&ailp->ail_lock);
65862306a36Sopenharmony_ci			schedule();
65962306a36Sopenharmony_ci			tout = 0;
66062306a36Sopenharmony_ci			continue;
66162306a36Sopenharmony_ci		}
66262306a36Sopenharmony_ci		spin_unlock(&ailp->ail_lock);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci		if (tout)
66562306a36Sopenharmony_ci			schedule_timeout(msecs_to_jiffies(tout));
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci		__set_current_state(TASK_RUNNING);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci		try_to_freeze();
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci		tout = xfsaild_push(ailp);
67262306a36Sopenharmony_ci	}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	memalloc_noreclaim_restore(noreclaim_flag);
67562306a36Sopenharmony_ci	return 0;
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci/*
67962306a36Sopenharmony_ci * This routine is called to move the tail of the AIL forward.  It does this by
68062306a36Sopenharmony_ci * trying to flush items in the AIL whose lsns are below the given
68162306a36Sopenharmony_ci * threshold_lsn.
68262306a36Sopenharmony_ci *
68362306a36Sopenharmony_ci * The push is run asynchronously in a workqueue, which means the caller needs
68462306a36Sopenharmony_ci * to handle waiting on the async flush for space to become available.
68562306a36Sopenharmony_ci * We don't want to interrupt any push that is in progress, hence we only queue
68662306a36Sopenharmony_ci * work if we set the pushing bit appropriately.
68762306a36Sopenharmony_ci *
68862306a36Sopenharmony_ci * We do this unlocked - we only need to know whether there is anything in the
68962306a36Sopenharmony_ci * AIL at the time we are called. We don't need to access the contents of
69062306a36Sopenharmony_ci * any of the objects, so the lock is not needed.
69162306a36Sopenharmony_ci */
69262306a36Sopenharmony_civoid
69362306a36Sopenharmony_cixfs_ail_push(
69462306a36Sopenharmony_ci	struct xfs_ail		*ailp,
69562306a36Sopenharmony_ci	xfs_lsn_t		threshold_lsn)
69662306a36Sopenharmony_ci{
69762306a36Sopenharmony_ci	struct xfs_log_item	*lip;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	lip = xfs_ail_min(ailp);
70062306a36Sopenharmony_ci	if (!lip || xlog_is_shutdown(ailp->ail_log) ||
70162306a36Sopenharmony_ci	    XFS_LSN_CMP(threshold_lsn, ailp->ail_target) <= 0)
70262306a36Sopenharmony_ci		return;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	/*
70562306a36Sopenharmony_ci	 * Ensure that the new target is noticed in push code before it clears
70662306a36Sopenharmony_ci	 * the XFS_AIL_PUSHING_BIT.
70762306a36Sopenharmony_ci	 */
70862306a36Sopenharmony_ci	smp_wmb();
70962306a36Sopenharmony_ci	xfs_trans_ail_copy_lsn(ailp, &ailp->ail_target, &threshold_lsn);
71062306a36Sopenharmony_ci	smp_wmb();
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	wake_up_process(ailp->ail_task);
71362306a36Sopenharmony_ci}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci/*
71662306a36Sopenharmony_ci * Push out all items in the AIL immediately
71762306a36Sopenharmony_ci */
71862306a36Sopenharmony_civoid
71962306a36Sopenharmony_cixfs_ail_push_all(
72062306a36Sopenharmony_ci	struct xfs_ail  *ailp)
72162306a36Sopenharmony_ci{
72262306a36Sopenharmony_ci	xfs_lsn_t       threshold_lsn = xfs_ail_max_lsn(ailp);
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	if (threshold_lsn)
72562306a36Sopenharmony_ci		xfs_ail_push(ailp, threshold_lsn);
72662306a36Sopenharmony_ci}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci/*
72962306a36Sopenharmony_ci * Push out all items in the AIL immediately and wait until the AIL is empty.
73062306a36Sopenharmony_ci */
73162306a36Sopenharmony_civoid
73262306a36Sopenharmony_cixfs_ail_push_all_sync(
73362306a36Sopenharmony_ci	struct xfs_ail  *ailp)
73462306a36Sopenharmony_ci{
73562306a36Sopenharmony_ci	DEFINE_WAIT(wait);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	spin_lock(&ailp->ail_lock);
73862306a36Sopenharmony_ci	while (xfs_ail_max(ailp) != NULL) {
73962306a36Sopenharmony_ci		prepare_to_wait(&ailp->ail_empty, &wait, TASK_UNINTERRUPTIBLE);
74062306a36Sopenharmony_ci		wake_up_process(ailp->ail_task);
74162306a36Sopenharmony_ci		spin_unlock(&ailp->ail_lock);
74262306a36Sopenharmony_ci		schedule();
74362306a36Sopenharmony_ci		spin_lock(&ailp->ail_lock);
74462306a36Sopenharmony_ci	}
74562306a36Sopenharmony_ci	spin_unlock(&ailp->ail_lock);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	finish_wait(&ailp->ail_empty, &wait);
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_civoid
75162306a36Sopenharmony_cixfs_ail_update_finish(
75262306a36Sopenharmony_ci	struct xfs_ail		*ailp,
75362306a36Sopenharmony_ci	xfs_lsn_t		old_lsn) __releases(ailp->ail_lock)
75462306a36Sopenharmony_ci{
75562306a36Sopenharmony_ci	struct xlog		*log = ailp->ail_log;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	/* if the tail lsn hasn't changed, don't do updates or wakeups. */
75862306a36Sopenharmony_ci	if (!old_lsn || old_lsn == __xfs_ail_min_lsn(ailp)) {
75962306a36Sopenharmony_ci		spin_unlock(&ailp->ail_lock);
76062306a36Sopenharmony_ci		return;
76162306a36Sopenharmony_ci	}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	if (!xlog_is_shutdown(log))
76462306a36Sopenharmony_ci		xlog_assign_tail_lsn_locked(log->l_mp);
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	if (list_empty(&ailp->ail_head))
76762306a36Sopenharmony_ci		wake_up_all(&ailp->ail_empty);
76862306a36Sopenharmony_ci	spin_unlock(&ailp->ail_lock);
76962306a36Sopenharmony_ci	xfs_log_space_wake(log->l_mp);
77062306a36Sopenharmony_ci}
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci/*
77362306a36Sopenharmony_ci * xfs_trans_ail_update - bulk AIL insertion operation.
77462306a36Sopenharmony_ci *
77562306a36Sopenharmony_ci * @xfs_trans_ail_update takes an array of log items that all need to be
77662306a36Sopenharmony_ci * positioned at the same LSN in the AIL. If an item is not in the AIL, it will
77762306a36Sopenharmony_ci * be added.  Otherwise, it will be repositioned  by removing it and re-adding
77862306a36Sopenharmony_ci * it to the AIL. If we move the first item in the AIL, update the log tail to
77962306a36Sopenharmony_ci * match the new minimum LSN in the AIL.
78062306a36Sopenharmony_ci *
78162306a36Sopenharmony_ci * This function takes the AIL lock once to execute the update operations on
78262306a36Sopenharmony_ci * all the items in the array, and as such should not be called with the AIL
78362306a36Sopenharmony_ci * lock held. As a result, once we have the AIL lock, we need to check each log
78462306a36Sopenharmony_ci * item LSN to confirm it needs to be moved forward in the AIL.
78562306a36Sopenharmony_ci *
78662306a36Sopenharmony_ci * To optimise the insert operation, we delete all the items from the AIL in
78762306a36Sopenharmony_ci * the first pass, moving them into a temporary list, then splice the temporary
78862306a36Sopenharmony_ci * list into the correct position in the AIL. This avoids needing to do an
78962306a36Sopenharmony_ci * insert operation on every item.
79062306a36Sopenharmony_ci *
79162306a36Sopenharmony_ci * This function must be called with the AIL lock held.  The lock is dropped
79262306a36Sopenharmony_ci * before returning.
79362306a36Sopenharmony_ci */
79462306a36Sopenharmony_civoid
79562306a36Sopenharmony_cixfs_trans_ail_update_bulk(
79662306a36Sopenharmony_ci	struct xfs_ail		*ailp,
79762306a36Sopenharmony_ci	struct xfs_ail_cursor	*cur,
79862306a36Sopenharmony_ci	struct xfs_log_item	**log_items,
79962306a36Sopenharmony_ci	int			nr_items,
80062306a36Sopenharmony_ci	xfs_lsn_t		lsn) __releases(ailp->ail_lock)
80162306a36Sopenharmony_ci{
80262306a36Sopenharmony_ci	struct xfs_log_item	*mlip;
80362306a36Sopenharmony_ci	xfs_lsn_t		tail_lsn = 0;
80462306a36Sopenharmony_ci	int			i;
80562306a36Sopenharmony_ci	LIST_HEAD(tmp);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	ASSERT(nr_items > 0);		/* Not required, but true. */
80862306a36Sopenharmony_ci	mlip = xfs_ail_min(ailp);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	for (i = 0; i < nr_items; i++) {
81162306a36Sopenharmony_ci		struct xfs_log_item *lip = log_items[i];
81262306a36Sopenharmony_ci		if (test_and_set_bit(XFS_LI_IN_AIL, &lip->li_flags)) {
81362306a36Sopenharmony_ci			/* check if we really need to move the item */
81462306a36Sopenharmony_ci			if (XFS_LSN_CMP(lsn, lip->li_lsn) <= 0)
81562306a36Sopenharmony_ci				continue;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci			trace_xfs_ail_move(lip, lip->li_lsn, lsn);
81862306a36Sopenharmony_ci			if (mlip == lip && !tail_lsn)
81962306a36Sopenharmony_ci				tail_lsn = lip->li_lsn;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci			xfs_ail_delete(ailp, lip);
82262306a36Sopenharmony_ci		} else {
82362306a36Sopenharmony_ci			trace_xfs_ail_insert(lip, 0, lsn);
82462306a36Sopenharmony_ci		}
82562306a36Sopenharmony_ci		lip->li_lsn = lsn;
82662306a36Sopenharmony_ci		list_add_tail(&lip->li_ail, &tmp);
82762306a36Sopenharmony_ci	}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	if (!list_empty(&tmp))
83062306a36Sopenharmony_ci		xfs_ail_splice(ailp, cur, &tmp, lsn);
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	xfs_ail_update_finish(ailp, tail_lsn);
83362306a36Sopenharmony_ci}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci/* Insert a log item into the AIL. */
83662306a36Sopenharmony_civoid
83762306a36Sopenharmony_cixfs_trans_ail_insert(
83862306a36Sopenharmony_ci	struct xfs_ail		*ailp,
83962306a36Sopenharmony_ci	struct xfs_log_item	*lip,
84062306a36Sopenharmony_ci	xfs_lsn_t		lsn)
84162306a36Sopenharmony_ci{
84262306a36Sopenharmony_ci	spin_lock(&ailp->ail_lock);
84362306a36Sopenharmony_ci	xfs_trans_ail_update_bulk(ailp, NULL, &lip, 1, lsn);
84462306a36Sopenharmony_ci}
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci/*
84762306a36Sopenharmony_ci * Delete one log item from the AIL.
84862306a36Sopenharmony_ci *
84962306a36Sopenharmony_ci * If this item was at the tail of the AIL, return the LSN of the log item so
85062306a36Sopenharmony_ci * that we can use it to check if the LSN of the tail of the log has moved
85162306a36Sopenharmony_ci * when finishing up the AIL delete process in xfs_ail_update_finish().
85262306a36Sopenharmony_ci */
85362306a36Sopenharmony_cixfs_lsn_t
85462306a36Sopenharmony_cixfs_ail_delete_one(
85562306a36Sopenharmony_ci	struct xfs_ail		*ailp,
85662306a36Sopenharmony_ci	struct xfs_log_item	*lip)
85762306a36Sopenharmony_ci{
85862306a36Sopenharmony_ci	struct xfs_log_item	*mlip = xfs_ail_min(ailp);
85962306a36Sopenharmony_ci	xfs_lsn_t		lsn = lip->li_lsn;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	trace_xfs_ail_delete(lip, mlip->li_lsn, lip->li_lsn);
86262306a36Sopenharmony_ci	xfs_ail_delete(ailp, lip);
86362306a36Sopenharmony_ci	clear_bit(XFS_LI_IN_AIL, &lip->li_flags);
86462306a36Sopenharmony_ci	lip->li_lsn = 0;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	if (mlip == lip)
86762306a36Sopenharmony_ci		return lsn;
86862306a36Sopenharmony_ci	return 0;
86962306a36Sopenharmony_ci}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_civoid
87262306a36Sopenharmony_cixfs_trans_ail_delete(
87362306a36Sopenharmony_ci	struct xfs_log_item	*lip,
87462306a36Sopenharmony_ci	int			shutdown_type)
87562306a36Sopenharmony_ci{
87662306a36Sopenharmony_ci	struct xfs_ail		*ailp = lip->li_ailp;
87762306a36Sopenharmony_ci	struct xlog		*log = ailp->ail_log;
87862306a36Sopenharmony_ci	xfs_lsn_t		tail_lsn;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	spin_lock(&ailp->ail_lock);
88162306a36Sopenharmony_ci	if (!test_bit(XFS_LI_IN_AIL, &lip->li_flags)) {
88262306a36Sopenharmony_ci		spin_unlock(&ailp->ail_lock);
88362306a36Sopenharmony_ci		if (shutdown_type && !xlog_is_shutdown(log)) {
88462306a36Sopenharmony_ci			xfs_alert_tag(log->l_mp, XFS_PTAG_AILDELETE,
88562306a36Sopenharmony_ci	"%s: attempting to delete a log item that is not in the AIL",
88662306a36Sopenharmony_ci					__func__);
88762306a36Sopenharmony_ci			xlog_force_shutdown(log, shutdown_type);
88862306a36Sopenharmony_ci		}
88962306a36Sopenharmony_ci		return;
89062306a36Sopenharmony_ci	}
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	/* xfs_ail_update_finish() drops the AIL lock */
89362306a36Sopenharmony_ci	xfs_clear_li_failed(lip);
89462306a36Sopenharmony_ci	tail_lsn = xfs_ail_delete_one(ailp, lip);
89562306a36Sopenharmony_ci	xfs_ail_update_finish(ailp, tail_lsn);
89662306a36Sopenharmony_ci}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ciint
89962306a36Sopenharmony_cixfs_trans_ail_init(
90062306a36Sopenharmony_ci	xfs_mount_t	*mp)
90162306a36Sopenharmony_ci{
90262306a36Sopenharmony_ci	struct xfs_ail	*ailp;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	ailp = kmem_zalloc(sizeof(struct xfs_ail), KM_MAYFAIL);
90562306a36Sopenharmony_ci	if (!ailp)
90662306a36Sopenharmony_ci		return -ENOMEM;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	ailp->ail_log = mp->m_log;
90962306a36Sopenharmony_ci	INIT_LIST_HEAD(&ailp->ail_head);
91062306a36Sopenharmony_ci	INIT_LIST_HEAD(&ailp->ail_cursors);
91162306a36Sopenharmony_ci	spin_lock_init(&ailp->ail_lock);
91262306a36Sopenharmony_ci	INIT_LIST_HEAD(&ailp->ail_buf_list);
91362306a36Sopenharmony_ci	init_waitqueue_head(&ailp->ail_empty);
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	ailp->ail_task = kthread_run(xfsaild, ailp, "xfsaild/%s",
91662306a36Sopenharmony_ci				mp->m_super->s_id);
91762306a36Sopenharmony_ci	if (IS_ERR(ailp->ail_task))
91862306a36Sopenharmony_ci		goto out_free_ailp;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	mp->m_ail = ailp;
92162306a36Sopenharmony_ci	return 0;
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ciout_free_ailp:
92462306a36Sopenharmony_ci	kmem_free(ailp);
92562306a36Sopenharmony_ci	return -ENOMEM;
92662306a36Sopenharmony_ci}
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_civoid
92962306a36Sopenharmony_cixfs_trans_ail_destroy(
93062306a36Sopenharmony_ci	xfs_mount_t	*mp)
93162306a36Sopenharmony_ci{
93262306a36Sopenharmony_ci	struct xfs_ail	*ailp = mp->m_ail;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	kthread_stop(ailp->ail_task);
93562306a36Sopenharmony_ci	kmem_free(ailp);
93662306a36Sopenharmony_ci}
937