11946b91cSDarrick J. Wong /*
21946b91cSDarrick J. Wong  * Copyright (C) 2016 Oracle.  All Rights Reserved.
31946b91cSDarrick J. Wong  *
41946b91cSDarrick J. Wong  * Author: Darrick J. Wong <darrick.wong@oracle.com>
51946b91cSDarrick J. Wong  *
61946b91cSDarrick J. Wong  * This program is free software; you can redistribute it and/or
71946b91cSDarrick J. Wong  * modify it under the terms of the GNU General Public License
81946b91cSDarrick J. Wong  * as published by the Free Software Foundation; either version 2
91946b91cSDarrick J. Wong  * of the License, or (at your option) any later version.
101946b91cSDarrick J. Wong  *
111946b91cSDarrick J. Wong  * This program is distributed in the hope that it would be useful,
121946b91cSDarrick J. Wong  * but WITHOUT ANY WARRANTY; without even the implied warranty of
131946b91cSDarrick J. Wong  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
141946b91cSDarrick J. Wong  * GNU General Public License for more details.
151946b91cSDarrick J. Wong  *
161946b91cSDarrick J. Wong  * You should have received a copy of the GNU General Public License
171946b91cSDarrick J. Wong  * along with this program; if not, write the Free Software Foundation,
181946b91cSDarrick J. Wong  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
191946b91cSDarrick J. Wong  */
201946b91cSDarrick J. Wong #include "xfs.h"
211946b91cSDarrick J. Wong #include "xfs_fs.h"
221946b91cSDarrick J. Wong #include "xfs_shared.h"
231946b91cSDarrick J. Wong #include "xfs_format.h"
241946b91cSDarrick J. Wong #include "xfs_log_format.h"
251946b91cSDarrick J. Wong #include "xfs_trans_resv.h"
261946b91cSDarrick J. Wong #include "xfs_sb.h"
271946b91cSDarrick J. Wong #include "xfs_mount.h"
281946b91cSDarrick J. Wong #include "xfs_btree.h"
291946b91cSDarrick J. Wong #include "xfs_bmap.h"
301946b91cSDarrick J. Wong #include "xfs_refcount_btree.h"
311946b91cSDarrick J. Wong #include "xfs_alloc.h"
321946b91cSDarrick J. Wong #include "xfs_error.h"
331946b91cSDarrick J. Wong #include "xfs_trace.h"
341946b91cSDarrick J. Wong #include "xfs_cksum.h"
351946b91cSDarrick J. Wong #include "xfs_trans.h"
361946b91cSDarrick J. Wong #include "xfs_bit.h"
37bdf28630SDarrick J. Wong #include "xfs_rmap.h"
381946b91cSDarrick J. Wong 
391946b91cSDarrick J. Wong static struct xfs_btree_cur *
401946b91cSDarrick J. Wong xfs_refcountbt_dup_cursor(
411946b91cSDarrick J. Wong 	struct xfs_btree_cur	*cur)
421946b91cSDarrick J. Wong {
431946b91cSDarrick J. Wong 	return xfs_refcountbt_init_cursor(cur->bc_mp, cur->bc_tp,
441946b91cSDarrick J. Wong 			cur->bc_private.a.agbp, cur->bc_private.a.agno,
451946b91cSDarrick J. Wong 			cur->bc_private.a.dfops);
461946b91cSDarrick J. Wong }
471946b91cSDarrick J. Wong 
48bdf28630SDarrick J. Wong STATIC void
49bdf28630SDarrick J. Wong xfs_refcountbt_set_root(
50bdf28630SDarrick J. Wong 	struct xfs_btree_cur	*cur,
51bdf28630SDarrick J. Wong 	union xfs_btree_ptr	*ptr,
52bdf28630SDarrick J. Wong 	int			inc)
53bdf28630SDarrick J. Wong {
54bdf28630SDarrick J. Wong 	struct xfs_buf		*agbp = cur->bc_private.a.agbp;
55bdf28630SDarrick J. Wong 	struct xfs_agf		*agf = XFS_BUF_TO_AGF(agbp);
56bdf28630SDarrick J. Wong 	xfs_agnumber_t		seqno = be32_to_cpu(agf->agf_seqno);
57bdf28630SDarrick J. Wong 	struct xfs_perag	*pag = xfs_perag_get(cur->bc_mp, seqno);
58bdf28630SDarrick J. Wong 
59bdf28630SDarrick J. Wong 	ASSERT(ptr->s != 0);
60bdf28630SDarrick J. Wong 
61bdf28630SDarrick J. Wong 	agf->agf_refcount_root = ptr->s;
62bdf28630SDarrick J. Wong 	be32_add_cpu(&agf->agf_refcount_level, inc);
63bdf28630SDarrick J. Wong 	pag->pagf_refcount_level += inc;
64bdf28630SDarrick J. Wong 	xfs_perag_put(pag);
65bdf28630SDarrick J. Wong 
66bdf28630SDarrick J. Wong 	xfs_alloc_log_agf(cur->bc_tp, agbp,
67bdf28630SDarrick J. Wong 			XFS_AGF_REFCOUNT_ROOT | XFS_AGF_REFCOUNT_LEVEL);
68bdf28630SDarrick J. Wong }
69bdf28630SDarrick J. Wong 
70bdf28630SDarrick J. Wong STATIC int
71bdf28630SDarrick J. Wong xfs_refcountbt_alloc_block(
72bdf28630SDarrick J. Wong 	struct xfs_btree_cur	*cur,
73bdf28630SDarrick J. Wong 	union xfs_btree_ptr	*start,
74bdf28630SDarrick J. Wong 	union xfs_btree_ptr	*new,
75bdf28630SDarrick J. Wong 	int			*stat)
76bdf28630SDarrick J. Wong {
77bdf28630SDarrick J. Wong 	struct xfs_buf		*agbp = cur->bc_private.a.agbp;
78bdf28630SDarrick J. Wong 	struct xfs_agf		*agf = XFS_BUF_TO_AGF(agbp);
79bdf28630SDarrick J. Wong 	struct xfs_alloc_arg	args;		/* block allocation args */
80bdf28630SDarrick J. Wong 	int			error;		/* error return value */
81bdf28630SDarrick J. Wong 
8284d69619SDarrick J. Wong 	XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
8384d69619SDarrick J. Wong 
84bdf28630SDarrick J. Wong 	memset(&args, 0, sizeof(args));
85bdf28630SDarrick J. Wong 	args.tp = cur->bc_tp;
86bdf28630SDarrick J. Wong 	args.mp = cur->bc_mp;
87bdf28630SDarrick J. Wong 	args.type = XFS_ALLOCTYPE_NEAR_BNO;
88bdf28630SDarrick J. Wong 	args.fsbno = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_private.a.agno,
89bdf28630SDarrick J. Wong 			xfs_refc_block(args.mp));
90bdf28630SDarrick J. Wong 	args.firstblock = args.fsbno;
91bdf28630SDarrick J. Wong 	xfs_rmap_ag_owner(&args.oinfo, XFS_RMAP_OWN_REFC);
92bdf28630SDarrick J. Wong 	args.minlen = args.maxlen = args.prod = 1;
9384d69619SDarrick J. Wong 	args.resv = XFS_AG_RESV_METADATA;
94bdf28630SDarrick J. Wong 
95bdf28630SDarrick J. Wong 	error = xfs_alloc_vextent(&args);
96bdf28630SDarrick J. Wong 	if (error)
97bdf28630SDarrick J. Wong 		goto out_error;
98bdf28630SDarrick J. Wong 	trace_xfs_refcountbt_alloc_block(cur->bc_mp, cur->bc_private.a.agno,
99bdf28630SDarrick J. Wong 			args.agbno, 1);
100bdf28630SDarrick J. Wong 	if (args.fsbno == NULLFSBLOCK) {
101bdf28630SDarrick J. Wong 		XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
102bdf28630SDarrick J. Wong 		*stat = 0;
103bdf28630SDarrick J. Wong 		return 0;
104bdf28630SDarrick J. Wong 	}
105bdf28630SDarrick J. Wong 	ASSERT(args.agno == cur->bc_private.a.agno);
106bdf28630SDarrick J. Wong 	ASSERT(args.len == 1);
107bdf28630SDarrick J. Wong 
108bdf28630SDarrick J. Wong 	new->s = cpu_to_be32(args.agbno);
109bdf28630SDarrick J. Wong 	be32_add_cpu(&agf->agf_refcount_blocks, 1);
110bdf28630SDarrick J. Wong 	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS);
111bdf28630SDarrick J. Wong 
112bdf28630SDarrick J. Wong 	XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
113bdf28630SDarrick J. Wong 	*stat = 1;
114bdf28630SDarrick J. Wong 	return 0;
115bdf28630SDarrick J. Wong 
116bdf28630SDarrick J. Wong out_error:
117bdf28630SDarrick J. Wong 	XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
118bdf28630SDarrick J. Wong 	return error;
119bdf28630SDarrick J. Wong }
120bdf28630SDarrick J. Wong 
121bdf28630SDarrick J. Wong STATIC int
122bdf28630SDarrick J. Wong xfs_refcountbt_free_block(
123bdf28630SDarrick J. Wong 	struct xfs_btree_cur	*cur,
124bdf28630SDarrick J. Wong 	struct xfs_buf		*bp)
125bdf28630SDarrick J. Wong {
126bdf28630SDarrick J. Wong 	struct xfs_mount	*mp = cur->bc_mp;
127bdf28630SDarrick J. Wong 	struct xfs_buf		*agbp = cur->bc_private.a.agbp;
128bdf28630SDarrick J. Wong 	struct xfs_agf		*agf = XFS_BUF_TO_AGF(agbp);
129bdf28630SDarrick J. Wong 	xfs_fsblock_t		fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp));
130bdf28630SDarrick J. Wong 	struct xfs_owner_info	oinfo;
13184d69619SDarrick J. Wong 	int			error;
132bdf28630SDarrick J. Wong 
133bdf28630SDarrick J. Wong 	trace_xfs_refcountbt_free_block(cur->bc_mp, cur->bc_private.a.agno,
134bdf28630SDarrick J. Wong 			XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno), 1);
135bdf28630SDarrick J. Wong 	xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_REFC);
136bdf28630SDarrick J. Wong 	be32_add_cpu(&agf->agf_refcount_blocks, -1);
137bdf28630SDarrick J. Wong 	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS);
13884d69619SDarrick J. Wong 	error = xfs_free_extent(cur->bc_tp, fsbno, 1, &oinfo,
13984d69619SDarrick J. Wong 			XFS_AG_RESV_METADATA);
14084d69619SDarrick J. Wong 	if (error)
14184d69619SDarrick J. Wong 		return error;
142bdf28630SDarrick J. Wong 
14384d69619SDarrick J. Wong 	return error;
144bdf28630SDarrick J. Wong }
145bdf28630SDarrick J. Wong 
146bdf28630SDarrick J. Wong STATIC int
147bdf28630SDarrick J. Wong xfs_refcountbt_get_minrecs(
148bdf28630SDarrick J. Wong 	struct xfs_btree_cur	*cur,
149bdf28630SDarrick J. Wong 	int			level)
150bdf28630SDarrick J. Wong {
151bdf28630SDarrick J. Wong 	return cur->bc_mp->m_refc_mnr[level != 0];
152bdf28630SDarrick J. Wong }
153bdf28630SDarrick J. Wong 
154bdf28630SDarrick J. Wong STATIC int
155bdf28630SDarrick J. Wong xfs_refcountbt_get_maxrecs(
156bdf28630SDarrick J. Wong 	struct xfs_btree_cur	*cur,
157bdf28630SDarrick J. Wong 	int			level)
158bdf28630SDarrick J. Wong {
159bdf28630SDarrick J. Wong 	return cur->bc_mp->m_refc_mxr[level != 0];
160bdf28630SDarrick J. Wong }
161bdf28630SDarrick J. Wong 
162bdf28630SDarrick J. Wong STATIC void
163bdf28630SDarrick J. Wong xfs_refcountbt_init_key_from_rec(
164bdf28630SDarrick J. Wong 	union xfs_btree_key	*key,
165bdf28630SDarrick J. Wong 	union xfs_btree_rec	*rec)
166bdf28630SDarrick J. Wong {
167bdf28630SDarrick J. Wong 	key->refc.rc_startblock = rec->refc.rc_startblock;
168bdf28630SDarrick J. Wong }
169bdf28630SDarrick J. Wong 
170bdf28630SDarrick J. Wong STATIC void
171bdf28630SDarrick J. Wong xfs_refcountbt_init_high_key_from_rec(
172bdf28630SDarrick J. Wong 	union xfs_btree_key	*key,
173bdf28630SDarrick J. Wong 	union xfs_btree_rec	*rec)
174bdf28630SDarrick J. Wong {
175bdf28630SDarrick J. Wong 	__u32			x;
176bdf28630SDarrick J. Wong 
177bdf28630SDarrick J. Wong 	x = be32_to_cpu(rec->refc.rc_startblock);
178bdf28630SDarrick J. Wong 	x += be32_to_cpu(rec->refc.rc_blockcount) - 1;
179bdf28630SDarrick J. Wong 	key->refc.rc_startblock = cpu_to_be32(x);
180bdf28630SDarrick J. Wong }
181bdf28630SDarrick J. Wong 
182bdf28630SDarrick J. Wong STATIC void
183bdf28630SDarrick J. Wong xfs_refcountbt_init_rec_from_cur(
184bdf28630SDarrick J. Wong 	struct xfs_btree_cur	*cur,
185bdf28630SDarrick J. Wong 	union xfs_btree_rec	*rec)
186bdf28630SDarrick J. Wong {
187bdf28630SDarrick J. Wong 	rec->refc.rc_startblock = cpu_to_be32(cur->bc_rec.rc.rc_startblock);
188bdf28630SDarrick J. Wong 	rec->refc.rc_blockcount = cpu_to_be32(cur->bc_rec.rc.rc_blockcount);
189bdf28630SDarrick J. Wong 	rec->refc.rc_refcount = cpu_to_be32(cur->bc_rec.rc.rc_refcount);
190bdf28630SDarrick J. Wong }
191bdf28630SDarrick J. Wong 
192bdf28630SDarrick J. Wong STATIC void
193bdf28630SDarrick J. Wong xfs_refcountbt_init_ptr_from_cur(
194bdf28630SDarrick J. Wong 	struct xfs_btree_cur	*cur,
195bdf28630SDarrick J. Wong 	union xfs_btree_ptr	*ptr)
196bdf28630SDarrick J. Wong {
197bdf28630SDarrick J. Wong 	struct xfs_agf		*agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp);
198bdf28630SDarrick J. Wong 
199bdf28630SDarrick J. Wong 	ASSERT(cur->bc_private.a.agno == be32_to_cpu(agf->agf_seqno));
200bdf28630SDarrick J. Wong 	ASSERT(agf->agf_refcount_root != 0);
201bdf28630SDarrick J. Wong 
202bdf28630SDarrick J. Wong 	ptr->s = agf->agf_refcount_root;
203bdf28630SDarrick J. Wong }
204bdf28630SDarrick J. Wong 
205c8ce540dSDarrick J. Wong STATIC int64_t
206bdf28630SDarrick J. Wong xfs_refcountbt_key_diff(
207bdf28630SDarrick J. Wong 	struct xfs_btree_cur	*cur,
208bdf28630SDarrick J. Wong 	union xfs_btree_key	*key)
209bdf28630SDarrick J. Wong {
210bdf28630SDarrick J. Wong 	struct xfs_refcount_irec	*rec = &cur->bc_rec.rc;
211bdf28630SDarrick J. Wong 	struct xfs_refcount_key		*kp = &key->refc;
212bdf28630SDarrick J. Wong 
213c8ce540dSDarrick J. Wong 	return (int64_t)be32_to_cpu(kp->rc_startblock) - rec->rc_startblock;
214bdf28630SDarrick J. Wong }
215bdf28630SDarrick J. Wong 
216c8ce540dSDarrick J. Wong STATIC int64_t
217bdf28630SDarrick J. Wong xfs_refcountbt_diff_two_keys(
218bdf28630SDarrick J. Wong 	struct xfs_btree_cur	*cur,
219bdf28630SDarrick J. Wong 	union xfs_btree_key	*k1,
220bdf28630SDarrick J. Wong 	union xfs_btree_key	*k2)
221bdf28630SDarrick J. Wong {
222c8ce540dSDarrick J. Wong 	return (int64_t)be32_to_cpu(k1->refc.rc_startblock) -
223bdf28630SDarrick J. Wong 			  be32_to_cpu(k2->refc.rc_startblock);
224bdf28630SDarrick J. Wong }
225bdf28630SDarrick J. Wong 
2261946b91cSDarrick J. Wong STATIC bool
2271946b91cSDarrick J. Wong xfs_refcountbt_verify(
2281946b91cSDarrick J. Wong 	struct xfs_buf		*bp)
2291946b91cSDarrick J. Wong {
2301946b91cSDarrick J. Wong 	struct xfs_mount	*mp = bp->b_target->bt_mount;
2311946b91cSDarrick J. Wong 	struct xfs_btree_block	*block = XFS_BUF_TO_BLOCK(bp);
2321946b91cSDarrick J. Wong 	struct xfs_perag	*pag = bp->b_pag;
2331946b91cSDarrick J. Wong 	unsigned int		level;
2341946b91cSDarrick J. Wong 
2351946b91cSDarrick J. Wong 	if (block->bb_magic != cpu_to_be32(XFS_REFC_CRC_MAGIC))
2361946b91cSDarrick J. Wong 		return false;
2371946b91cSDarrick J. Wong 
2381946b91cSDarrick J. Wong 	if (!xfs_sb_version_hasreflink(&mp->m_sb))
2391946b91cSDarrick J. Wong 		return false;
2401946b91cSDarrick J. Wong 	if (!xfs_btree_sblock_v5hdr_verify(bp))
2411946b91cSDarrick J. Wong 		return false;
2421946b91cSDarrick J. Wong 
2431946b91cSDarrick J. Wong 	level = be16_to_cpu(block->bb_level);
2441946b91cSDarrick J. Wong 	if (pag && pag->pagf_init) {
2451946b91cSDarrick J. Wong 		if (level >= pag->pagf_refcount_level)
2461946b91cSDarrick J. Wong 			return false;
2471946b91cSDarrick J. Wong 	} else if (level >= mp->m_refc_maxlevels)
2481946b91cSDarrick J. Wong 		return false;
2491946b91cSDarrick J. Wong 
2501946b91cSDarrick J. Wong 	return xfs_btree_sblock_verify(bp, mp->m_refc_mxr[level != 0]);
2511946b91cSDarrick J. Wong }
2521946b91cSDarrick J. Wong 
2531946b91cSDarrick J. Wong STATIC void
2541946b91cSDarrick J. Wong xfs_refcountbt_read_verify(
2551946b91cSDarrick J. Wong 	struct xfs_buf	*bp)
2561946b91cSDarrick J. Wong {
2571946b91cSDarrick J. Wong 	if (!xfs_btree_sblock_verify_crc(bp))
2581946b91cSDarrick J. Wong 		xfs_buf_ioerror(bp, -EFSBADCRC);
2591946b91cSDarrick J. Wong 	else if (!xfs_refcountbt_verify(bp))
2601946b91cSDarrick J. Wong 		xfs_buf_ioerror(bp, -EFSCORRUPTED);
2611946b91cSDarrick J. Wong 
2621946b91cSDarrick J. Wong 	if (bp->b_error) {
2631946b91cSDarrick J. Wong 		trace_xfs_btree_corrupt(bp, _RET_IP_);
2641946b91cSDarrick J. Wong 		xfs_verifier_error(bp);
2651946b91cSDarrick J. Wong 	}
2661946b91cSDarrick J. Wong }
2671946b91cSDarrick J. Wong 
2681946b91cSDarrick J. Wong STATIC void
2691946b91cSDarrick J. Wong xfs_refcountbt_write_verify(
2701946b91cSDarrick J. Wong 	struct xfs_buf	*bp)
2711946b91cSDarrick J. Wong {
2721946b91cSDarrick J. Wong 	if (!xfs_refcountbt_verify(bp)) {
2731946b91cSDarrick J. Wong 		trace_xfs_btree_corrupt(bp, _RET_IP_);
2741946b91cSDarrick J. Wong 		xfs_buf_ioerror(bp, -EFSCORRUPTED);
2751946b91cSDarrick J. Wong 		xfs_verifier_error(bp);
2761946b91cSDarrick J. Wong 		return;
2771946b91cSDarrick J. Wong 	}
2781946b91cSDarrick J. Wong 	xfs_btree_sblock_calc_crc(bp);
2791946b91cSDarrick J. Wong 
2801946b91cSDarrick J. Wong }
2811946b91cSDarrick J. Wong 
2821946b91cSDarrick J. Wong const struct xfs_buf_ops xfs_refcountbt_buf_ops = {
2831946b91cSDarrick J. Wong 	.name			= "xfs_refcountbt",
2841946b91cSDarrick J. Wong 	.verify_read		= xfs_refcountbt_read_verify,
2851946b91cSDarrick J. Wong 	.verify_write		= xfs_refcountbt_write_verify,
2861946b91cSDarrick J. Wong };
2871946b91cSDarrick J. Wong 
288bdf28630SDarrick J. Wong #if defined(DEBUG) || defined(XFS_WARN)
289bdf28630SDarrick J. Wong STATIC int
290bdf28630SDarrick J. Wong xfs_refcountbt_keys_inorder(
291bdf28630SDarrick J. Wong 	struct xfs_btree_cur	*cur,
292bdf28630SDarrick J. Wong 	union xfs_btree_key	*k1,
293bdf28630SDarrick J. Wong 	union xfs_btree_key	*k2)
294bdf28630SDarrick J. Wong {
295bdf28630SDarrick J. Wong 	return be32_to_cpu(k1->refc.rc_startblock) <
296bdf28630SDarrick J. Wong 	       be32_to_cpu(k2->refc.rc_startblock);
297bdf28630SDarrick J. Wong }
298bdf28630SDarrick J. Wong 
299bdf28630SDarrick J. Wong STATIC int
300bdf28630SDarrick J. Wong xfs_refcountbt_recs_inorder(
301bdf28630SDarrick J. Wong 	struct xfs_btree_cur	*cur,
302bdf28630SDarrick J. Wong 	union xfs_btree_rec	*r1,
303bdf28630SDarrick J. Wong 	union xfs_btree_rec	*r2)
304bdf28630SDarrick J. Wong {
305bdf28630SDarrick J. Wong 	return  be32_to_cpu(r1->refc.rc_startblock) +
306bdf28630SDarrick J. Wong 		be32_to_cpu(r1->refc.rc_blockcount) <=
307bdf28630SDarrick J. Wong 		be32_to_cpu(r2->refc.rc_startblock);
308bdf28630SDarrick J. Wong }
309bdf28630SDarrick J. Wong #endif
310bdf28630SDarrick J. Wong 
3111946b91cSDarrick J. Wong static const struct xfs_btree_ops xfs_refcountbt_ops = {
3121946b91cSDarrick J. Wong 	.rec_len		= sizeof(struct xfs_refcount_rec),
3131946b91cSDarrick J. Wong 	.key_len		= sizeof(struct xfs_refcount_key),
3141946b91cSDarrick J. Wong 
3151946b91cSDarrick J. Wong 	.dup_cursor		= xfs_refcountbt_dup_cursor,
316bdf28630SDarrick J. Wong 	.set_root		= xfs_refcountbt_set_root,
317bdf28630SDarrick J. Wong 	.alloc_block		= xfs_refcountbt_alloc_block,
318bdf28630SDarrick J. Wong 	.free_block		= xfs_refcountbt_free_block,
319bdf28630SDarrick J. Wong 	.get_minrecs		= xfs_refcountbt_get_minrecs,
320bdf28630SDarrick J. Wong 	.get_maxrecs		= xfs_refcountbt_get_maxrecs,
321bdf28630SDarrick J. Wong 	.init_key_from_rec	= xfs_refcountbt_init_key_from_rec,
322bdf28630SDarrick J. Wong 	.init_high_key_from_rec	= xfs_refcountbt_init_high_key_from_rec,
323bdf28630SDarrick J. Wong 	.init_rec_from_cur	= xfs_refcountbt_init_rec_from_cur,
324bdf28630SDarrick J. Wong 	.init_ptr_from_cur	= xfs_refcountbt_init_ptr_from_cur,
325bdf28630SDarrick J. Wong 	.key_diff		= xfs_refcountbt_key_diff,
3261946b91cSDarrick J. Wong 	.buf_ops		= &xfs_refcountbt_buf_ops,
327bdf28630SDarrick J. Wong 	.diff_two_keys		= xfs_refcountbt_diff_two_keys,
328bdf28630SDarrick J. Wong #if defined(DEBUG) || defined(XFS_WARN)
329bdf28630SDarrick J. Wong 	.keys_inorder		= xfs_refcountbt_keys_inorder,
330bdf28630SDarrick J. Wong 	.recs_inorder		= xfs_refcountbt_recs_inorder,
331bdf28630SDarrick J. Wong #endif
3321946b91cSDarrick J. Wong };
3331946b91cSDarrick J. Wong 
3341946b91cSDarrick J. Wong /*
3351946b91cSDarrick J. Wong  * Allocate a new refcount btree cursor.
3361946b91cSDarrick J. Wong  */
3371946b91cSDarrick J. Wong struct xfs_btree_cur *
3381946b91cSDarrick J. Wong xfs_refcountbt_init_cursor(
3391946b91cSDarrick J. Wong 	struct xfs_mount	*mp,
3401946b91cSDarrick J. Wong 	struct xfs_trans	*tp,
3411946b91cSDarrick J. Wong 	struct xfs_buf		*agbp,
3421946b91cSDarrick J. Wong 	xfs_agnumber_t		agno,
3431946b91cSDarrick J. Wong 	struct xfs_defer_ops	*dfops)
3441946b91cSDarrick J. Wong {
3451946b91cSDarrick J. Wong 	struct xfs_agf		*agf = XFS_BUF_TO_AGF(agbp);
3461946b91cSDarrick J. Wong 	struct xfs_btree_cur	*cur;
3471946b91cSDarrick J. Wong 
3481946b91cSDarrick J. Wong 	ASSERT(agno != NULLAGNUMBER);
3491946b91cSDarrick J. Wong 	ASSERT(agno < mp->m_sb.sb_agcount);
3501946b91cSDarrick J. Wong 	cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_NOFS);
3511946b91cSDarrick J. Wong 
3521946b91cSDarrick J. Wong 	cur->bc_tp = tp;
3531946b91cSDarrick J. Wong 	cur->bc_mp = mp;
3541946b91cSDarrick J. Wong 	cur->bc_btnum = XFS_BTNUM_REFC;
3551946b91cSDarrick J. Wong 	cur->bc_blocklog = mp->m_sb.sb_blocklog;
3561946b91cSDarrick J. Wong 	cur->bc_ops = &xfs_refcountbt_ops;
35711ef38afSDave Chinner 	cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_refcbt_2);
3581946b91cSDarrick J. Wong 
3591946b91cSDarrick J. Wong 	cur->bc_nlevels = be32_to_cpu(agf->agf_refcount_level);
3601946b91cSDarrick J. Wong 
3611946b91cSDarrick J. Wong 	cur->bc_private.a.agbp = agbp;
3621946b91cSDarrick J. Wong 	cur->bc_private.a.agno = agno;
3631946b91cSDarrick J. Wong 	cur->bc_private.a.dfops = dfops;
3641946b91cSDarrick J. Wong 	cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
3651946b91cSDarrick J. Wong 
3661946b91cSDarrick J. Wong 	cur->bc_private.a.priv.refc.nr_ops = 0;
3671946b91cSDarrick J. Wong 	cur->bc_private.a.priv.refc.shape_changes = 0;
3681946b91cSDarrick J. Wong 
3691946b91cSDarrick J. Wong 	return cur;
3701946b91cSDarrick J. Wong }
3711946b91cSDarrick J. Wong 
3721946b91cSDarrick J. Wong /*
3731946b91cSDarrick J. Wong  * Calculate the number of records in a refcount btree block.
3741946b91cSDarrick J. Wong  */
3751946b91cSDarrick J. Wong int
3761946b91cSDarrick J. Wong xfs_refcountbt_maxrecs(
3771946b91cSDarrick J. Wong 	struct xfs_mount	*mp,
3781946b91cSDarrick J. Wong 	int			blocklen,
3791946b91cSDarrick J. Wong 	bool			leaf)
3801946b91cSDarrick J. Wong {
3811946b91cSDarrick J. Wong 	blocklen -= XFS_REFCOUNT_BLOCK_LEN;
3821946b91cSDarrick J. Wong 
3831946b91cSDarrick J. Wong 	if (leaf)
3841946b91cSDarrick J. Wong 		return blocklen / sizeof(struct xfs_refcount_rec);
3851946b91cSDarrick J. Wong 	return blocklen / (sizeof(struct xfs_refcount_key) +
3861946b91cSDarrick J. Wong 			   sizeof(xfs_refcount_ptr_t));
3871946b91cSDarrick J. Wong }
3881946b91cSDarrick J. Wong 
3891946b91cSDarrick J. Wong /* Compute the maximum height of a refcount btree. */
3901946b91cSDarrick J. Wong void
3911946b91cSDarrick J. Wong xfs_refcountbt_compute_maxlevels(
3921946b91cSDarrick J. Wong 	struct xfs_mount		*mp)
3931946b91cSDarrick J. Wong {
3941946b91cSDarrick J. Wong 	mp->m_refc_maxlevels = xfs_btree_compute_maxlevels(mp,
3951946b91cSDarrick J. Wong 			mp->m_refc_mnr, mp->m_sb.sb_agblocks);
3961946b91cSDarrick J. Wong }
39784d69619SDarrick J. Wong 
39884d69619SDarrick J. Wong /* Calculate the refcount btree size for some records. */
39984d69619SDarrick J. Wong xfs_extlen_t
40084d69619SDarrick J. Wong xfs_refcountbt_calc_size(
40184d69619SDarrick J. Wong 	struct xfs_mount	*mp,
40284d69619SDarrick J. Wong 	unsigned long long	len)
40384d69619SDarrick J. Wong {
40484d69619SDarrick J. Wong 	return xfs_btree_calc_size(mp, mp->m_refc_mnr, len);
40584d69619SDarrick J. Wong }
40684d69619SDarrick J. Wong 
40784d69619SDarrick J. Wong /*
40884d69619SDarrick J. Wong  * Calculate the maximum refcount btree size.
40984d69619SDarrick J. Wong  */
41084d69619SDarrick J. Wong xfs_extlen_t
41184d69619SDarrick J. Wong xfs_refcountbt_max_size(
41220e73b00SDarrick J. Wong 	struct xfs_mount	*mp,
41320e73b00SDarrick J. Wong 	xfs_agblock_t		agblocks)
41484d69619SDarrick J. Wong {
41584d69619SDarrick J. Wong 	/* Bail out if we're uninitialized, which can happen in mkfs. */
41684d69619SDarrick J. Wong 	if (mp->m_refc_mxr[0] == 0)
41784d69619SDarrick J. Wong 		return 0;
41884d69619SDarrick J. Wong 
41920e73b00SDarrick J. Wong 	return xfs_refcountbt_calc_size(mp, agblocks);
42084d69619SDarrick J. Wong }
42184d69619SDarrick J. Wong 
42284d69619SDarrick J. Wong /*
42384d69619SDarrick J. Wong  * Figure out how many blocks to reserve and how many are used by this btree.
42484d69619SDarrick J. Wong  */
42584d69619SDarrick J. Wong int
42684d69619SDarrick J. Wong xfs_refcountbt_calc_reserves(
42784d69619SDarrick J. Wong 	struct xfs_mount	*mp,
42884d69619SDarrick J. Wong 	xfs_agnumber_t		agno,
42984d69619SDarrick J. Wong 	xfs_extlen_t		*ask,
43084d69619SDarrick J. Wong 	xfs_extlen_t		*used)
43184d69619SDarrick J. Wong {
43284d69619SDarrick J. Wong 	struct xfs_buf		*agbp;
43384d69619SDarrick J. Wong 	struct xfs_agf		*agf;
43420e73b00SDarrick J. Wong 	xfs_agblock_t		agblocks;
43584d69619SDarrick J. Wong 	xfs_extlen_t		tree_len;
43684d69619SDarrick J. Wong 	int			error;
43784d69619SDarrick J. Wong 
43884d69619SDarrick J. Wong 	if (!xfs_sb_version_hasreflink(&mp->m_sb))
43984d69619SDarrick J. Wong 		return 0;
44084d69619SDarrick J. Wong 
44184d69619SDarrick J. Wong 
44284d69619SDarrick J. Wong 	error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp);
44384d69619SDarrick J. Wong 	if (error)
44484d69619SDarrick J. Wong 		return error;
44584d69619SDarrick J. Wong 
44684d69619SDarrick J. Wong 	agf = XFS_BUF_TO_AGF(agbp);
44720e73b00SDarrick J. Wong 	agblocks = be32_to_cpu(agf->agf_length);
44884d69619SDarrick J. Wong 	tree_len = be32_to_cpu(agf->agf_refcount_blocks);
44984d69619SDarrick J. Wong 	xfs_buf_relse(agbp);
45084d69619SDarrick J. Wong 
45120e73b00SDarrick J. Wong 	*ask += xfs_refcountbt_max_size(mp, agblocks);
45284d69619SDarrick J. Wong 	*used += tree_len;
45384d69619SDarrick J. Wong 
45484d69619SDarrick J. Wong 	return error;
45584d69619SDarrick J. Wong }
456