18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Oracle.  All Rights Reserved.
48c2ecf20Sopenharmony_ci * Author: Darrick J. Wong <darrick.wong@oracle.com>
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_refcount_btree.h"
178c2ecf20Sopenharmony_ci#include "xfs_alloc.h"
188c2ecf20Sopenharmony_ci#include "xfs_error.h"
198c2ecf20Sopenharmony_ci#include "xfs_trace.h"
208c2ecf20Sopenharmony_ci#include "xfs_trans.h"
218c2ecf20Sopenharmony_ci#include "xfs_bit.h"
228c2ecf20Sopenharmony_ci#include "xfs_rmap.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic struct xfs_btree_cur *
258c2ecf20Sopenharmony_cixfs_refcountbt_dup_cursor(
268c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	return xfs_refcountbt_init_cursor(cur->bc_mp, cur->bc_tp,
298c2ecf20Sopenharmony_ci			cur->bc_ag.agbp, cur->bc_ag.agno);
308c2ecf20Sopenharmony_ci}
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ciSTATIC void
338c2ecf20Sopenharmony_cixfs_refcountbt_set_root(
348c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
358c2ecf20Sopenharmony_ci	union xfs_btree_ptr	*ptr,
368c2ecf20Sopenharmony_ci	int			inc)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	struct xfs_buf		*agbp = cur->bc_ag.agbp;
398c2ecf20Sopenharmony_ci	struct xfs_agf		*agf = agbp->b_addr;
408c2ecf20Sopenharmony_ci	struct xfs_perag	*pag = agbp->b_pag;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	ASSERT(ptr->s != 0);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	agf->agf_refcount_root = ptr->s;
458c2ecf20Sopenharmony_ci	be32_add_cpu(&agf->agf_refcount_level, inc);
468c2ecf20Sopenharmony_ci	pag->pagf_refcount_level += inc;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	xfs_alloc_log_agf(cur->bc_tp, agbp,
498c2ecf20Sopenharmony_ci			XFS_AGF_REFCOUNT_ROOT | XFS_AGF_REFCOUNT_LEVEL);
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ciSTATIC int
538c2ecf20Sopenharmony_cixfs_refcountbt_alloc_block(
548c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
558c2ecf20Sopenharmony_ci	union xfs_btree_ptr	*start,
568c2ecf20Sopenharmony_ci	union xfs_btree_ptr	*new,
578c2ecf20Sopenharmony_ci	int			*stat)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	struct xfs_buf		*agbp = cur->bc_ag.agbp;
608c2ecf20Sopenharmony_ci	struct xfs_agf		*agf = agbp->b_addr;
618c2ecf20Sopenharmony_ci	struct xfs_alloc_arg	args;		/* block allocation args */
628c2ecf20Sopenharmony_ci	int			error;		/* error return value */
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	memset(&args, 0, sizeof(args));
658c2ecf20Sopenharmony_ci	args.tp = cur->bc_tp;
668c2ecf20Sopenharmony_ci	args.mp = cur->bc_mp;
678c2ecf20Sopenharmony_ci	args.type = XFS_ALLOCTYPE_NEAR_BNO;
688c2ecf20Sopenharmony_ci	args.fsbno = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.agno,
698c2ecf20Sopenharmony_ci			xfs_refc_block(args.mp));
708c2ecf20Sopenharmony_ci	args.oinfo = XFS_RMAP_OINFO_REFC;
718c2ecf20Sopenharmony_ci	args.minlen = args.maxlen = args.prod = 1;
728c2ecf20Sopenharmony_ci	args.resv = XFS_AG_RESV_METADATA;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	error = xfs_alloc_vextent(&args);
758c2ecf20Sopenharmony_ci	if (error)
768c2ecf20Sopenharmony_ci		goto out_error;
778c2ecf20Sopenharmony_ci	trace_xfs_refcountbt_alloc_block(cur->bc_mp, cur->bc_ag.agno,
788c2ecf20Sopenharmony_ci			args.agbno, 1);
798c2ecf20Sopenharmony_ci	if (args.fsbno == NULLFSBLOCK) {
808c2ecf20Sopenharmony_ci		*stat = 0;
818c2ecf20Sopenharmony_ci		return 0;
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci	ASSERT(args.agno == cur->bc_ag.agno);
848c2ecf20Sopenharmony_ci	ASSERT(args.len == 1);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	new->s = cpu_to_be32(args.agbno);
878c2ecf20Sopenharmony_ci	be32_add_cpu(&agf->agf_refcount_blocks, 1);
888c2ecf20Sopenharmony_ci	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS);
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	*stat = 1;
918c2ecf20Sopenharmony_ci	return 0;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ciout_error:
948c2ecf20Sopenharmony_ci	return error;
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ciSTATIC int
988c2ecf20Sopenharmony_cixfs_refcountbt_free_block(
998c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
1008c2ecf20Sopenharmony_ci	struct xfs_buf		*bp)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	struct xfs_mount	*mp = cur->bc_mp;
1038c2ecf20Sopenharmony_ci	struct xfs_buf		*agbp = cur->bc_ag.agbp;
1048c2ecf20Sopenharmony_ci	struct xfs_agf		*agf = agbp->b_addr;
1058c2ecf20Sopenharmony_ci	xfs_fsblock_t		fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp));
1068c2ecf20Sopenharmony_ci	int			error;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	trace_xfs_refcountbt_free_block(cur->bc_mp, cur->bc_ag.agno,
1098c2ecf20Sopenharmony_ci			XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno), 1);
1108c2ecf20Sopenharmony_ci	be32_add_cpu(&agf->agf_refcount_blocks, -1);
1118c2ecf20Sopenharmony_ci	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS);
1128c2ecf20Sopenharmony_ci	error = xfs_free_extent(cur->bc_tp, fsbno, 1, &XFS_RMAP_OINFO_REFC,
1138c2ecf20Sopenharmony_ci			XFS_AG_RESV_METADATA);
1148c2ecf20Sopenharmony_ci	if (error)
1158c2ecf20Sopenharmony_ci		return error;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	return error;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ciSTATIC int
1218c2ecf20Sopenharmony_cixfs_refcountbt_get_minrecs(
1228c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
1238c2ecf20Sopenharmony_ci	int			level)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	return cur->bc_mp->m_refc_mnr[level != 0];
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ciSTATIC int
1298c2ecf20Sopenharmony_cixfs_refcountbt_get_maxrecs(
1308c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
1318c2ecf20Sopenharmony_ci	int			level)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	return cur->bc_mp->m_refc_mxr[level != 0];
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ciSTATIC void
1378c2ecf20Sopenharmony_cixfs_refcountbt_init_key_from_rec(
1388c2ecf20Sopenharmony_ci	union xfs_btree_key	*key,
1398c2ecf20Sopenharmony_ci	union xfs_btree_rec	*rec)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	key->refc.rc_startblock = rec->refc.rc_startblock;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ciSTATIC void
1458c2ecf20Sopenharmony_cixfs_refcountbt_init_high_key_from_rec(
1468c2ecf20Sopenharmony_ci	union xfs_btree_key	*key,
1478c2ecf20Sopenharmony_ci	union xfs_btree_rec	*rec)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	__u32			x;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	x = be32_to_cpu(rec->refc.rc_startblock);
1528c2ecf20Sopenharmony_ci	x += be32_to_cpu(rec->refc.rc_blockcount) - 1;
1538c2ecf20Sopenharmony_ci	key->refc.rc_startblock = cpu_to_be32(x);
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ciSTATIC void
1578c2ecf20Sopenharmony_cixfs_refcountbt_init_rec_from_cur(
1588c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
1598c2ecf20Sopenharmony_ci	union xfs_btree_rec	*rec)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	rec->refc.rc_startblock = cpu_to_be32(cur->bc_rec.rc.rc_startblock);
1628c2ecf20Sopenharmony_ci	rec->refc.rc_blockcount = cpu_to_be32(cur->bc_rec.rc.rc_blockcount);
1638c2ecf20Sopenharmony_ci	rec->refc.rc_refcount = cpu_to_be32(cur->bc_rec.rc.rc_refcount);
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ciSTATIC void
1678c2ecf20Sopenharmony_cixfs_refcountbt_init_ptr_from_cur(
1688c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
1698c2ecf20Sopenharmony_ci	union xfs_btree_ptr	*ptr)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	struct xfs_agf		*agf = cur->bc_ag.agbp->b_addr;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	ASSERT(cur->bc_ag.agno == be32_to_cpu(agf->agf_seqno));
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	ptr->s = agf->agf_refcount_root;
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ciSTATIC int64_t
1798c2ecf20Sopenharmony_cixfs_refcountbt_key_diff(
1808c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
1818c2ecf20Sopenharmony_ci	union xfs_btree_key	*key)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	struct xfs_refcount_irec	*rec = &cur->bc_rec.rc;
1848c2ecf20Sopenharmony_ci	struct xfs_refcount_key		*kp = &key->refc;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	return (int64_t)be32_to_cpu(kp->rc_startblock) - rec->rc_startblock;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ciSTATIC int64_t
1908c2ecf20Sopenharmony_cixfs_refcountbt_diff_two_keys(
1918c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
1928c2ecf20Sopenharmony_ci	union xfs_btree_key	*k1,
1938c2ecf20Sopenharmony_ci	union xfs_btree_key	*k2)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	return (int64_t)be32_to_cpu(k1->refc.rc_startblock) -
1968c2ecf20Sopenharmony_ci			  be32_to_cpu(k2->refc.rc_startblock);
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ciSTATIC xfs_failaddr_t
2008c2ecf20Sopenharmony_cixfs_refcountbt_verify(
2018c2ecf20Sopenharmony_ci	struct xfs_buf		*bp)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	struct xfs_mount	*mp = bp->b_mount;
2048c2ecf20Sopenharmony_ci	struct xfs_btree_block	*block = XFS_BUF_TO_BLOCK(bp);
2058c2ecf20Sopenharmony_ci	struct xfs_perag	*pag = bp->b_pag;
2068c2ecf20Sopenharmony_ci	xfs_failaddr_t		fa;
2078c2ecf20Sopenharmony_ci	unsigned int		level;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	if (!xfs_verify_magic(bp, block->bb_magic))
2108c2ecf20Sopenharmony_ci		return __this_address;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	if (!xfs_sb_version_hasreflink(&mp->m_sb))
2138c2ecf20Sopenharmony_ci		return __this_address;
2148c2ecf20Sopenharmony_ci	fa = xfs_btree_sblock_v5hdr_verify(bp);
2158c2ecf20Sopenharmony_ci	if (fa)
2168c2ecf20Sopenharmony_ci		return fa;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	level = be16_to_cpu(block->bb_level);
2198c2ecf20Sopenharmony_ci	if (pag && pag->pagf_init) {
2208c2ecf20Sopenharmony_ci		if (level >= pag->pagf_refcount_level)
2218c2ecf20Sopenharmony_ci			return __this_address;
2228c2ecf20Sopenharmony_ci	} else if (level >= mp->m_refc_maxlevels)
2238c2ecf20Sopenharmony_ci		return __this_address;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	return xfs_btree_sblock_verify(bp, mp->m_refc_mxr[level != 0]);
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ciSTATIC void
2298c2ecf20Sopenharmony_cixfs_refcountbt_read_verify(
2308c2ecf20Sopenharmony_ci	struct xfs_buf	*bp)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	xfs_failaddr_t	fa;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	if (!xfs_btree_sblock_verify_crc(bp))
2358c2ecf20Sopenharmony_ci		xfs_verifier_error(bp, -EFSBADCRC, __this_address);
2368c2ecf20Sopenharmony_ci	else {
2378c2ecf20Sopenharmony_ci		fa = xfs_refcountbt_verify(bp);
2388c2ecf20Sopenharmony_ci		if (fa)
2398c2ecf20Sopenharmony_ci			xfs_verifier_error(bp, -EFSCORRUPTED, fa);
2408c2ecf20Sopenharmony_ci	}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	if (bp->b_error)
2438c2ecf20Sopenharmony_ci		trace_xfs_btree_corrupt(bp, _RET_IP_);
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ciSTATIC void
2478c2ecf20Sopenharmony_cixfs_refcountbt_write_verify(
2488c2ecf20Sopenharmony_ci	struct xfs_buf	*bp)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	xfs_failaddr_t	fa;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	fa = xfs_refcountbt_verify(bp);
2538c2ecf20Sopenharmony_ci	if (fa) {
2548c2ecf20Sopenharmony_ci		trace_xfs_btree_corrupt(bp, _RET_IP_);
2558c2ecf20Sopenharmony_ci		xfs_verifier_error(bp, -EFSCORRUPTED, fa);
2568c2ecf20Sopenharmony_ci		return;
2578c2ecf20Sopenharmony_ci	}
2588c2ecf20Sopenharmony_ci	xfs_btree_sblock_calc_crc(bp);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ciconst struct xfs_buf_ops xfs_refcountbt_buf_ops = {
2638c2ecf20Sopenharmony_ci	.name			= "xfs_refcountbt",
2648c2ecf20Sopenharmony_ci	.magic			= { 0, cpu_to_be32(XFS_REFC_CRC_MAGIC) },
2658c2ecf20Sopenharmony_ci	.verify_read		= xfs_refcountbt_read_verify,
2668c2ecf20Sopenharmony_ci	.verify_write		= xfs_refcountbt_write_verify,
2678c2ecf20Sopenharmony_ci	.verify_struct		= xfs_refcountbt_verify,
2688c2ecf20Sopenharmony_ci};
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ciSTATIC int
2718c2ecf20Sopenharmony_cixfs_refcountbt_keys_inorder(
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	return be32_to_cpu(k1->refc.rc_startblock) <
2778c2ecf20Sopenharmony_ci	       be32_to_cpu(k2->refc.rc_startblock);
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ciSTATIC int
2818c2ecf20Sopenharmony_cixfs_refcountbt_recs_inorder(
2828c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
2838c2ecf20Sopenharmony_ci	union xfs_btree_rec	*r1,
2848c2ecf20Sopenharmony_ci	union xfs_btree_rec	*r2)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	return  be32_to_cpu(r1->refc.rc_startblock) +
2878c2ecf20Sopenharmony_ci		be32_to_cpu(r1->refc.rc_blockcount) <=
2888c2ecf20Sopenharmony_ci		be32_to_cpu(r2->refc.rc_startblock);
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic const struct xfs_btree_ops xfs_refcountbt_ops = {
2928c2ecf20Sopenharmony_ci	.rec_len		= sizeof(struct xfs_refcount_rec),
2938c2ecf20Sopenharmony_ci	.key_len		= sizeof(struct xfs_refcount_key),
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	.dup_cursor		= xfs_refcountbt_dup_cursor,
2968c2ecf20Sopenharmony_ci	.set_root		= xfs_refcountbt_set_root,
2978c2ecf20Sopenharmony_ci	.alloc_block		= xfs_refcountbt_alloc_block,
2988c2ecf20Sopenharmony_ci	.free_block		= xfs_refcountbt_free_block,
2998c2ecf20Sopenharmony_ci	.get_minrecs		= xfs_refcountbt_get_minrecs,
3008c2ecf20Sopenharmony_ci	.get_maxrecs		= xfs_refcountbt_get_maxrecs,
3018c2ecf20Sopenharmony_ci	.init_key_from_rec	= xfs_refcountbt_init_key_from_rec,
3028c2ecf20Sopenharmony_ci	.init_high_key_from_rec	= xfs_refcountbt_init_high_key_from_rec,
3038c2ecf20Sopenharmony_ci	.init_rec_from_cur	= xfs_refcountbt_init_rec_from_cur,
3048c2ecf20Sopenharmony_ci	.init_ptr_from_cur	= xfs_refcountbt_init_ptr_from_cur,
3058c2ecf20Sopenharmony_ci	.key_diff		= xfs_refcountbt_key_diff,
3068c2ecf20Sopenharmony_ci	.buf_ops		= &xfs_refcountbt_buf_ops,
3078c2ecf20Sopenharmony_ci	.diff_two_keys		= xfs_refcountbt_diff_two_keys,
3088c2ecf20Sopenharmony_ci	.keys_inorder		= xfs_refcountbt_keys_inorder,
3098c2ecf20Sopenharmony_ci	.recs_inorder		= xfs_refcountbt_recs_inorder,
3108c2ecf20Sopenharmony_ci};
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci/*
3138c2ecf20Sopenharmony_ci * Initialize a new refcount btree cursor.
3148c2ecf20Sopenharmony_ci */
3158c2ecf20Sopenharmony_cistatic struct xfs_btree_cur *
3168c2ecf20Sopenharmony_cixfs_refcountbt_init_common(
3178c2ecf20Sopenharmony_ci	struct xfs_mount	*mp,
3188c2ecf20Sopenharmony_ci	struct xfs_trans	*tp,
3198c2ecf20Sopenharmony_ci	xfs_agnumber_t		agno)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	ASSERT(agno != NULLAGNUMBER);
3248c2ecf20Sopenharmony_ci	ASSERT(agno < mp->m_sb.sb_agcount);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	cur = kmem_cache_zalloc(xfs_btree_cur_zone, GFP_NOFS | __GFP_NOFAIL);
3278c2ecf20Sopenharmony_ci	cur->bc_tp = tp;
3288c2ecf20Sopenharmony_ci	cur->bc_mp = mp;
3298c2ecf20Sopenharmony_ci	cur->bc_btnum = XFS_BTNUM_REFC;
3308c2ecf20Sopenharmony_ci	cur->bc_blocklog = mp->m_sb.sb_blocklog;
3318c2ecf20Sopenharmony_ci	cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_refcbt_2);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	cur->bc_ag.agno = agno;
3348c2ecf20Sopenharmony_ci	cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	cur->bc_ag.refc.nr_ops = 0;
3378c2ecf20Sopenharmony_ci	cur->bc_ag.refc.shape_changes = 0;
3388c2ecf20Sopenharmony_ci	cur->bc_ops = &xfs_refcountbt_ops;
3398c2ecf20Sopenharmony_ci	return cur;
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci/* Create a btree cursor. */
3438c2ecf20Sopenharmony_cistruct xfs_btree_cur *
3448c2ecf20Sopenharmony_cixfs_refcountbt_init_cursor(
3458c2ecf20Sopenharmony_ci	struct xfs_mount	*mp,
3468c2ecf20Sopenharmony_ci	struct xfs_trans	*tp,
3478c2ecf20Sopenharmony_ci	struct xfs_buf		*agbp,
3488c2ecf20Sopenharmony_ci	xfs_agnumber_t		agno)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	struct xfs_agf		*agf = agbp->b_addr;
3518c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	cur = xfs_refcountbt_init_common(mp, tp, agno);
3548c2ecf20Sopenharmony_ci	cur->bc_nlevels = be32_to_cpu(agf->agf_refcount_level);
3558c2ecf20Sopenharmony_ci	cur->bc_ag.agbp = agbp;
3568c2ecf20Sopenharmony_ci	return cur;
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci/* Create a btree cursor with a fake root for staging. */
3608c2ecf20Sopenharmony_cistruct xfs_btree_cur *
3618c2ecf20Sopenharmony_cixfs_refcountbt_stage_cursor(
3628c2ecf20Sopenharmony_ci	struct xfs_mount	*mp,
3638c2ecf20Sopenharmony_ci	struct xbtree_afakeroot	*afake,
3648c2ecf20Sopenharmony_ci	xfs_agnumber_t		agno)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	cur = xfs_refcountbt_init_common(mp, NULL, agno);
3698c2ecf20Sopenharmony_ci	xfs_btree_stage_afakeroot(cur, afake);
3708c2ecf20Sopenharmony_ci	return cur;
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci/*
3748c2ecf20Sopenharmony_ci * Swap in the new btree root.  Once we pass this point the newly rebuilt btree
3758c2ecf20Sopenharmony_ci * is in place and we have to kill off all the old btree blocks.
3768c2ecf20Sopenharmony_ci */
3778c2ecf20Sopenharmony_civoid
3788c2ecf20Sopenharmony_cixfs_refcountbt_commit_staged_btree(
3798c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
3808c2ecf20Sopenharmony_ci	struct xfs_trans	*tp,
3818c2ecf20Sopenharmony_ci	struct xfs_buf		*agbp)
3828c2ecf20Sopenharmony_ci{
3838c2ecf20Sopenharmony_ci	struct xfs_agf		*agf = agbp->b_addr;
3848c2ecf20Sopenharmony_ci	struct xbtree_afakeroot	*afake = cur->bc_ag.afake;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	ASSERT(cur->bc_flags & XFS_BTREE_STAGING);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	agf->agf_refcount_root = cpu_to_be32(afake->af_root);
3898c2ecf20Sopenharmony_ci	agf->agf_refcount_level = cpu_to_be32(afake->af_levels);
3908c2ecf20Sopenharmony_ci	agf->agf_refcount_blocks = cpu_to_be32(afake->af_blocks);
3918c2ecf20Sopenharmony_ci	xfs_alloc_log_agf(tp, agbp, XFS_AGF_REFCOUNT_BLOCKS |
3928c2ecf20Sopenharmony_ci				    XFS_AGF_REFCOUNT_ROOT |
3938c2ecf20Sopenharmony_ci				    XFS_AGF_REFCOUNT_LEVEL);
3948c2ecf20Sopenharmony_ci	xfs_btree_commit_afakeroot(cur, tp, agbp, &xfs_refcountbt_ops);
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci/*
3988c2ecf20Sopenharmony_ci * Calculate the number of records in a refcount btree block.
3998c2ecf20Sopenharmony_ci */
4008c2ecf20Sopenharmony_ciint
4018c2ecf20Sopenharmony_cixfs_refcountbt_maxrecs(
4028c2ecf20Sopenharmony_ci	int			blocklen,
4038c2ecf20Sopenharmony_ci	bool			leaf)
4048c2ecf20Sopenharmony_ci{
4058c2ecf20Sopenharmony_ci	blocklen -= XFS_REFCOUNT_BLOCK_LEN;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	if (leaf)
4088c2ecf20Sopenharmony_ci		return blocklen / sizeof(struct xfs_refcount_rec);
4098c2ecf20Sopenharmony_ci	return blocklen / (sizeof(struct xfs_refcount_key) +
4108c2ecf20Sopenharmony_ci			   sizeof(xfs_refcount_ptr_t));
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci/* Compute the maximum height of a refcount btree. */
4148c2ecf20Sopenharmony_civoid
4158c2ecf20Sopenharmony_cixfs_refcountbt_compute_maxlevels(
4168c2ecf20Sopenharmony_ci	struct xfs_mount		*mp)
4178c2ecf20Sopenharmony_ci{
4188c2ecf20Sopenharmony_ci	mp->m_refc_maxlevels = xfs_btree_compute_maxlevels(
4198c2ecf20Sopenharmony_ci			mp->m_refc_mnr, mp->m_sb.sb_agblocks);
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci/* Calculate the refcount btree size for some records. */
4238c2ecf20Sopenharmony_cixfs_extlen_t
4248c2ecf20Sopenharmony_cixfs_refcountbt_calc_size(
4258c2ecf20Sopenharmony_ci	struct xfs_mount	*mp,
4268c2ecf20Sopenharmony_ci	unsigned long long	len)
4278c2ecf20Sopenharmony_ci{
4288c2ecf20Sopenharmony_ci	return xfs_btree_calc_size(mp->m_refc_mnr, len);
4298c2ecf20Sopenharmony_ci}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci/*
4328c2ecf20Sopenharmony_ci * Calculate the maximum refcount btree size.
4338c2ecf20Sopenharmony_ci */
4348c2ecf20Sopenharmony_cixfs_extlen_t
4358c2ecf20Sopenharmony_cixfs_refcountbt_max_size(
4368c2ecf20Sopenharmony_ci	struct xfs_mount	*mp,
4378c2ecf20Sopenharmony_ci	xfs_agblock_t		agblocks)
4388c2ecf20Sopenharmony_ci{
4398c2ecf20Sopenharmony_ci	/* Bail out if we're uninitialized, which can happen in mkfs. */
4408c2ecf20Sopenharmony_ci	if (mp->m_refc_mxr[0] == 0)
4418c2ecf20Sopenharmony_ci		return 0;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	return xfs_refcountbt_calc_size(mp, agblocks);
4448c2ecf20Sopenharmony_ci}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci/*
4478c2ecf20Sopenharmony_ci * Figure out how many blocks to reserve and how many are used by this btree.
4488c2ecf20Sopenharmony_ci */
4498c2ecf20Sopenharmony_ciint
4508c2ecf20Sopenharmony_cixfs_refcountbt_calc_reserves(
4518c2ecf20Sopenharmony_ci	struct xfs_mount	*mp,
4528c2ecf20Sopenharmony_ci	struct xfs_trans	*tp,
4538c2ecf20Sopenharmony_ci	xfs_agnumber_t		agno,
4548c2ecf20Sopenharmony_ci	xfs_extlen_t		*ask,
4558c2ecf20Sopenharmony_ci	xfs_extlen_t		*used)
4568c2ecf20Sopenharmony_ci{
4578c2ecf20Sopenharmony_ci	struct xfs_buf		*agbp;
4588c2ecf20Sopenharmony_ci	struct xfs_agf		*agf;
4598c2ecf20Sopenharmony_ci	xfs_agblock_t		agblocks;
4608c2ecf20Sopenharmony_ci	xfs_extlen_t		tree_len;
4618c2ecf20Sopenharmony_ci	int			error;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	if (!xfs_sb_version_hasreflink(&mp->m_sb))
4648c2ecf20Sopenharmony_ci		return 0;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
4688c2ecf20Sopenharmony_ci	if (error)
4698c2ecf20Sopenharmony_ci		return error;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	agf = agbp->b_addr;
4728c2ecf20Sopenharmony_ci	agblocks = be32_to_cpu(agf->agf_length);
4738c2ecf20Sopenharmony_ci	tree_len = be32_to_cpu(agf->agf_refcount_blocks);
4748c2ecf20Sopenharmony_ci	xfs_trans_brelse(tp, agbp);
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	/*
4778c2ecf20Sopenharmony_ci	 * The log is permanently allocated, so the space it occupies will
4788c2ecf20Sopenharmony_ci	 * never be available for the kinds of things that would require btree
4798c2ecf20Sopenharmony_ci	 * expansion.  We therefore can pretend the space isn't there.
4808c2ecf20Sopenharmony_ci	 */
4818c2ecf20Sopenharmony_ci	if (mp->m_sb.sb_logstart &&
4828c2ecf20Sopenharmony_ci	    XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == agno)
4838c2ecf20Sopenharmony_ci		agblocks -= mp->m_sb.sb_logblocks;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	*ask += xfs_refcountbt_max_size(mp, agblocks);
4868c2ecf20Sopenharmony_ci	*used += tree_len;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	return error;
4898c2ecf20Sopenharmony_ci}
490