18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
48c2ecf20Sopenharmony_ci * All Rights Reserved.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci#include "xfs.h"
78c2ecf20Sopenharmony_ci#include "xfs_fs.h"
88c2ecf20Sopenharmony_ci#include "xfs_shared.h"
98c2ecf20Sopenharmony_ci#include "xfs_format.h"
108c2ecf20Sopenharmony_ci#include "xfs_log_format.h"
118c2ecf20Sopenharmony_ci#include "xfs_trans_resv.h"
128c2ecf20Sopenharmony_ci#include "xfs_sb.h"
138c2ecf20Sopenharmony_ci#include "xfs_mount.h"
148c2ecf20Sopenharmony_ci#include "xfs_btree.h"
158c2ecf20Sopenharmony_ci#include "xfs_btree_staging.h"
168c2ecf20Sopenharmony_ci#include "xfs_alloc_btree.h"
178c2ecf20Sopenharmony_ci#include "xfs_alloc.h"
188c2ecf20Sopenharmony_ci#include "xfs_extent_busy.h"
198c2ecf20Sopenharmony_ci#include "xfs_error.h"
208c2ecf20Sopenharmony_ci#include "xfs_trace.h"
218c2ecf20Sopenharmony_ci#include "xfs_trans.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ciSTATIC struct xfs_btree_cur *
258c2ecf20Sopenharmony_cixfs_allocbt_dup_cursor(
268c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	return xfs_allocbt_init_cursor(cur->bc_mp, cur->bc_tp,
298c2ecf20Sopenharmony_ci			cur->bc_ag.agbp, cur->bc_ag.agno,
308c2ecf20Sopenharmony_ci			cur->bc_btnum);
318c2ecf20Sopenharmony_ci}
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ciSTATIC void
348c2ecf20Sopenharmony_cixfs_allocbt_set_root(
358c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
368c2ecf20Sopenharmony_ci	union xfs_btree_ptr	*ptr,
378c2ecf20Sopenharmony_ci	int			inc)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	struct xfs_buf		*agbp = cur->bc_ag.agbp;
408c2ecf20Sopenharmony_ci	struct xfs_agf		*agf = agbp->b_addr;
418c2ecf20Sopenharmony_ci	int			btnum = cur->bc_btnum;
428c2ecf20Sopenharmony_ci	struct xfs_perag	*pag = agbp->b_pag;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	ASSERT(ptr->s != 0);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	agf->agf_roots[btnum] = ptr->s;
478c2ecf20Sopenharmony_ci	be32_add_cpu(&agf->agf_levels[btnum], inc);
488c2ecf20Sopenharmony_ci	pag->pagf_levels[btnum] += inc;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS);
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ciSTATIC int
548c2ecf20Sopenharmony_cixfs_allocbt_alloc_block(
558c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
568c2ecf20Sopenharmony_ci	union xfs_btree_ptr	*start,
578c2ecf20Sopenharmony_ci	union xfs_btree_ptr	*new,
588c2ecf20Sopenharmony_ci	int			*stat)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	int			error;
618c2ecf20Sopenharmony_ci	xfs_agblock_t		bno;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	/* Allocate the new block from the freelist. If we can't, give up.  */
648c2ecf20Sopenharmony_ci	error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_ag.agbp,
658c2ecf20Sopenharmony_ci				       &bno, 1);
668c2ecf20Sopenharmony_ci	if (error)
678c2ecf20Sopenharmony_ci		return error;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	if (bno == NULLAGBLOCK) {
708c2ecf20Sopenharmony_ci		*stat = 0;
718c2ecf20Sopenharmony_ci		return 0;
728c2ecf20Sopenharmony_ci	}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	xfs_extent_busy_reuse(cur->bc_mp, cur->bc_ag.agno, bno, 1, false);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	xfs_trans_agbtree_delta(cur->bc_tp, 1);
778c2ecf20Sopenharmony_ci	new->s = cpu_to_be32(bno);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	*stat = 1;
808c2ecf20Sopenharmony_ci	return 0;
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ciSTATIC int
848c2ecf20Sopenharmony_cixfs_allocbt_free_block(
858c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
868c2ecf20Sopenharmony_ci	struct xfs_buf		*bp)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	struct xfs_buf		*agbp = cur->bc_ag.agbp;
898c2ecf20Sopenharmony_ci	struct xfs_agf		*agf = agbp->b_addr;
908c2ecf20Sopenharmony_ci	xfs_agblock_t		bno;
918c2ecf20Sopenharmony_ci	int			error;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	bno = xfs_daddr_to_agbno(cur->bc_mp, XFS_BUF_ADDR(bp));
948c2ecf20Sopenharmony_ci	error = xfs_alloc_put_freelist(cur->bc_tp, agbp, NULL, bno, 1);
958c2ecf20Sopenharmony_ci	if (error)
968c2ecf20Sopenharmony_ci		return error;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1,
998c2ecf20Sopenharmony_ci			      XFS_EXTENT_BUSY_SKIP_DISCARD);
1008c2ecf20Sopenharmony_ci	xfs_trans_agbtree_delta(cur->bc_tp, -1);
1018c2ecf20Sopenharmony_ci	return 0;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci/*
1058c2ecf20Sopenharmony_ci * Update the longest extent in the AGF
1068c2ecf20Sopenharmony_ci */
1078c2ecf20Sopenharmony_ciSTATIC void
1088c2ecf20Sopenharmony_cixfs_allocbt_update_lastrec(
1098c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
1108c2ecf20Sopenharmony_ci	struct xfs_btree_block	*block,
1118c2ecf20Sopenharmony_ci	union xfs_btree_rec	*rec,
1128c2ecf20Sopenharmony_ci	int			ptr,
1138c2ecf20Sopenharmony_ci	int			reason)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	struct xfs_agf		*agf = cur->bc_ag.agbp->b_addr;
1168c2ecf20Sopenharmony_ci	struct xfs_perag	*pag;
1178c2ecf20Sopenharmony_ci	__be32			len;
1188c2ecf20Sopenharmony_ci	int			numrecs;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	ASSERT(cur->bc_btnum == XFS_BTNUM_CNT);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	switch (reason) {
1238c2ecf20Sopenharmony_ci	case LASTREC_UPDATE:
1248c2ecf20Sopenharmony_ci		/*
1258c2ecf20Sopenharmony_ci		 * If this is the last leaf block and it's the last record,
1268c2ecf20Sopenharmony_ci		 * then update the size of the longest extent in the AG.
1278c2ecf20Sopenharmony_ci		 */
1288c2ecf20Sopenharmony_ci		if (ptr != xfs_btree_get_numrecs(block))
1298c2ecf20Sopenharmony_ci			return;
1308c2ecf20Sopenharmony_ci		len = rec->alloc.ar_blockcount;
1318c2ecf20Sopenharmony_ci		break;
1328c2ecf20Sopenharmony_ci	case LASTREC_INSREC:
1338c2ecf20Sopenharmony_ci		if (be32_to_cpu(rec->alloc.ar_blockcount) <=
1348c2ecf20Sopenharmony_ci		    be32_to_cpu(agf->agf_longest))
1358c2ecf20Sopenharmony_ci			return;
1368c2ecf20Sopenharmony_ci		len = rec->alloc.ar_blockcount;
1378c2ecf20Sopenharmony_ci		break;
1388c2ecf20Sopenharmony_ci	case LASTREC_DELREC:
1398c2ecf20Sopenharmony_ci		numrecs = xfs_btree_get_numrecs(block);
1408c2ecf20Sopenharmony_ci		if (ptr <= numrecs)
1418c2ecf20Sopenharmony_ci			return;
1428c2ecf20Sopenharmony_ci		ASSERT(ptr == numrecs + 1);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci		if (numrecs) {
1458c2ecf20Sopenharmony_ci			xfs_alloc_rec_t *rrp;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci			rrp = XFS_ALLOC_REC_ADDR(cur->bc_mp, block, numrecs);
1488c2ecf20Sopenharmony_ci			len = rrp->ar_blockcount;
1498c2ecf20Sopenharmony_ci		} else {
1508c2ecf20Sopenharmony_ci			len = 0;
1518c2ecf20Sopenharmony_ci		}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci		break;
1548c2ecf20Sopenharmony_ci	default:
1558c2ecf20Sopenharmony_ci		ASSERT(0);
1568c2ecf20Sopenharmony_ci		return;
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	agf->agf_longest = len;
1608c2ecf20Sopenharmony_ci	pag = cur->bc_ag.agbp->b_pag;
1618c2ecf20Sopenharmony_ci	pag->pagf_longest = be32_to_cpu(len);
1628c2ecf20Sopenharmony_ci	xfs_alloc_log_agf(cur->bc_tp, cur->bc_ag.agbp, XFS_AGF_LONGEST);
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ciSTATIC int
1668c2ecf20Sopenharmony_cixfs_allocbt_get_minrecs(
1678c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
1688c2ecf20Sopenharmony_ci	int			level)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	return cur->bc_mp->m_alloc_mnr[level != 0];
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ciSTATIC int
1748c2ecf20Sopenharmony_cixfs_allocbt_get_maxrecs(
1758c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
1768c2ecf20Sopenharmony_ci	int			level)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	return cur->bc_mp->m_alloc_mxr[level != 0];
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ciSTATIC void
1828c2ecf20Sopenharmony_cixfs_allocbt_init_key_from_rec(
1838c2ecf20Sopenharmony_ci	union xfs_btree_key	*key,
1848c2ecf20Sopenharmony_ci	union xfs_btree_rec	*rec)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	key->alloc.ar_startblock = rec->alloc.ar_startblock;
1878c2ecf20Sopenharmony_ci	key->alloc.ar_blockcount = rec->alloc.ar_blockcount;
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ciSTATIC void
1918c2ecf20Sopenharmony_cixfs_bnobt_init_high_key_from_rec(
1928c2ecf20Sopenharmony_ci	union xfs_btree_key	*key,
1938c2ecf20Sopenharmony_ci	union xfs_btree_rec	*rec)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	__u32			x;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	x = be32_to_cpu(rec->alloc.ar_startblock);
1988c2ecf20Sopenharmony_ci	x += be32_to_cpu(rec->alloc.ar_blockcount) - 1;
1998c2ecf20Sopenharmony_ci	key->alloc.ar_startblock = cpu_to_be32(x);
2008c2ecf20Sopenharmony_ci	key->alloc.ar_blockcount = 0;
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ciSTATIC void
2048c2ecf20Sopenharmony_cixfs_cntbt_init_high_key_from_rec(
2058c2ecf20Sopenharmony_ci	union xfs_btree_key	*key,
2068c2ecf20Sopenharmony_ci	union xfs_btree_rec	*rec)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	key->alloc.ar_blockcount = rec->alloc.ar_blockcount;
2098c2ecf20Sopenharmony_ci	key->alloc.ar_startblock = 0;
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ciSTATIC void
2138c2ecf20Sopenharmony_cixfs_allocbt_init_rec_from_cur(
2148c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
2158c2ecf20Sopenharmony_ci	union xfs_btree_rec	*rec)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	rec->alloc.ar_startblock = cpu_to_be32(cur->bc_rec.a.ar_startblock);
2188c2ecf20Sopenharmony_ci	rec->alloc.ar_blockcount = cpu_to_be32(cur->bc_rec.a.ar_blockcount);
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ciSTATIC void
2228c2ecf20Sopenharmony_cixfs_allocbt_init_ptr_from_cur(
2238c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
2248c2ecf20Sopenharmony_ci	union xfs_btree_ptr	*ptr)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	struct xfs_agf		*agf = cur->bc_ag.agbp->b_addr;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	ASSERT(cur->bc_ag.agno == be32_to_cpu(agf->agf_seqno));
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	ptr->s = agf->agf_roots[cur->bc_btnum];
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ciSTATIC int64_t
2348c2ecf20Sopenharmony_cixfs_bnobt_key_diff(
2358c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
2368c2ecf20Sopenharmony_ci	union xfs_btree_key	*key)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	xfs_alloc_rec_incore_t	*rec = &cur->bc_rec.a;
2398c2ecf20Sopenharmony_ci	xfs_alloc_key_t		*kp = &key->alloc;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	return (int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock;
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ciSTATIC int64_t
2458c2ecf20Sopenharmony_cixfs_cntbt_key_diff(
2468c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
2478c2ecf20Sopenharmony_ci	union xfs_btree_key	*key)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	xfs_alloc_rec_incore_t	*rec = &cur->bc_rec.a;
2508c2ecf20Sopenharmony_ci	xfs_alloc_key_t		*kp = &key->alloc;
2518c2ecf20Sopenharmony_ci	int64_t			diff;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	diff = (int64_t)be32_to_cpu(kp->ar_blockcount) - rec->ar_blockcount;
2548c2ecf20Sopenharmony_ci	if (diff)
2558c2ecf20Sopenharmony_ci		return diff;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	return (int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock;
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ciSTATIC int64_t
2618c2ecf20Sopenharmony_cixfs_bnobt_diff_two_keys(
2628c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
2638c2ecf20Sopenharmony_ci	union xfs_btree_key	*k1,
2648c2ecf20Sopenharmony_ci	union xfs_btree_key	*k2)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	return (int64_t)be32_to_cpu(k1->alloc.ar_startblock) -
2678c2ecf20Sopenharmony_ci			  be32_to_cpu(k2->alloc.ar_startblock);
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ciSTATIC int64_t
2718c2ecf20Sopenharmony_cixfs_cntbt_diff_two_keys(
2728c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
2738c2ecf20Sopenharmony_ci	union xfs_btree_key	*k1,
2748c2ecf20Sopenharmony_ci	union xfs_btree_key	*k2)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	int64_t			diff;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	diff =  be32_to_cpu(k1->alloc.ar_blockcount) -
2798c2ecf20Sopenharmony_ci		be32_to_cpu(k2->alloc.ar_blockcount);
2808c2ecf20Sopenharmony_ci	if (diff)
2818c2ecf20Sopenharmony_ci		return diff;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	return  be32_to_cpu(k1->alloc.ar_startblock) -
2848c2ecf20Sopenharmony_ci		be32_to_cpu(k2->alloc.ar_startblock);
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_cistatic xfs_failaddr_t
2888c2ecf20Sopenharmony_cixfs_allocbt_verify(
2898c2ecf20Sopenharmony_ci	struct xfs_buf		*bp)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	struct xfs_mount	*mp = bp->b_mount;
2928c2ecf20Sopenharmony_ci	struct xfs_btree_block	*block = XFS_BUF_TO_BLOCK(bp);
2938c2ecf20Sopenharmony_ci	struct xfs_perag	*pag = bp->b_pag;
2948c2ecf20Sopenharmony_ci	xfs_failaddr_t		fa;
2958c2ecf20Sopenharmony_ci	unsigned int		level;
2968c2ecf20Sopenharmony_ci	xfs_btnum_t		btnum = XFS_BTNUM_BNOi;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	if (!xfs_verify_magic(bp, block->bb_magic))
2998c2ecf20Sopenharmony_ci		return __this_address;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	if (xfs_sb_version_hascrc(&mp->m_sb)) {
3028c2ecf20Sopenharmony_ci		fa = xfs_btree_sblock_v5hdr_verify(bp);
3038c2ecf20Sopenharmony_ci		if (fa)
3048c2ecf20Sopenharmony_ci			return fa;
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	/*
3088c2ecf20Sopenharmony_ci	 * The perag may not be attached during grow operations or fully
3098c2ecf20Sopenharmony_ci	 * initialized from the AGF during log recovery. Therefore we can only
3108c2ecf20Sopenharmony_ci	 * check against maximum tree depth from those contexts.
3118c2ecf20Sopenharmony_ci	 *
3128c2ecf20Sopenharmony_ci	 * Otherwise check against the per-tree limit. Peek at one of the
3138c2ecf20Sopenharmony_ci	 * verifier magic values to determine the type of tree we're verifying
3148c2ecf20Sopenharmony_ci	 * against.
3158c2ecf20Sopenharmony_ci	 */
3168c2ecf20Sopenharmony_ci	level = be16_to_cpu(block->bb_level);
3178c2ecf20Sopenharmony_ci	if (bp->b_ops->magic[0] == cpu_to_be32(XFS_ABTC_MAGIC))
3188c2ecf20Sopenharmony_ci		btnum = XFS_BTNUM_CNTi;
3198c2ecf20Sopenharmony_ci	if (pag && pag->pagf_init) {
3208c2ecf20Sopenharmony_ci		if (level >= pag->pagf_levels[btnum])
3218c2ecf20Sopenharmony_ci			return __this_address;
3228c2ecf20Sopenharmony_ci	} else if (level >= mp->m_ag_maxlevels)
3238c2ecf20Sopenharmony_ci		return __this_address;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	return xfs_btree_sblock_verify(bp, mp->m_alloc_mxr[level != 0]);
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_cistatic void
3298c2ecf20Sopenharmony_cixfs_allocbt_read_verify(
3308c2ecf20Sopenharmony_ci	struct xfs_buf	*bp)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	xfs_failaddr_t	fa;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if (!xfs_btree_sblock_verify_crc(bp))
3358c2ecf20Sopenharmony_ci		xfs_verifier_error(bp, -EFSBADCRC, __this_address);
3368c2ecf20Sopenharmony_ci	else {
3378c2ecf20Sopenharmony_ci		fa = xfs_allocbt_verify(bp);
3388c2ecf20Sopenharmony_ci		if (fa)
3398c2ecf20Sopenharmony_ci			xfs_verifier_error(bp, -EFSCORRUPTED, fa);
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	if (bp->b_error)
3438c2ecf20Sopenharmony_ci		trace_xfs_btree_corrupt(bp, _RET_IP_);
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic void
3478c2ecf20Sopenharmony_cixfs_allocbt_write_verify(
3488c2ecf20Sopenharmony_ci	struct xfs_buf	*bp)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	xfs_failaddr_t	fa;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	fa = xfs_allocbt_verify(bp);
3538c2ecf20Sopenharmony_ci	if (fa) {
3548c2ecf20Sopenharmony_ci		trace_xfs_btree_corrupt(bp, _RET_IP_);
3558c2ecf20Sopenharmony_ci		xfs_verifier_error(bp, -EFSCORRUPTED, fa);
3568c2ecf20Sopenharmony_ci		return;
3578c2ecf20Sopenharmony_ci	}
3588c2ecf20Sopenharmony_ci	xfs_btree_sblock_calc_crc(bp);
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ciconst struct xfs_buf_ops xfs_bnobt_buf_ops = {
3638c2ecf20Sopenharmony_ci	.name = "xfs_bnobt",
3648c2ecf20Sopenharmony_ci	.magic = { cpu_to_be32(XFS_ABTB_MAGIC),
3658c2ecf20Sopenharmony_ci		   cpu_to_be32(XFS_ABTB_CRC_MAGIC) },
3668c2ecf20Sopenharmony_ci	.verify_read = xfs_allocbt_read_verify,
3678c2ecf20Sopenharmony_ci	.verify_write = xfs_allocbt_write_verify,
3688c2ecf20Sopenharmony_ci	.verify_struct = xfs_allocbt_verify,
3698c2ecf20Sopenharmony_ci};
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ciconst struct xfs_buf_ops xfs_cntbt_buf_ops = {
3728c2ecf20Sopenharmony_ci	.name = "xfs_cntbt",
3738c2ecf20Sopenharmony_ci	.magic = { cpu_to_be32(XFS_ABTC_MAGIC),
3748c2ecf20Sopenharmony_ci		   cpu_to_be32(XFS_ABTC_CRC_MAGIC) },
3758c2ecf20Sopenharmony_ci	.verify_read = xfs_allocbt_read_verify,
3768c2ecf20Sopenharmony_ci	.verify_write = xfs_allocbt_write_verify,
3778c2ecf20Sopenharmony_ci	.verify_struct = xfs_allocbt_verify,
3788c2ecf20Sopenharmony_ci};
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ciSTATIC int
3818c2ecf20Sopenharmony_cixfs_bnobt_keys_inorder(
3828c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
3838c2ecf20Sopenharmony_ci	union xfs_btree_key	*k1,
3848c2ecf20Sopenharmony_ci	union xfs_btree_key	*k2)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	return be32_to_cpu(k1->alloc.ar_startblock) <
3878c2ecf20Sopenharmony_ci	       be32_to_cpu(k2->alloc.ar_startblock);
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ciSTATIC int
3918c2ecf20Sopenharmony_cixfs_bnobt_recs_inorder(
3928c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
3938c2ecf20Sopenharmony_ci	union xfs_btree_rec	*r1,
3948c2ecf20Sopenharmony_ci	union xfs_btree_rec	*r2)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	return be32_to_cpu(r1->alloc.ar_startblock) +
3978c2ecf20Sopenharmony_ci		be32_to_cpu(r1->alloc.ar_blockcount) <=
3988c2ecf20Sopenharmony_ci		be32_to_cpu(r2->alloc.ar_startblock);
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ciSTATIC int
4028c2ecf20Sopenharmony_cixfs_cntbt_keys_inorder(
4038c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
4048c2ecf20Sopenharmony_ci	union xfs_btree_key	*k1,
4058c2ecf20Sopenharmony_ci	union xfs_btree_key	*k2)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	return be32_to_cpu(k1->alloc.ar_blockcount) <
4088c2ecf20Sopenharmony_ci		be32_to_cpu(k2->alloc.ar_blockcount) ||
4098c2ecf20Sopenharmony_ci		(k1->alloc.ar_blockcount == k2->alloc.ar_blockcount &&
4108c2ecf20Sopenharmony_ci		 be32_to_cpu(k1->alloc.ar_startblock) <
4118c2ecf20Sopenharmony_ci		 be32_to_cpu(k2->alloc.ar_startblock));
4128c2ecf20Sopenharmony_ci}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ciSTATIC int
4158c2ecf20Sopenharmony_cixfs_cntbt_recs_inorder(
4168c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
4178c2ecf20Sopenharmony_ci	union xfs_btree_rec	*r1,
4188c2ecf20Sopenharmony_ci	union xfs_btree_rec	*r2)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	return be32_to_cpu(r1->alloc.ar_blockcount) <
4218c2ecf20Sopenharmony_ci		be32_to_cpu(r2->alloc.ar_blockcount) ||
4228c2ecf20Sopenharmony_ci		(r1->alloc.ar_blockcount == r2->alloc.ar_blockcount &&
4238c2ecf20Sopenharmony_ci		 be32_to_cpu(r1->alloc.ar_startblock) <
4248c2ecf20Sopenharmony_ci		 be32_to_cpu(r2->alloc.ar_startblock));
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic const struct xfs_btree_ops xfs_bnobt_ops = {
4288c2ecf20Sopenharmony_ci	.rec_len		= sizeof(xfs_alloc_rec_t),
4298c2ecf20Sopenharmony_ci	.key_len		= sizeof(xfs_alloc_key_t),
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	.dup_cursor		= xfs_allocbt_dup_cursor,
4328c2ecf20Sopenharmony_ci	.set_root		= xfs_allocbt_set_root,
4338c2ecf20Sopenharmony_ci	.alloc_block		= xfs_allocbt_alloc_block,
4348c2ecf20Sopenharmony_ci	.free_block		= xfs_allocbt_free_block,
4358c2ecf20Sopenharmony_ci	.update_lastrec		= xfs_allocbt_update_lastrec,
4368c2ecf20Sopenharmony_ci	.get_minrecs		= xfs_allocbt_get_minrecs,
4378c2ecf20Sopenharmony_ci	.get_maxrecs		= xfs_allocbt_get_maxrecs,
4388c2ecf20Sopenharmony_ci	.init_key_from_rec	= xfs_allocbt_init_key_from_rec,
4398c2ecf20Sopenharmony_ci	.init_high_key_from_rec	= xfs_bnobt_init_high_key_from_rec,
4408c2ecf20Sopenharmony_ci	.init_rec_from_cur	= xfs_allocbt_init_rec_from_cur,
4418c2ecf20Sopenharmony_ci	.init_ptr_from_cur	= xfs_allocbt_init_ptr_from_cur,
4428c2ecf20Sopenharmony_ci	.key_diff		= xfs_bnobt_key_diff,
4438c2ecf20Sopenharmony_ci	.buf_ops		= &xfs_bnobt_buf_ops,
4448c2ecf20Sopenharmony_ci	.diff_two_keys		= xfs_bnobt_diff_two_keys,
4458c2ecf20Sopenharmony_ci	.keys_inorder		= xfs_bnobt_keys_inorder,
4468c2ecf20Sopenharmony_ci	.recs_inorder		= xfs_bnobt_recs_inorder,
4478c2ecf20Sopenharmony_ci};
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_cistatic const struct xfs_btree_ops xfs_cntbt_ops = {
4508c2ecf20Sopenharmony_ci	.rec_len		= sizeof(xfs_alloc_rec_t),
4518c2ecf20Sopenharmony_ci	.key_len		= sizeof(xfs_alloc_key_t),
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	.dup_cursor		= xfs_allocbt_dup_cursor,
4548c2ecf20Sopenharmony_ci	.set_root		= xfs_allocbt_set_root,
4558c2ecf20Sopenharmony_ci	.alloc_block		= xfs_allocbt_alloc_block,
4568c2ecf20Sopenharmony_ci	.free_block		= xfs_allocbt_free_block,
4578c2ecf20Sopenharmony_ci	.update_lastrec		= xfs_allocbt_update_lastrec,
4588c2ecf20Sopenharmony_ci	.get_minrecs		= xfs_allocbt_get_minrecs,
4598c2ecf20Sopenharmony_ci	.get_maxrecs		= xfs_allocbt_get_maxrecs,
4608c2ecf20Sopenharmony_ci	.init_key_from_rec	= xfs_allocbt_init_key_from_rec,
4618c2ecf20Sopenharmony_ci	.init_high_key_from_rec	= xfs_cntbt_init_high_key_from_rec,
4628c2ecf20Sopenharmony_ci	.init_rec_from_cur	= xfs_allocbt_init_rec_from_cur,
4638c2ecf20Sopenharmony_ci	.init_ptr_from_cur	= xfs_allocbt_init_ptr_from_cur,
4648c2ecf20Sopenharmony_ci	.key_diff		= xfs_cntbt_key_diff,
4658c2ecf20Sopenharmony_ci	.buf_ops		= &xfs_cntbt_buf_ops,
4668c2ecf20Sopenharmony_ci	.diff_two_keys		= xfs_cntbt_diff_two_keys,
4678c2ecf20Sopenharmony_ci	.keys_inorder		= xfs_cntbt_keys_inorder,
4688c2ecf20Sopenharmony_ci	.recs_inorder		= xfs_cntbt_recs_inorder,
4698c2ecf20Sopenharmony_ci};
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci/* Allocate most of a new allocation btree cursor. */
4728c2ecf20Sopenharmony_ciSTATIC struct xfs_btree_cur *
4738c2ecf20Sopenharmony_cixfs_allocbt_init_common(
4748c2ecf20Sopenharmony_ci	struct xfs_mount	*mp,
4758c2ecf20Sopenharmony_ci	struct xfs_trans	*tp,
4768c2ecf20Sopenharmony_ci	xfs_agnumber_t		agno,
4778c2ecf20Sopenharmony_ci	xfs_btnum_t		btnum)
4788c2ecf20Sopenharmony_ci{
4798c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	ASSERT(btnum == XFS_BTNUM_BNO || btnum == XFS_BTNUM_CNT);
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	cur = kmem_cache_zalloc(xfs_btree_cur_zone, GFP_NOFS | __GFP_NOFAIL);
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	cur->bc_tp = tp;
4868c2ecf20Sopenharmony_ci	cur->bc_mp = mp;
4878c2ecf20Sopenharmony_ci	cur->bc_btnum = btnum;
4888c2ecf20Sopenharmony_ci	cur->bc_blocklog = mp->m_sb.sb_blocklog;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	if (btnum == XFS_BTNUM_CNT) {
4918c2ecf20Sopenharmony_ci		cur->bc_ops = &xfs_cntbt_ops;
4928c2ecf20Sopenharmony_ci		cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_abtc_2);
4938c2ecf20Sopenharmony_ci		cur->bc_flags = XFS_BTREE_LASTREC_UPDATE;
4948c2ecf20Sopenharmony_ci	} else {
4958c2ecf20Sopenharmony_ci		cur->bc_ops = &xfs_bnobt_ops;
4968c2ecf20Sopenharmony_ci		cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_abtb_2);
4978c2ecf20Sopenharmony_ci	}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	cur->bc_ag.agno = agno;
5008c2ecf20Sopenharmony_ci	cur->bc_ag.abt.active = false;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	if (xfs_sb_version_hascrc(&mp->m_sb))
5038c2ecf20Sopenharmony_ci		cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	return cur;
5068c2ecf20Sopenharmony_ci}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci/*
5098c2ecf20Sopenharmony_ci * Allocate a new allocation btree cursor.
5108c2ecf20Sopenharmony_ci */
5118c2ecf20Sopenharmony_cistruct xfs_btree_cur *			/* new alloc btree cursor */
5128c2ecf20Sopenharmony_cixfs_allocbt_init_cursor(
5138c2ecf20Sopenharmony_ci	struct xfs_mount	*mp,		/* file system mount point */
5148c2ecf20Sopenharmony_ci	struct xfs_trans	*tp,		/* transaction pointer */
5158c2ecf20Sopenharmony_ci	struct xfs_buf		*agbp,		/* buffer for agf structure */
5168c2ecf20Sopenharmony_ci	xfs_agnumber_t		agno,		/* allocation group number */
5178c2ecf20Sopenharmony_ci	xfs_btnum_t		btnum)		/* btree identifier */
5188c2ecf20Sopenharmony_ci{
5198c2ecf20Sopenharmony_ci	struct xfs_agf		*agf = agbp->b_addr;
5208c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	cur = xfs_allocbt_init_common(mp, tp, agno, btnum);
5238c2ecf20Sopenharmony_ci	if (btnum == XFS_BTNUM_CNT)
5248c2ecf20Sopenharmony_ci		cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]);
5258c2ecf20Sopenharmony_ci	else
5268c2ecf20Sopenharmony_ci		cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	cur->bc_ag.agbp = agbp;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	return cur;
5318c2ecf20Sopenharmony_ci}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci/* Create a free space btree cursor with a fake root for staging. */
5348c2ecf20Sopenharmony_cistruct xfs_btree_cur *
5358c2ecf20Sopenharmony_cixfs_allocbt_stage_cursor(
5368c2ecf20Sopenharmony_ci	struct xfs_mount	*mp,
5378c2ecf20Sopenharmony_ci	struct xbtree_afakeroot	*afake,
5388c2ecf20Sopenharmony_ci	xfs_agnumber_t		agno,
5398c2ecf20Sopenharmony_ci	xfs_btnum_t		btnum)
5408c2ecf20Sopenharmony_ci{
5418c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	cur = xfs_allocbt_init_common(mp, NULL, agno, btnum);
5448c2ecf20Sopenharmony_ci	xfs_btree_stage_afakeroot(cur, afake);
5458c2ecf20Sopenharmony_ci	return cur;
5468c2ecf20Sopenharmony_ci}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci/*
5498c2ecf20Sopenharmony_ci * Install a new free space btree root.  Caller is responsible for invalidating
5508c2ecf20Sopenharmony_ci * and freeing the old btree blocks.
5518c2ecf20Sopenharmony_ci */
5528c2ecf20Sopenharmony_civoid
5538c2ecf20Sopenharmony_cixfs_allocbt_commit_staged_btree(
5548c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
5558c2ecf20Sopenharmony_ci	struct xfs_trans	*tp,
5568c2ecf20Sopenharmony_ci	struct xfs_buf		*agbp)
5578c2ecf20Sopenharmony_ci{
5588c2ecf20Sopenharmony_ci	struct xfs_agf		*agf = agbp->b_addr;
5598c2ecf20Sopenharmony_ci	struct xbtree_afakeroot	*afake = cur->bc_ag.afake;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	ASSERT(cur->bc_flags & XFS_BTREE_STAGING);
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	agf->agf_roots[cur->bc_btnum] = cpu_to_be32(afake->af_root);
5648c2ecf20Sopenharmony_ci	agf->agf_levels[cur->bc_btnum] = cpu_to_be32(afake->af_levels);
5658c2ecf20Sopenharmony_ci	xfs_alloc_log_agf(tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS);
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	if (cur->bc_btnum == XFS_BTNUM_BNO) {
5688c2ecf20Sopenharmony_ci		xfs_btree_commit_afakeroot(cur, tp, agbp, &xfs_bnobt_ops);
5698c2ecf20Sopenharmony_ci	} else {
5708c2ecf20Sopenharmony_ci		cur->bc_flags |= XFS_BTREE_LASTREC_UPDATE;
5718c2ecf20Sopenharmony_ci		xfs_btree_commit_afakeroot(cur, tp, agbp, &xfs_cntbt_ops);
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci/*
5768c2ecf20Sopenharmony_ci * Calculate number of records in an alloc btree block.
5778c2ecf20Sopenharmony_ci */
5788c2ecf20Sopenharmony_ciint
5798c2ecf20Sopenharmony_cixfs_allocbt_maxrecs(
5808c2ecf20Sopenharmony_ci	struct xfs_mount	*mp,
5818c2ecf20Sopenharmony_ci	int			blocklen,
5828c2ecf20Sopenharmony_ci	int			leaf)
5838c2ecf20Sopenharmony_ci{
5848c2ecf20Sopenharmony_ci	blocklen -= XFS_ALLOC_BLOCK_LEN(mp);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	if (leaf)
5878c2ecf20Sopenharmony_ci		return blocklen / sizeof(xfs_alloc_rec_t);
5888c2ecf20Sopenharmony_ci	return blocklen / (sizeof(xfs_alloc_key_t) + sizeof(xfs_alloc_ptr_t));
5898c2ecf20Sopenharmony_ci}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci/* Calculate the freespace btree size for some records. */
5928c2ecf20Sopenharmony_cixfs_extlen_t
5938c2ecf20Sopenharmony_cixfs_allocbt_calc_size(
5948c2ecf20Sopenharmony_ci	struct xfs_mount	*mp,
5958c2ecf20Sopenharmony_ci	unsigned long long	len)
5968c2ecf20Sopenharmony_ci{
5978c2ecf20Sopenharmony_ci	return xfs_btree_calc_size(mp->m_alloc_mnr, len);
5988c2ecf20Sopenharmony_ci}
599