162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2016 Oracle.  All Rights Reserved.
462306a36Sopenharmony_ci * Author: Darrick J. Wong <darrick.wong@oracle.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include "xfs.h"
762306a36Sopenharmony_ci#include "xfs_fs.h"
862306a36Sopenharmony_ci#include "xfs_format.h"
962306a36Sopenharmony_ci#include "xfs_log_format.h"
1062306a36Sopenharmony_ci#include "xfs_trans_resv.h"
1162306a36Sopenharmony_ci#include "xfs_bit.h"
1262306a36Sopenharmony_ci#include "xfs_shared.h"
1362306a36Sopenharmony_ci#include "xfs_mount.h"
1462306a36Sopenharmony_ci#include "xfs_defer.h"
1562306a36Sopenharmony_ci#include "xfs_inode.h"
1662306a36Sopenharmony_ci#include "xfs_trans.h"
1762306a36Sopenharmony_ci#include "xfs_trans_priv.h"
1862306a36Sopenharmony_ci#include "xfs_bmap_item.h"
1962306a36Sopenharmony_ci#include "xfs_log.h"
2062306a36Sopenharmony_ci#include "xfs_bmap.h"
2162306a36Sopenharmony_ci#include "xfs_icache.h"
2262306a36Sopenharmony_ci#include "xfs_bmap_btree.h"
2362306a36Sopenharmony_ci#include "xfs_trans_space.h"
2462306a36Sopenharmony_ci#include "xfs_error.h"
2562306a36Sopenharmony_ci#include "xfs_log_priv.h"
2662306a36Sopenharmony_ci#include "xfs_log_recover.h"
2762306a36Sopenharmony_ci#include "xfs_ag.h"
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistruct kmem_cache	*xfs_bui_cache;
3062306a36Sopenharmony_cistruct kmem_cache	*xfs_bud_cache;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic const struct xfs_item_ops xfs_bui_item_ops;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic inline struct xfs_bui_log_item *BUI_ITEM(struct xfs_log_item *lip)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	return container_of(lip, struct xfs_bui_log_item, bui_item);
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ciSTATIC void
4062306a36Sopenharmony_cixfs_bui_item_free(
4162306a36Sopenharmony_ci	struct xfs_bui_log_item	*buip)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	kmem_free(buip->bui_item.li_lv_shadow);
4462306a36Sopenharmony_ci	kmem_cache_free(xfs_bui_cache, buip);
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/*
4862306a36Sopenharmony_ci * Freeing the BUI requires that we remove it from the AIL if it has already
4962306a36Sopenharmony_ci * been placed there. However, the BUI may not yet have been placed in the AIL
5062306a36Sopenharmony_ci * when called by xfs_bui_release() from BUD processing due to the ordering of
5162306a36Sopenharmony_ci * committed vs unpin operations in bulk insert operations. Hence the reference
5262306a36Sopenharmony_ci * count to ensure only the last caller frees the BUI.
5362306a36Sopenharmony_ci */
5462306a36Sopenharmony_ciSTATIC void
5562306a36Sopenharmony_cixfs_bui_release(
5662306a36Sopenharmony_ci	struct xfs_bui_log_item	*buip)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	ASSERT(atomic_read(&buip->bui_refcount) > 0);
5962306a36Sopenharmony_ci	if (!atomic_dec_and_test(&buip->bui_refcount))
6062306a36Sopenharmony_ci		return;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	xfs_trans_ail_delete(&buip->bui_item, 0);
6362306a36Sopenharmony_ci	xfs_bui_item_free(buip);
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ciSTATIC void
6862306a36Sopenharmony_cixfs_bui_item_size(
6962306a36Sopenharmony_ci	struct xfs_log_item	*lip,
7062306a36Sopenharmony_ci	int			*nvecs,
7162306a36Sopenharmony_ci	int			*nbytes)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	struct xfs_bui_log_item	*buip = BUI_ITEM(lip);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	*nvecs += 1;
7662306a36Sopenharmony_ci	*nbytes += xfs_bui_log_format_sizeof(buip->bui_format.bui_nextents);
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/*
8062306a36Sopenharmony_ci * This is called to fill in the vector of log iovecs for the
8162306a36Sopenharmony_ci * given bui log item. We use only 1 iovec, and we point that
8262306a36Sopenharmony_ci * at the bui_log_format structure embedded in the bui item.
8362306a36Sopenharmony_ci * It is at this point that we assert that all of the extent
8462306a36Sopenharmony_ci * slots in the bui item have been filled.
8562306a36Sopenharmony_ci */
8662306a36Sopenharmony_ciSTATIC void
8762306a36Sopenharmony_cixfs_bui_item_format(
8862306a36Sopenharmony_ci	struct xfs_log_item	*lip,
8962306a36Sopenharmony_ci	struct xfs_log_vec	*lv)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	struct xfs_bui_log_item	*buip = BUI_ITEM(lip);
9262306a36Sopenharmony_ci	struct xfs_log_iovec	*vecp = NULL;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	ASSERT(atomic_read(&buip->bui_next_extent) ==
9562306a36Sopenharmony_ci			buip->bui_format.bui_nextents);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	buip->bui_format.bui_type = XFS_LI_BUI;
9862306a36Sopenharmony_ci	buip->bui_format.bui_size = 1;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_BUI_FORMAT, &buip->bui_format,
10162306a36Sopenharmony_ci			xfs_bui_log_format_sizeof(buip->bui_format.bui_nextents));
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/*
10562306a36Sopenharmony_ci * The unpin operation is the last place an BUI is manipulated in the log. It is
10662306a36Sopenharmony_ci * either inserted in the AIL or aborted in the event of a log I/O error. In
10762306a36Sopenharmony_ci * either case, the BUI transaction has been successfully committed to make it
10862306a36Sopenharmony_ci * this far. Therefore, we expect whoever committed the BUI to either construct
10962306a36Sopenharmony_ci * and commit the BUD or drop the BUD's reference in the event of error. Simply
11062306a36Sopenharmony_ci * drop the log's BUI reference now that the log is done with it.
11162306a36Sopenharmony_ci */
11262306a36Sopenharmony_ciSTATIC void
11362306a36Sopenharmony_cixfs_bui_item_unpin(
11462306a36Sopenharmony_ci	struct xfs_log_item	*lip,
11562306a36Sopenharmony_ci	int			remove)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	struct xfs_bui_log_item	*buip = BUI_ITEM(lip);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	xfs_bui_release(buip);
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/*
12362306a36Sopenharmony_ci * The BUI has been either committed or aborted if the transaction has been
12462306a36Sopenharmony_ci * cancelled. If the transaction was cancelled, an BUD isn't going to be
12562306a36Sopenharmony_ci * constructed and thus we free the BUI here directly.
12662306a36Sopenharmony_ci */
12762306a36Sopenharmony_ciSTATIC void
12862306a36Sopenharmony_cixfs_bui_item_release(
12962306a36Sopenharmony_ci	struct xfs_log_item	*lip)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	xfs_bui_release(BUI_ITEM(lip));
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci/*
13562306a36Sopenharmony_ci * Allocate and initialize an bui item with the given number of extents.
13662306a36Sopenharmony_ci */
13762306a36Sopenharmony_ciSTATIC struct xfs_bui_log_item *
13862306a36Sopenharmony_cixfs_bui_init(
13962306a36Sopenharmony_ci	struct xfs_mount		*mp)
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	struct xfs_bui_log_item		*buip;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	buip = kmem_cache_zalloc(xfs_bui_cache, GFP_KERNEL | __GFP_NOFAIL);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	xfs_log_item_init(mp, &buip->bui_item, XFS_LI_BUI, &xfs_bui_item_ops);
14762306a36Sopenharmony_ci	buip->bui_format.bui_nextents = XFS_BUI_MAX_FAST_EXTENTS;
14862306a36Sopenharmony_ci	buip->bui_format.bui_id = (uintptr_t)(void *)buip;
14962306a36Sopenharmony_ci	atomic_set(&buip->bui_next_extent, 0);
15062306a36Sopenharmony_ci	atomic_set(&buip->bui_refcount, 2);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	return buip;
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic inline struct xfs_bud_log_item *BUD_ITEM(struct xfs_log_item *lip)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	return container_of(lip, struct xfs_bud_log_item, bud_item);
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ciSTATIC void
16162306a36Sopenharmony_cixfs_bud_item_size(
16262306a36Sopenharmony_ci	struct xfs_log_item	*lip,
16362306a36Sopenharmony_ci	int			*nvecs,
16462306a36Sopenharmony_ci	int			*nbytes)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	*nvecs += 1;
16762306a36Sopenharmony_ci	*nbytes += sizeof(struct xfs_bud_log_format);
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci/*
17162306a36Sopenharmony_ci * This is called to fill in the vector of log iovecs for the
17262306a36Sopenharmony_ci * given bud log item. We use only 1 iovec, and we point that
17362306a36Sopenharmony_ci * at the bud_log_format structure embedded in the bud item.
17462306a36Sopenharmony_ci * It is at this point that we assert that all of the extent
17562306a36Sopenharmony_ci * slots in the bud item have been filled.
17662306a36Sopenharmony_ci */
17762306a36Sopenharmony_ciSTATIC void
17862306a36Sopenharmony_cixfs_bud_item_format(
17962306a36Sopenharmony_ci	struct xfs_log_item	*lip,
18062306a36Sopenharmony_ci	struct xfs_log_vec	*lv)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	struct xfs_bud_log_item	*budp = BUD_ITEM(lip);
18362306a36Sopenharmony_ci	struct xfs_log_iovec	*vecp = NULL;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	budp->bud_format.bud_type = XFS_LI_BUD;
18662306a36Sopenharmony_ci	budp->bud_format.bud_size = 1;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_BUD_FORMAT, &budp->bud_format,
18962306a36Sopenharmony_ci			sizeof(struct xfs_bud_log_format));
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci/*
19362306a36Sopenharmony_ci * The BUD is either committed or aborted if the transaction is cancelled. If
19462306a36Sopenharmony_ci * the transaction is cancelled, drop our reference to the BUI and free the
19562306a36Sopenharmony_ci * BUD.
19662306a36Sopenharmony_ci */
19762306a36Sopenharmony_ciSTATIC void
19862306a36Sopenharmony_cixfs_bud_item_release(
19962306a36Sopenharmony_ci	struct xfs_log_item	*lip)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct xfs_bud_log_item	*budp = BUD_ITEM(lip);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	xfs_bui_release(budp->bud_buip);
20462306a36Sopenharmony_ci	kmem_free(budp->bud_item.li_lv_shadow);
20562306a36Sopenharmony_ci	kmem_cache_free(xfs_bud_cache, budp);
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic struct xfs_log_item *
20962306a36Sopenharmony_cixfs_bud_item_intent(
21062306a36Sopenharmony_ci	struct xfs_log_item	*lip)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	return &BUD_ITEM(lip)->bud_buip->bui_item;
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic const struct xfs_item_ops xfs_bud_item_ops = {
21662306a36Sopenharmony_ci	.flags		= XFS_ITEM_RELEASE_WHEN_COMMITTED |
21762306a36Sopenharmony_ci			  XFS_ITEM_INTENT_DONE,
21862306a36Sopenharmony_ci	.iop_size	= xfs_bud_item_size,
21962306a36Sopenharmony_ci	.iop_format	= xfs_bud_item_format,
22062306a36Sopenharmony_ci	.iop_release	= xfs_bud_item_release,
22162306a36Sopenharmony_ci	.iop_intent	= xfs_bud_item_intent,
22262306a36Sopenharmony_ci};
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic struct xfs_bud_log_item *
22562306a36Sopenharmony_cixfs_trans_get_bud(
22662306a36Sopenharmony_ci	struct xfs_trans		*tp,
22762306a36Sopenharmony_ci	struct xfs_bui_log_item		*buip)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	struct xfs_bud_log_item		*budp;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	budp = kmem_cache_zalloc(xfs_bud_cache, GFP_KERNEL | __GFP_NOFAIL);
23262306a36Sopenharmony_ci	xfs_log_item_init(tp->t_mountp, &budp->bud_item, XFS_LI_BUD,
23362306a36Sopenharmony_ci			  &xfs_bud_item_ops);
23462306a36Sopenharmony_ci	budp->bud_buip = buip;
23562306a36Sopenharmony_ci	budp->bud_format.bud_bui_id = buip->bui_format.bui_id;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	xfs_trans_add_item(tp, &budp->bud_item);
23862306a36Sopenharmony_ci	return budp;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci/*
24262306a36Sopenharmony_ci * Finish an bmap update and log it to the BUD. Note that the
24362306a36Sopenharmony_ci * transaction is marked dirty regardless of whether the bmap update
24462306a36Sopenharmony_ci * succeeds or fails to support the BUI/BUD lifecycle rules.
24562306a36Sopenharmony_ci */
24662306a36Sopenharmony_cistatic int
24762306a36Sopenharmony_cixfs_trans_log_finish_bmap_update(
24862306a36Sopenharmony_ci	struct xfs_trans		*tp,
24962306a36Sopenharmony_ci	struct xfs_bud_log_item		*budp,
25062306a36Sopenharmony_ci	struct xfs_bmap_intent		*bi)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	int				error;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	error = xfs_bmap_finish_one(tp, bi);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	/*
25762306a36Sopenharmony_ci	 * Mark the transaction dirty, even on error. This ensures the
25862306a36Sopenharmony_ci	 * transaction is aborted, which:
25962306a36Sopenharmony_ci	 *
26062306a36Sopenharmony_ci	 * 1.) releases the BUI and frees the BUD
26162306a36Sopenharmony_ci	 * 2.) shuts down the filesystem
26262306a36Sopenharmony_ci	 */
26362306a36Sopenharmony_ci	tp->t_flags |= XFS_TRANS_DIRTY | XFS_TRANS_HAS_INTENT_DONE;
26462306a36Sopenharmony_ci	set_bit(XFS_LI_DIRTY, &budp->bud_item.li_flags);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	return error;
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci/* Sort bmap intents by inode. */
27062306a36Sopenharmony_cistatic int
27162306a36Sopenharmony_cixfs_bmap_update_diff_items(
27262306a36Sopenharmony_ci	void				*priv,
27362306a36Sopenharmony_ci	const struct list_head		*a,
27462306a36Sopenharmony_ci	const struct list_head		*b)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	struct xfs_bmap_intent		*ba;
27762306a36Sopenharmony_ci	struct xfs_bmap_intent		*bb;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	ba = container_of(a, struct xfs_bmap_intent, bi_list);
28062306a36Sopenharmony_ci	bb = container_of(b, struct xfs_bmap_intent, bi_list);
28162306a36Sopenharmony_ci	return ba->bi_owner->i_ino - bb->bi_owner->i_ino;
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci/* Set the map extent flags for this mapping. */
28562306a36Sopenharmony_cistatic void
28662306a36Sopenharmony_cixfs_trans_set_bmap_flags(
28762306a36Sopenharmony_ci	struct xfs_map_extent		*map,
28862306a36Sopenharmony_ci	enum xfs_bmap_intent_type	type,
28962306a36Sopenharmony_ci	int				whichfork,
29062306a36Sopenharmony_ci	xfs_exntst_t			state)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	map->me_flags = 0;
29362306a36Sopenharmony_ci	switch (type) {
29462306a36Sopenharmony_ci	case XFS_BMAP_MAP:
29562306a36Sopenharmony_ci	case XFS_BMAP_UNMAP:
29662306a36Sopenharmony_ci		map->me_flags = type;
29762306a36Sopenharmony_ci		break;
29862306a36Sopenharmony_ci	default:
29962306a36Sopenharmony_ci		ASSERT(0);
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci	if (state == XFS_EXT_UNWRITTEN)
30262306a36Sopenharmony_ci		map->me_flags |= XFS_BMAP_EXTENT_UNWRITTEN;
30362306a36Sopenharmony_ci	if (whichfork == XFS_ATTR_FORK)
30462306a36Sopenharmony_ci		map->me_flags |= XFS_BMAP_EXTENT_ATTR_FORK;
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci/* Log bmap updates in the intent item. */
30862306a36Sopenharmony_ciSTATIC void
30962306a36Sopenharmony_cixfs_bmap_update_log_item(
31062306a36Sopenharmony_ci	struct xfs_trans		*tp,
31162306a36Sopenharmony_ci	struct xfs_bui_log_item		*buip,
31262306a36Sopenharmony_ci	struct xfs_bmap_intent		*bi)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	uint				next_extent;
31562306a36Sopenharmony_ci	struct xfs_map_extent		*map;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	tp->t_flags |= XFS_TRANS_DIRTY;
31862306a36Sopenharmony_ci	set_bit(XFS_LI_DIRTY, &buip->bui_item.li_flags);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	/*
32162306a36Sopenharmony_ci	 * atomic_inc_return gives us the value after the increment;
32262306a36Sopenharmony_ci	 * we want to use it as an array index so we need to subtract 1 from
32362306a36Sopenharmony_ci	 * it.
32462306a36Sopenharmony_ci	 */
32562306a36Sopenharmony_ci	next_extent = atomic_inc_return(&buip->bui_next_extent) - 1;
32662306a36Sopenharmony_ci	ASSERT(next_extent < buip->bui_format.bui_nextents);
32762306a36Sopenharmony_ci	map = &buip->bui_format.bui_extents[next_extent];
32862306a36Sopenharmony_ci	map->me_owner = bi->bi_owner->i_ino;
32962306a36Sopenharmony_ci	map->me_startblock = bi->bi_bmap.br_startblock;
33062306a36Sopenharmony_ci	map->me_startoff = bi->bi_bmap.br_startoff;
33162306a36Sopenharmony_ci	map->me_len = bi->bi_bmap.br_blockcount;
33262306a36Sopenharmony_ci	xfs_trans_set_bmap_flags(map, bi->bi_type, bi->bi_whichfork,
33362306a36Sopenharmony_ci			bi->bi_bmap.br_state);
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic struct xfs_log_item *
33762306a36Sopenharmony_cixfs_bmap_update_create_intent(
33862306a36Sopenharmony_ci	struct xfs_trans		*tp,
33962306a36Sopenharmony_ci	struct list_head		*items,
34062306a36Sopenharmony_ci	unsigned int			count,
34162306a36Sopenharmony_ci	bool				sort)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	struct xfs_mount		*mp = tp->t_mountp;
34462306a36Sopenharmony_ci	struct xfs_bui_log_item		*buip = xfs_bui_init(mp);
34562306a36Sopenharmony_ci	struct xfs_bmap_intent		*bi;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	ASSERT(count == XFS_BUI_MAX_FAST_EXTENTS);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	xfs_trans_add_item(tp, &buip->bui_item);
35062306a36Sopenharmony_ci	if (sort)
35162306a36Sopenharmony_ci		list_sort(mp, items, xfs_bmap_update_diff_items);
35262306a36Sopenharmony_ci	list_for_each_entry(bi, items, bi_list)
35362306a36Sopenharmony_ci		xfs_bmap_update_log_item(tp, buip, bi);
35462306a36Sopenharmony_ci	return &buip->bui_item;
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci/* Get an BUD so we can process all the deferred rmap updates. */
35862306a36Sopenharmony_cistatic struct xfs_log_item *
35962306a36Sopenharmony_cixfs_bmap_update_create_done(
36062306a36Sopenharmony_ci	struct xfs_trans		*tp,
36162306a36Sopenharmony_ci	struct xfs_log_item		*intent,
36262306a36Sopenharmony_ci	unsigned int			count)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	return &xfs_trans_get_bud(tp, BUI_ITEM(intent))->bud_item;
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci/* Take a passive ref to the AG containing the space we're mapping. */
36862306a36Sopenharmony_civoid
36962306a36Sopenharmony_cixfs_bmap_update_get_group(
37062306a36Sopenharmony_ci	struct xfs_mount	*mp,
37162306a36Sopenharmony_ci	struct xfs_bmap_intent	*bi)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	xfs_agnumber_t		agno;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	agno = XFS_FSB_TO_AGNO(mp, bi->bi_bmap.br_startblock);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	/*
37862306a36Sopenharmony_ci	 * Bump the intent count on behalf of the deferred rmap and refcount
37962306a36Sopenharmony_ci	 * intent items that that we can queue when we finish this bmap work.
38062306a36Sopenharmony_ci	 * This new intent item will bump the intent count before the bmap
38162306a36Sopenharmony_ci	 * intent drops the intent count, ensuring that the intent count
38262306a36Sopenharmony_ci	 * remains nonzero across the transaction roll.
38362306a36Sopenharmony_ci	 */
38462306a36Sopenharmony_ci	bi->bi_pag = xfs_perag_intent_get(mp, agno);
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci/* Release a passive AG ref after finishing mapping work. */
38862306a36Sopenharmony_cistatic inline void
38962306a36Sopenharmony_cixfs_bmap_update_put_group(
39062306a36Sopenharmony_ci	struct xfs_bmap_intent	*bi)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	xfs_perag_intent_put(bi->bi_pag);
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci/* Process a deferred rmap update. */
39662306a36Sopenharmony_ciSTATIC int
39762306a36Sopenharmony_cixfs_bmap_update_finish_item(
39862306a36Sopenharmony_ci	struct xfs_trans		*tp,
39962306a36Sopenharmony_ci	struct xfs_log_item		*done,
40062306a36Sopenharmony_ci	struct list_head		*item,
40162306a36Sopenharmony_ci	struct xfs_btree_cur		**state)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	struct xfs_bmap_intent		*bi;
40462306a36Sopenharmony_ci	int				error;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	bi = container_of(item, struct xfs_bmap_intent, bi_list);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	error = xfs_trans_log_finish_bmap_update(tp, BUD_ITEM(done), bi);
40962306a36Sopenharmony_ci	if (!error && bi->bi_bmap.br_blockcount > 0) {
41062306a36Sopenharmony_ci		ASSERT(bi->bi_type == XFS_BMAP_UNMAP);
41162306a36Sopenharmony_ci		return -EAGAIN;
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	xfs_bmap_update_put_group(bi);
41562306a36Sopenharmony_ci	kmem_cache_free(xfs_bmap_intent_cache, bi);
41662306a36Sopenharmony_ci	return error;
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci/* Abort all pending BUIs. */
42062306a36Sopenharmony_ciSTATIC void
42162306a36Sopenharmony_cixfs_bmap_update_abort_intent(
42262306a36Sopenharmony_ci	struct xfs_log_item		*intent)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	xfs_bui_release(BUI_ITEM(intent));
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci/* Cancel a deferred bmap update. */
42862306a36Sopenharmony_ciSTATIC void
42962306a36Sopenharmony_cixfs_bmap_update_cancel_item(
43062306a36Sopenharmony_ci	struct list_head		*item)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	struct xfs_bmap_intent		*bi;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	bi = container_of(item, struct xfs_bmap_intent, bi_list);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	xfs_bmap_update_put_group(bi);
43762306a36Sopenharmony_ci	kmem_cache_free(xfs_bmap_intent_cache, bi);
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ciconst struct xfs_defer_op_type xfs_bmap_update_defer_type = {
44162306a36Sopenharmony_ci	.max_items	= XFS_BUI_MAX_FAST_EXTENTS,
44262306a36Sopenharmony_ci	.create_intent	= xfs_bmap_update_create_intent,
44362306a36Sopenharmony_ci	.abort_intent	= xfs_bmap_update_abort_intent,
44462306a36Sopenharmony_ci	.create_done	= xfs_bmap_update_create_done,
44562306a36Sopenharmony_ci	.finish_item	= xfs_bmap_update_finish_item,
44662306a36Sopenharmony_ci	.cancel_item	= xfs_bmap_update_cancel_item,
44762306a36Sopenharmony_ci};
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci/* Is this recovered BUI ok? */
45062306a36Sopenharmony_cistatic inline bool
45162306a36Sopenharmony_cixfs_bui_validate(
45262306a36Sopenharmony_ci	struct xfs_mount		*mp,
45362306a36Sopenharmony_ci	struct xfs_bui_log_item		*buip)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	struct xfs_map_extent		*map;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	/* Only one mapping operation per BUI... */
45862306a36Sopenharmony_ci	if (buip->bui_format.bui_nextents != XFS_BUI_MAX_FAST_EXTENTS)
45962306a36Sopenharmony_ci		return false;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	map = &buip->bui_format.bui_extents[0];
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	if (map->me_flags & ~XFS_BMAP_EXTENT_FLAGS)
46462306a36Sopenharmony_ci		return false;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	switch (map->me_flags & XFS_BMAP_EXTENT_TYPE_MASK) {
46762306a36Sopenharmony_ci	case XFS_BMAP_MAP:
46862306a36Sopenharmony_ci	case XFS_BMAP_UNMAP:
46962306a36Sopenharmony_ci		break;
47062306a36Sopenharmony_ci	default:
47162306a36Sopenharmony_ci		return false;
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	if (!xfs_verify_ino(mp, map->me_owner))
47562306a36Sopenharmony_ci		return false;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	if (!xfs_verify_fileext(mp, map->me_startoff, map->me_len))
47862306a36Sopenharmony_ci		return false;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	return xfs_verify_fsbext(mp, map->me_startblock, map->me_len);
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci/*
48462306a36Sopenharmony_ci * Process a bmap update intent item that was recovered from the log.
48562306a36Sopenharmony_ci * We need to update some inode's bmbt.
48662306a36Sopenharmony_ci */
48762306a36Sopenharmony_ciSTATIC int
48862306a36Sopenharmony_cixfs_bui_item_recover(
48962306a36Sopenharmony_ci	struct xfs_log_item		*lip,
49062306a36Sopenharmony_ci	struct list_head		*capture_list)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	struct xfs_bmap_intent		fake = { };
49362306a36Sopenharmony_ci	struct xfs_trans_res		resv;
49462306a36Sopenharmony_ci	struct xfs_bui_log_item		*buip = BUI_ITEM(lip);
49562306a36Sopenharmony_ci	struct xfs_trans		*tp;
49662306a36Sopenharmony_ci	struct xfs_inode		*ip = NULL;
49762306a36Sopenharmony_ci	struct xfs_mount		*mp = lip->li_log->l_mp;
49862306a36Sopenharmony_ci	struct xfs_map_extent		*map;
49962306a36Sopenharmony_ci	struct xfs_bud_log_item		*budp;
50062306a36Sopenharmony_ci	int				iext_delta;
50162306a36Sopenharmony_ci	int				error = 0;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	if (!xfs_bui_validate(mp, buip)) {
50462306a36Sopenharmony_ci		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
50562306a36Sopenharmony_ci				&buip->bui_format, sizeof(buip->bui_format));
50662306a36Sopenharmony_ci		return -EFSCORRUPTED;
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	map = &buip->bui_format.bui_extents[0];
51062306a36Sopenharmony_ci	fake.bi_whichfork = (map->me_flags & XFS_BMAP_EXTENT_ATTR_FORK) ?
51162306a36Sopenharmony_ci			XFS_ATTR_FORK : XFS_DATA_FORK;
51262306a36Sopenharmony_ci	fake.bi_type = map->me_flags & XFS_BMAP_EXTENT_TYPE_MASK;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	error = xlog_recover_iget(mp, map->me_owner, &ip);
51562306a36Sopenharmony_ci	if (error)
51662306a36Sopenharmony_ci		return error;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	/* Allocate transaction and do the work. */
51962306a36Sopenharmony_ci	resv = xlog_recover_resv(&M_RES(mp)->tr_itruncate);
52062306a36Sopenharmony_ci	error = xfs_trans_alloc(mp, &resv,
52162306a36Sopenharmony_ci			XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK), 0, 0, &tp);
52262306a36Sopenharmony_ci	if (error)
52362306a36Sopenharmony_ci		goto err_rele;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	budp = xfs_trans_get_bud(tp, buip);
52662306a36Sopenharmony_ci	xfs_ilock(ip, XFS_ILOCK_EXCL);
52762306a36Sopenharmony_ci	xfs_trans_ijoin(tp, ip, 0);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	if (fake.bi_type == XFS_BMAP_MAP)
53062306a36Sopenharmony_ci		iext_delta = XFS_IEXT_ADD_NOSPLIT_CNT;
53162306a36Sopenharmony_ci	else
53262306a36Sopenharmony_ci		iext_delta = XFS_IEXT_PUNCH_HOLE_CNT;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	error = xfs_iext_count_may_overflow(ip, fake.bi_whichfork, iext_delta);
53562306a36Sopenharmony_ci	if (error == -EFBIG)
53662306a36Sopenharmony_ci		error = xfs_iext_count_upgrade(tp, ip, iext_delta);
53762306a36Sopenharmony_ci	if (error)
53862306a36Sopenharmony_ci		goto err_cancel;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	fake.bi_owner = ip;
54162306a36Sopenharmony_ci	fake.bi_bmap.br_startblock = map->me_startblock;
54262306a36Sopenharmony_ci	fake.bi_bmap.br_startoff = map->me_startoff;
54362306a36Sopenharmony_ci	fake.bi_bmap.br_blockcount = map->me_len;
54462306a36Sopenharmony_ci	fake.bi_bmap.br_state = (map->me_flags & XFS_BMAP_EXTENT_UNWRITTEN) ?
54562306a36Sopenharmony_ci			XFS_EXT_UNWRITTEN : XFS_EXT_NORM;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	xfs_bmap_update_get_group(mp, &fake);
54862306a36Sopenharmony_ci	error = xfs_trans_log_finish_bmap_update(tp, budp, &fake);
54962306a36Sopenharmony_ci	if (error == -EFSCORRUPTED)
55062306a36Sopenharmony_ci		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, map,
55162306a36Sopenharmony_ci				sizeof(*map));
55262306a36Sopenharmony_ci	xfs_bmap_update_put_group(&fake);
55362306a36Sopenharmony_ci	if (error)
55462306a36Sopenharmony_ci		goto err_cancel;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	if (fake.bi_bmap.br_blockcount > 0) {
55762306a36Sopenharmony_ci		ASSERT(fake.bi_type == XFS_BMAP_UNMAP);
55862306a36Sopenharmony_ci		xfs_bmap_unmap_extent(tp, ip, &fake.bi_bmap);
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	/*
56262306a36Sopenharmony_ci	 * Commit transaction, which frees the transaction and saves the inode
56362306a36Sopenharmony_ci	 * for later replay activities.
56462306a36Sopenharmony_ci	 */
56562306a36Sopenharmony_ci	error = xfs_defer_ops_capture_and_commit(tp, capture_list);
56662306a36Sopenharmony_ci	if (error)
56762306a36Sopenharmony_ci		goto err_unlock;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	xfs_iunlock(ip, XFS_ILOCK_EXCL);
57062306a36Sopenharmony_ci	xfs_irele(ip);
57162306a36Sopenharmony_ci	return 0;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cierr_cancel:
57462306a36Sopenharmony_ci	xfs_trans_cancel(tp);
57562306a36Sopenharmony_cierr_unlock:
57662306a36Sopenharmony_ci	xfs_iunlock(ip, XFS_ILOCK_EXCL);
57762306a36Sopenharmony_cierr_rele:
57862306a36Sopenharmony_ci	xfs_irele(ip);
57962306a36Sopenharmony_ci	return error;
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ciSTATIC bool
58362306a36Sopenharmony_cixfs_bui_item_match(
58462306a36Sopenharmony_ci	struct xfs_log_item	*lip,
58562306a36Sopenharmony_ci	uint64_t		intent_id)
58662306a36Sopenharmony_ci{
58762306a36Sopenharmony_ci	return BUI_ITEM(lip)->bui_format.bui_id == intent_id;
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci/* Relog an intent item to push the log tail forward. */
59162306a36Sopenharmony_cistatic struct xfs_log_item *
59262306a36Sopenharmony_cixfs_bui_item_relog(
59362306a36Sopenharmony_ci	struct xfs_log_item		*intent,
59462306a36Sopenharmony_ci	struct xfs_trans		*tp)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	struct xfs_bud_log_item		*budp;
59762306a36Sopenharmony_ci	struct xfs_bui_log_item		*buip;
59862306a36Sopenharmony_ci	struct xfs_map_extent		*map;
59962306a36Sopenharmony_ci	unsigned int			count;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	count = BUI_ITEM(intent)->bui_format.bui_nextents;
60262306a36Sopenharmony_ci	map = BUI_ITEM(intent)->bui_format.bui_extents;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	tp->t_flags |= XFS_TRANS_DIRTY;
60562306a36Sopenharmony_ci	budp = xfs_trans_get_bud(tp, BUI_ITEM(intent));
60662306a36Sopenharmony_ci	set_bit(XFS_LI_DIRTY, &budp->bud_item.li_flags);
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	buip = xfs_bui_init(tp->t_mountp);
60962306a36Sopenharmony_ci	memcpy(buip->bui_format.bui_extents, map, count * sizeof(*map));
61062306a36Sopenharmony_ci	atomic_set(&buip->bui_next_extent, count);
61162306a36Sopenharmony_ci	xfs_trans_add_item(tp, &buip->bui_item);
61262306a36Sopenharmony_ci	set_bit(XFS_LI_DIRTY, &buip->bui_item.li_flags);
61362306a36Sopenharmony_ci	return &buip->bui_item;
61462306a36Sopenharmony_ci}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_cistatic const struct xfs_item_ops xfs_bui_item_ops = {
61762306a36Sopenharmony_ci	.flags		= XFS_ITEM_INTENT,
61862306a36Sopenharmony_ci	.iop_size	= xfs_bui_item_size,
61962306a36Sopenharmony_ci	.iop_format	= xfs_bui_item_format,
62062306a36Sopenharmony_ci	.iop_unpin	= xfs_bui_item_unpin,
62162306a36Sopenharmony_ci	.iop_release	= xfs_bui_item_release,
62262306a36Sopenharmony_ci	.iop_recover	= xfs_bui_item_recover,
62362306a36Sopenharmony_ci	.iop_match	= xfs_bui_item_match,
62462306a36Sopenharmony_ci	.iop_relog	= xfs_bui_item_relog,
62562306a36Sopenharmony_ci};
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_cistatic inline void
62862306a36Sopenharmony_cixfs_bui_copy_format(
62962306a36Sopenharmony_ci	struct xfs_bui_log_format	*dst,
63062306a36Sopenharmony_ci	const struct xfs_bui_log_format	*src)
63162306a36Sopenharmony_ci{
63262306a36Sopenharmony_ci	unsigned int			i;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	memcpy(dst, src, offsetof(struct xfs_bui_log_format, bui_extents));
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	for (i = 0; i < src->bui_nextents; i++)
63762306a36Sopenharmony_ci		memcpy(&dst->bui_extents[i], &src->bui_extents[i],
63862306a36Sopenharmony_ci				sizeof(struct xfs_map_extent));
63962306a36Sopenharmony_ci}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci/*
64262306a36Sopenharmony_ci * This routine is called to create an in-core extent bmap update
64362306a36Sopenharmony_ci * item from the bui format structure which was logged on disk.
64462306a36Sopenharmony_ci * It allocates an in-core bui, copies the extents from the format
64562306a36Sopenharmony_ci * structure into it, and adds the bui to the AIL with the given
64662306a36Sopenharmony_ci * LSN.
64762306a36Sopenharmony_ci */
64862306a36Sopenharmony_ciSTATIC int
64962306a36Sopenharmony_cixlog_recover_bui_commit_pass2(
65062306a36Sopenharmony_ci	struct xlog			*log,
65162306a36Sopenharmony_ci	struct list_head		*buffer_list,
65262306a36Sopenharmony_ci	struct xlog_recover_item	*item,
65362306a36Sopenharmony_ci	xfs_lsn_t			lsn)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	struct xfs_mount		*mp = log->l_mp;
65662306a36Sopenharmony_ci	struct xfs_bui_log_item		*buip;
65762306a36Sopenharmony_ci	struct xfs_bui_log_format	*bui_formatp;
65862306a36Sopenharmony_ci	size_t				len;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	bui_formatp = item->ri_buf[0].i_addr;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	if (item->ri_buf[0].i_len < xfs_bui_log_format_sizeof(0)) {
66362306a36Sopenharmony_ci		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
66462306a36Sopenharmony_ci				item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
66562306a36Sopenharmony_ci		return -EFSCORRUPTED;
66662306a36Sopenharmony_ci	}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	if (bui_formatp->bui_nextents != XFS_BUI_MAX_FAST_EXTENTS) {
66962306a36Sopenharmony_ci		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
67062306a36Sopenharmony_ci				item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
67162306a36Sopenharmony_ci		return -EFSCORRUPTED;
67262306a36Sopenharmony_ci	}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	len = xfs_bui_log_format_sizeof(bui_formatp->bui_nextents);
67562306a36Sopenharmony_ci	if (item->ri_buf[0].i_len != len) {
67662306a36Sopenharmony_ci		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
67762306a36Sopenharmony_ci				item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
67862306a36Sopenharmony_ci		return -EFSCORRUPTED;
67962306a36Sopenharmony_ci	}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	buip = xfs_bui_init(mp);
68262306a36Sopenharmony_ci	xfs_bui_copy_format(&buip->bui_format, bui_formatp);
68362306a36Sopenharmony_ci	atomic_set(&buip->bui_next_extent, bui_formatp->bui_nextents);
68462306a36Sopenharmony_ci	/*
68562306a36Sopenharmony_ci	 * Insert the intent into the AIL directly and drop one reference so
68662306a36Sopenharmony_ci	 * that finishing or canceling the work will drop the other.
68762306a36Sopenharmony_ci	 */
68862306a36Sopenharmony_ci	xfs_trans_ail_insert(log->l_ailp, &buip->bui_item, lsn);
68962306a36Sopenharmony_ci	xfs_bui_release(buip);
69062306a36Sopenharmony_ci	return 0;
69162306a36Sopenharmony_ci}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ciconst struct xlog_recover_item_ops xlog_bui_item_ops = {
69462306a36Sopenharmony_ci	.item_type		= XFS_LI_BUI,
69562306a36Sopenharmony_ci	.commit_pass2		= xlog_recover_bui_commit_pass2,
69662306a36Sopenharmony_ci};
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci/*
69962306a36Sopenharmony_ci * This routine is called when an BUD format structure is found in a committed
70062306a36Sopenharmony_ci * transaction in the log. Its purpose is to cancel the corresponding BUI if it
70162306a36Sopenharmony_ci * was still in the log. To do this it searches the AIL for the BUI with an id
70262306a36Sopenharmony_ci * equal to that in the BUD format structure. If we find it we drop the BUD
70362306a36Sopenharmony_ci * reference, which removes the BUI from the AIL and frees it.
70462306a36Sopenharmony_ci */
70562306a36Sopenharmony_ciSTATIC int
70662306a36Sopenharmony_cixlog_recover_bud_commit_pass2(
70762306a36Sopenharmony_ci	struct xlog			*log,
70862306a36Sopenharmony_ci	struct list_head		*buffer_list,
70962306a36Sopenharmony_ci	struct xlog_recover_item	*item,
71062306a36Sopenharmony_ci	xfs_lsn_t			lsn)
71162306a36Sopenharmony_ci{
71262306a36Sopenharmony_ci	struct xfs_bud_log_format	*bud_formatp;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	bud_formatp = item->ri_buf[0].i_addr;
71562306a36Sopenharmony_ci	if (item->ri_buf[0].i_len != sizeof(struct xfs_bud_log_format)) {
71662306a36Sopenharmony_ci		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp,
71762306a36Sopenharmony_ci				item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
71862306a36Sopenharmony_ci		return -EFSCORRUPTED;
71962306a36Sopenharmony_ci	}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	xlog_recover_release_intent(log, XFS_LI_BUI, bud_formatp->bud_bui_id);
72262306a36Sopenharmony_ci	return 0;
72362306a36Sopenharmony_ci}
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ciconst struct xlog_recover_item_ops xlog_bud_item_ops = {
72662306a36Sopenharmony_ci	.item_type		= XFS_LI_BUD,
72762306a36Sopenharmony_ci	.commit_pass2		= xlog_recover_bud_commit_pass2,
72862306a36Sopenharmony_ci};
729