xref: /linux/fs/xfs/libxfs/xfs_rtrmap_btree.c (revision d386b4024372ea2f06aaa0f2c6c380b45ba0536e)
1fc6856c6SDarrick J. Wong // SPDX-License-Identifier: GPL-2.0-or-later
2fc6856c6SDarrick J. Wong /*
3fc6856c6SDarrick J. Wong  * Copyright (c) 2018-2024 Oracle.  All Rights Reserved.
4fc6856c6SDarrick J. Wong  * Author: Darrick J. Wong <djwong@kernel.org>
5fc6856c6SDarrick J. Wong  */
6fc6856c6SDarrick J. Wong #include "xfs.h"
7fc6856c6SDarrick J. Wong #include "xfs_fs.h"
8fc6856c6SDarrick J. Wong #include "xfs_shared.h"
9fc6856c6SDarrick J. Wong #include "xfs_format.h"
10fc6856c6SDarrick J. Wong #include "xfs_log_format.h"
11fc6856c6SDarrick J. Wong #include "xfs_trans_resv.h"
12fc6856c6SDarrick J. Wong #include "xfs_bit.h"
13fc6856c6SDarrick J. Wong #include "xfs_sb.h"
14fc6856c6SDarrick J. Wong #include "xfs_mount.h"
15fc6856c6SDarrick J. Wong #include "xfs_defer.h"
16fc6856c6SDarrick J. Wong #include "xfs_inode.h"
17fc6856c6SDarrick J. Wong #include "xfs_trans.h"
18fc6856c6SDarrick J. Wong #include "xfs_alloc.h"
19fc6856c6SDarrick J. Wong #include "xfs_btree.h"
20fc6856c6SDarrick J. Wong #include "xfs_btree_staging.h"
21*d386b402SDarrick J. Wong #include "xfs_rmap.h"
22fc6856c6SDarrick J. Wong #include "xfs_rtrmap_btree.h"
23fc6856c6SDarrick J. Wong #include "xfs_trace.h"
24fc6856c6SDarrick J. Wong #include "xfs_cksum.h"
25fc6856c6SDarrick J. Wong #include "xfs_error.h"
26fc6856c6SDarrick J. Wong #include "xfs_extent_busy.h"
27fc6856c6SDarrick J. Wong #include "xfs_rtgroup.h"
28*d386b402SDarrick J. Wong #include "xfs_bmap.h"
29fc6856c6SDarrick J. Wong 
30fc6856c6SDarrick J. Wong static struct kmem_cache	*xfs_rtrmapbt_cur_cache;
31fc6856c6SDarrick J. Wong 
32fc6856c6SDarrick J. Wong /*
33fc6856c6SDarrick J. Wong  * Realtime Reverse Map btree.
34fc6856c6SDarrick J. Wong  *
35fc6856c6SDarrick J. Wong  * This is a btree used to track the owner(s) of a given extent in the realtime
36fc6856c6SDarrick J. Wong  * device.  See the comments in xfs_rmap_btree.c for more information.
37fc6856c6SDarrick J. Wong  *
38fc6856c6SDarrick J. Wong  * This tree is basically the same as the regular rmap btree except that it
39fc6856c6SDarrick J. Wong  * is rooted in an inode and does not live in free space.
40fc6856c6SDarrick J. Wong  */
41fc6856c6SDarrick J. Wong 
42fc6856c6SDarrick J. Wong static struct xfs_btree_cur *
43fc6856c6SDarrick J. Wong xfs_rtrmapbt_dup_cursor(
44fc6856c6SDarrick J. Wong 	struct xfs_btree_cur	*cur)
45fc6856c6SDarrick J. Wong {
46fc6856c6SDarrick J. Wong 	return xfs_rtrmapbt_init_cursor(cur->bc_tp, to_rtg(cur->bc_group));
47fc6856c6SDarrick J. Wong }
48fc6856c6SDarrick J. Wong 
49*d386b402SDarrick J. Wong STATIC int
50*d386b402SDarrick J. Wong xfs_rtrmapbt_get_minrecs(
51*d386b402SDarrick J. Wong 	struct xfs_btree_cur	*cur,
52*d386b402SDarrick J. Wong 	int			level)
53*d386b402SDarrick J. Wong {
54*d386b402SDarrick J. Wong 	if (level == cur->bc_nlevels - 1) {
55*d386b402SDarrick J. Wong 		struct xfs_ifork	*ifp = xfs_btree_ifork_ptr(cur);
56*d386b402SDarrick J. Wong 
57*d386b402SDarrick J. Wong 		return xfs_rtrmapbt_maxrecs(cur->bc_mp, ifp->if_broot_bytes,
58*d386b402SDarrick J. Wong 				level == 0) / 2;
59*d386b402SDarrick J. Wong 	}
60*d386b402SDarrick J. Wong 
61*d386b402SDarrick J. Wong 	return cur->bc_mp->m_rtrmap_mnr[level != 0];
62*d386b402SDarrick J. Wong }
63*d386b402SDarrick J. Wong 
64*d386b402SDarrick J. Wong STATIC int
65*d386b402SDarrick J. Wong xfs_rtrmapbt_get_maxrecs(
66*d386b402SDarrick J. Wong 	struct xfs_btree_cur	*cur,
67*d386b402SDarrick J. Wong 	int			level)
68*d386b402SDarrick J. Wong {
69*d386b402SDarrick J. Wong 	if (level == cur->bc_nlevels - 1) {
70*d386b402SDarrick J. Wong 		struct xfs_ifork	*ifp = xfs_btree_ifork_ptr(cur);
71*d386b402SDarrick J. Wong 
72*d386b402SDarrick J. Wong 		return xfs_rtrmapbt_maxrecs(cur->bc_mp, ifp->if_broot_bytes,
73*d386b402SDarrick J. Wong 				level == 0);
74*d386b402SDarrick J. Wong 	}
75*d386b402SDarrick J. Wong 
76*d386b402SDarrick J. Wong 	return cur->bc_mp->m_rtrmap_mxr[level != 0];
77*d386b402SDarrick J. Wong }
78*d386b402SDarrick J. Wong 
79*d386b402SDarrick J. Wong /*
80*d386b402SDarrick J. Wong  * Convert the ondisk record's offset field into the ondisk key's offset field.
81*d386b402SDarrick J. Wong  * Fork and bmbt are significant parts of the rmap record key, but written
82*d386b402SDarrick J. Wong  * status is merely a record attribute.
83*d386b402SDarrick J. Wong  */
84*d386b402SDarrick J. Wong static inline __be64 ondisk_rec_offset_to_key(const union xfs_btree_rec *rec)
85*d386b402SDarrick J. Wong {
86*d386b402SDarrick J. Wong 	return rec->rmap.rm_offset & ~cpu_to_be64(XFS_RMAP_OFF_UNWRITTEN);
87*d386b402SDarrick J. Wong }
88*d386b402SDarrick J. Wong 
89*d386b402SDarrick J. Wong STATIC void
90*d386b402SDarrick J. Wong xfs_rtrmapbt_init_key_from_rec(
91*d386b402SDarrick J. Wong 	union xfs_btree_key		*key,
92*d386b402SDarrick J. Wong 	const union xfs_btree_rec	*rec)
93*d386b402SDarrick J. Wong {
94*d386b402SDarrick J. Wong 	key->rmap.rm_startblock = rec->rmap.rm_startblock;
95*d386b402SDarrick J. Wong 	key->rmap.rm_owner = rec->rmap.rm_owner;
96*d386b402SDarrick J. Wong 	key->rmap.rm_offset = ondisk_rec_offset_to_key(rec);
97*d386b402SDarrick J. Wong }
98*d386b402SDarrick J. Wong 
99*d386b402SDarrick J. Wong STATIC void
100*d386b402SDarrick J. Wong xfs_rtrmapbt_init_high_key_from_rec(
101*d386b402SDarrick J. Wong 	union xfs_btree_key		*key,
102*d386b402SDarrick J. Wong 	const union xfs_btree_rec	*rec)
103*d386b402SDarrick J. Wong {
104*d386b402SDarrick J. Wong 	uint64_t			off;
105*d386b402SDarrick J. Wong 	int				adj;
106*d386b402SDarrick J. Wong 
107*d386b402SDarrick J. Wong 	adj = be32_to_cpu(rec->rmap.rm_blockcount) - 1;
108*d386b402SDarrick J. Wong 
109*d386b402SDarrick J. Wong 	key->rmap.rm_startblock = rec->rmap.rm_startblock;
110*d386b402SDarrick J. Wong 	be32_add_cpu(&key->rmap.rm_startblock, adj);
111*d386b402SDarrick J. Wong 	key->rmap.rm_owner = rec->rmap.rm_owner;
112*d386b402SDarrick J. Wong 	key->rmap.rm_offset = ondisk_rec_offset_to_key(rec);
113*d386b402SDarrick J. Wong 	if (XFS_RMAP_NON_INODE_OWNER(be64_to_cpu(rec->rmap.rm_owner)) ||
114*d386b402SDarrick J. Wong 	    XFS_RMAP_IS_BMBT_BLOCK(be64_to_cpu(rec->rmap.rm_offset)))
115*d386b402SDarrick J. Wong 		return;
116*d386b402SDarrick J. Wong 	off = be64_to_cpu(key->rmap.rm_offset);
117*d386b402SDarrick J. Wong 	off = (XFS_RMAP_OFF(off) + adj) | (off & ~XFS_RMAP_OFF_MASK);
118*d386b402SDarrick J. Wong 	key->rmap.rm_offset = cpu_to_be64(off);
119*d386b402SDarrick J. Wong }
120*d386b402SDarrick J. Wong 
121*d386b402SDarrick J. Wong STATIC void
122*d386b402SDarrick J. Wong xfs_rtrmapbt_init_rec_from_cur(
123*d386b402SDarrick J. Wong 	struct xfs_btree_cur	*cur,
124*d386b402SDarrick J. Wong 	union xfs_btree_rec	*rec)
125*d386b402SDarrick J. Wong {
126*d386b402SDarrick J. Wong 	rec->rmap.rm_startblock = cpu_to_be32(cur->bc_rec.r.rm_startblock);
127*d386b402SDarrick J. Wong 	rec->rmap.rm_blockcount = cpu_to_be32(cur->bc_rec.r.rm_blockcount);
128*d386b402SDarrick J. Wong 	rec->rmap.rm_owner = cpu_to_be64(cur->bc_rec.r.rm_owner);
129*d386b402SDarrick J. Wong 	rec->rmap.rm_offset = cpu_to_be64(
130*d386b402SDarrick J. Wong 			xfs_rmap_irec_offset_pack(&cur->bc_rec.r));
131*d386b402SDarrick J. Wong }
132*d386b402SDarrick J. Wong 
133*d386b402SDarrick J. Wong STATIC void
134*d386b402SDarrick J. Wong xfs_rtrmapbt_init_ptr_from_cur(
135*d386b402SDarrick J. Wong 	struct xfs_btree_cur	*cur,
136*d386b402SDarrick J. Wong 	union xfs_btree_ptr	*ptr)
137*d386b402SDarrick J. Wong {
138*d386b402SDarrick J. Wong 	ptr->l = 0;
139*d386b402SDarrick J. Wong }
140*d386b402SDarrick J. Wong 
141*d386b402SDarrick J. Wong /*
142*d386b402SDarrick J. Wong  * Mask the appropriate parts of the ondisk key field for a key comparison.
143*d386b402SDarrick J. Wong  * Fork and bmbt are significant parts of the rmap record key, but written
144*d386b402SDarrick J. Wong  * status is merely a record attribute.
145*d386b402SDarrick J. Wong  */
146*d386b402SDarrick J. Wong static inline uint64_t offset_keymask(uint64_t offset)
147*d386b402SDarrick J. Wong {
148*d386b402SDarrick J. Wong 	return offset & ~XFS_RMAP_OFF_UNWRITTEN;
149*d386b402SDarrick J. Wong }
150*d386b402SDarrick J. Wong 
151*d386b402SDarrick J. Wong STATIC int64_t
152*d386b402SDarrick J. Wong xfs_rtrmapbt_key_diff(
153*d386b402SDarrick J. Wong 	struct xfs_btree_cur		*cur,
154*d386b402SDarrick J. Wong 	const union xfs_btree_key	*key)
155*d386b402SDarrick J. Wong {
156*d386b402SDarrick J. Wong 	struct xfs_rmap_irec		*rec = &cur->bc_rec.r;
157*d386b402SDarrick J. Wong 	const struct xfs_rmap_key	*kp = &key->rmap;
158*d386b402SDarrick J. Wong 	__u64				x, y;
159*d386b402SDarrick J. Wong 	int64_t				d;
160*d386b402SDarrick J. Wong 
161*d386b402SDarrick J. Wong 	d = (int64_t)be32_to_cpu(kp->rm_startblock) - rec->rm_startblock;
162*d386b402SDarrick J. Wong 	if (d)
163*d386b402SDarrick J. Wong 		return d;
164*d386b402SDarrick J. Wong 
165*d386b402SDarrick J. Wong 	x = be64_to_cpu(kp->rm_owner);
166*d386b402SDarrick J. Wong 	y = rec->rm_owner;
167*d386b402SDarrick J. Wong 	if (x > y)
168*d386b402SDarrick J. Wong 		return 1;
169*d386b402SDarrick J. Wong 	else if (y > x)
170*d386b402SDarrick J. Wong 		return -1;
171*d386b402SDarrick J. Wong 
172*d386b402SDarrick J. Wong 	x = offset_keymask(be64_to_cpu(kp->rm_offset));
173*d386b402SDarrick J. Wong 	y = offset_keymask(xfs_rmap_irec_offset_pack(rec));
174*d386b402SDarrick J. Wong 	if (x > y)
175*d386b402SDarrick J. Wong 		return 1;
176*d386b402SDarrick J. Wong 	else if (y > x)
177*d386b402SDarrick J. Wong 		return -1;
178*d386b402SDarrick J. Wong 	return 0;
179*d386b402SDarrick J. Wong }
180*d386b402SDarrick J. Wong 
181*d386b402SDarrick J. Wong STATIC int64_t
182*d386b402SDarrick J. Wong xfs_rtrmapbt_diff_two_keys(
183*d386b402SDarrick J. Wong 	struct xfs_btree_cur		*cur,
184*d386b402SDarrick J. Wong 	const union xfs_btree_key	*k1,
185*d386b402SDarrick J. Wong 	const union xfs_btree_key	*k2,
186*d386b402SDarrick J. Wong 	const union xfs_btree_key	*mask)
187*d386b402SDarrick J. Wong {
188*d386b402SDarrick J. Wong 	const struct xfs_rmap_key	*kp1 = &k1->rmap;
189*d386b402SDarrick J. Wong 	const struct xfs_rmap_key	*kp2 = &k2->rmap;
190*d386b402SDarrick J. Wong 	int64_t				d;
191*d386b402SDarrick J. Wong 	__u64				x, y;
192*d386b402SDarrick J. Wong 
193*d386b402SDarrick J. Wong 	/* Doesn't make sense to mask off the physical space part */
194*d386b402SDarrick J. Wong 	ASSERT(!mask || mask->rmap.rm_startblock);
195*d386b402SDarrick J. Wong 
196*d386b402SDarrick J. Wong 	d = (int64_t)be32_to_cpu(kp1->rm_startblock) -
197*d386b402SDarrick J. Wong 		     be32_to_cpu(kp2->rm_startblock);
198*d386b402SDarrick J. Wong 	if (d)
199*d386b402SDarrick J. Wong 		return d;
200*d386b402SDarrick J. Wong 
201*d386b402SDarrick J. Wong 	if (!mask || mask->rmap.rm_owner) {
202*d386b402SDarrick J. Wong 		x = be64_to_cpu(kp1->rm_owner);
203*d386b402SDarrick J. Wong 		y = be64_to_cpu(kp2->rm_owner);
204*d386b402SDarrick J. Wong 		if (x > y)
205*d386b402SDarrick J. Wong 			return 1;
206*d386b402SDarrick J. Wong 		else if (y > x)
207*d386b402SDarrick J. Wong 			return -1;
208*d386b402SDarrick J. Wong 	}
209*d386b402SDarrick J. Wong 
210*d386b402SDarrick J. Wong 	if (!mask || mask->rmap.rm_offset) {
211*d386b402SDarrick J. Wong 		/* Doesn't make sense to allow offset but not owner */
212*d386b402SDarrick J. Wong 		ASSERT(!mask || mask->rmap.rm_owner);
213*d386b402SDarrick J. Wong 
214*d386b402SDarrick J. Wong 		x = offset_keymask(be64_to_cpu(kp1->rm_offset));
215*d386b402SDarrick J. Wong 		y = offset_keymask(be64_to_cpu(kp2->rm_offset));
216*d386b402SDarrick J. Wong 		if (x > y)
217*d386b402SDarrick J. Wong 			return 1;
218*d386b402SDarrick J. Wong 		else if (y > x)
219*d386b402SDarrick J. Wong 			return -1;
220*d386b402SDarrick J. Wong 	}
221*d386b402SDarrick J. Wong 
222*d386b402SDarrick J. Wong 	return 0;
223*d386b402SDarrick J. Wong }
224*d386b402SDarrick J. Wong 
225fc6856c6SDarrick J. Wong static xfs_failaddr_t
226fc6856c6SDarrick J. Wong xfs_rtrmapbt_verify(
227fc6856c6SDarrick J. Wong 	struct xfs_buf		*bp)
228fc6856c6SDarrick J. Wong {
229fc6856c6SDarrick J. Wong 	struct xfs_mount	*mp = bp->b_target->bt_mount;
230fc6856c6SDarrick J. Wong 	struct xfs_btree_block	*block = XFS_BUF_TO_BLOCK(bp);
231fc6856c6SDarrick J. Wong 	xfs_failaddr_t		fa;
232fc6856c6SDarrick J. Wong 	int			level;
233fc6856c6SDarrick J. Wong 
234fc6856c6SDarrick J. Wong 	if (!xfs_verify_magic(bp, block->bb_magic))
235fc6856c6SDarrick J. Wong 		return __this_address;
236fc6856c6SDarrick J. Wong 
237fc6856c6SDarrick J. Wong 	if (!xfs_has_rmapbt(mp))
238fc6856c6SDarrick J. Wong 		return __this_address;
239fc6856c6SDarrick J. Wong 	fa = xfs_btree_fsblock_v5hdr_verify(bp, XFS_RMAP_OWN_UNKNOWN);
240fc6856c6SDarrick J. Wong 	if (fa)
241fc6856c6SDarrick J. Wong 		return fa;
242fc6856c6SDarrick J. Wong 	level = be16_to_cpu(block->bb_level);
243fc6856c6SDarrick J. Wong 	if (level > mp->m_rtrmap_maxlevels)
244fc6856c6SDarrick J. Wong 		return __this_address;
245fc6856c6SDarrick J. Wong 
246fc6856c6SDarrick J. Wong 	return xfs_btree_fsblock_verify(bp, mp->m_rtrmap_mxr[level != 0]);
247fc6856c6SDarrick J. Wong }
248fc6856c6SDarrick J. Wong 
249fc6856c6SDarrick J. Wong static void
250fc6856c6SDarrick J. Wong xfs_rtrmapbt_read_verify(
251fc6856c6SDarrick J. Wong 	struct xfs_buf	*bp)
252fc6856c6SDarrick J. Wong {
253fc6856c6SDarrick J. Wong 	xfs_failaddr_t	fa;
254fc6856c6SDarrick J. Wong 
255fc6856c6SDarrick J. Wong 	if (!xfs_btree_fsblock_verify_crc(bp))
256fc6856c6SDarrick J. Wong 		xfs_verifier_error(bp, -EFSBADCRC, __this_address);
257fc6856c6SDarrick J. Wong 	else {
258fc6856c6SDarrick J. Wong 		fa = xfs_rtrmapbt_verify(bp);
259fc6856c6SDarrick J. Wong 		if (fa)
260fc6856c6SDarrick J. Wong 			xfs_verifier_error(bp, -EFSCORRUPTED, fa);
261fc6856c6SDarrick J. Wong 	}
262fc6856c6SDarrick J. Wong 
263fc6856c6SDarrick J. Wong 	if (bp->b_error)
264fc6856c6SDarrick J. Wong 		trace_xfs_btree_corrupt(bp, _RET_IP_);
265fc6856c6SDarrick J. Wong }
266fc6856c6SDarrick J. Wong 
267fc6856c6SDarrick J. Wong static void
268fc6856c6SDarrick J. Wong xfs_rtrmapbt_write_verify(
269fc6856c6SDarrick J. Wong 	struct xfs_buf	*bp)
270fc6856c6SDarrick J. Wong {
271fc6856c6SDarrick J. Wong 	xfs_failaddr_t	fa;
272fc6856c6SDarrick J. Wong 
273fc6856c6SDarrick J. Wong 	fa = xfs_rtrmapbt_verify(bp);
274fc6856c6SDarrick J. Wong 	if (fa) {
275fc6856c6SDarrick J. Wong 		trace_xfs_btree_corrupt(bp, _RET_IP_);
276fc6856c6SDarrick J. Wong 		xfs_verifier_error(bp, -EFSCORRUPTED, fa);
277fc6856c6SDarrick J. Wong 		return;
278fc6856c6SDarrick J. Wong 	}
279fc6856c6SDarrick J. Wong 	xfs_btree_fsblock_calc_crc(bp);
280fc6856c6SDarrick J. Wong 
281fc6856c6SDarrick J. Wong }
282fc6856c6SDarrick J. Wong 
283fc6856c6SDarrick J. Wong const struct xfs_buf_ops xfs_rtrmapbt_buf_ops = {
284fc6856c6SDarrick J. Wong 	.name			= "xfs_rtrmapbt",
285fc6856c6SDarrick J. Wong 	.magic			= { 0, cpu_to_be32(XFS_RTRMAP_CRC_MAGIC) },
286fc6856c6SDarrick J. Wong 	.verify_read		= xfs_rtrmapbt_read_verify,
287fc6856c6SDarrick J. Wong 	.verify_write		= xfs_rtrmapbt_write_verify,
288fc6856c6SDarrick J. Wong 	.verify_struct		= xfs_rtrmapbt_verify,
289fc6856c6SDarrick J. Wong };
290fc6856c6SDarrick J. Wong 
291*d386b402SDarrick J. Wong STATIC int
292*d386b402SDarrick J. Wong xfs_rtrmapbt_keys_inorder(
293*d386b402SDarrick J. Wong 	struct xfs_btree_cur		*cur,
294*d386b402SDarrick J. Wong 	const union xfs_btree_key	*k1,
295*d386b402SDarrick J. Wong 	const union xfs_btree_key	*k2)
296*d386b402SDarrick J. Wong {
297*d386b402SDarrick J. Wong 	uint32_t			x;
298*d386b402SDarrick J. Wong 	uint32_t			y;
299*d386b402SDarrick J. Wong 	uint64_t			a;
300*d386b402SDarrick J. Wong 	uint64_t			b;
301*d386b402SDarrick J. Wong 
302*d386b402SDarrick J. Wong 	x = be32_to_cpu(k1->rmap.rm_startblock);
303*d386b402SDarrick J. Wong 	y = be32_to_cpu(k2->rmap.rm_startblock);
304*d386b402SDarrick J. Wong 	if (x < y)
305*d386b402SDarrick J. Wong 		return 1;
306*d386b402SDarrick J. Wong 	else if (x > y)
307*d386b402SDarrick J. Wong 		return 0;
308*d386b402SDarrick J. Wong 	a = be64_to_cpu(k1->rmap.rm_owner);
309*d386b402SDarrick J. Wong 	b = be64_to_cpu(k2->rmap.rm_owner);
310*d386b402SDarrick J. Wong 	if (a < b)
311*d386b402SDarrick J. Wong 		return 1;
312*d386b402SDarrick J. Wong 	else if (a > b)
313*d386b402SDarrick J. Wong 		return 0;
314*d386b402SDarrick J. Wong 	a = offset_keymask(be64_to_cpu(k1->rmap.rm_offset));
315*d386b402SDarrick J. Wong 	b = offset_keymask(be64_to_cpu(k2->rmap.rm_offset));
316*d386b402SDarrick J. Wong 	if (a <= b)
317*d386b402SDarrick J. Wong 		return 1;
318*d386b402SDarrick J. Wong 	return 0;
319*d386b402SDarrick J. Wong }
320*d386b402SDarrick J. Wong 
321*d386b402SDarrick J. Wong STATIC int
322*d386b402SDarrick J. Wong xfs_rtrmapbt_recs_inorder(
323*d386b402SDarrick J. Wong 	struct xfs_btree_cur		*cur,
324*d386b402SDarrick J. Wong 	const union xfs_btree_rec	*r1,
325*d386b402SDarrick J. Wong 	const union xfs_btree_rec	*r2)
326*d386b402SDarrick J. Wong {
327*d386b402SDarrick J. Wong 	uint32_t			x;
328*d386b402SDarrick J. Wong 	uint32_t			y;
329*d386b402SDarrick J. Wong 	uint64_t			a;
330*d386b402SDarrick J. Wong 	uint64_t			b;
331*d386b402SDarrick J. Wong 
332*d386b402SDarrick J. Wong 	x = be32_to_cpu(r1->rmap.rm_startblock);
333*d386b402SDarrick J. Wong 	y = be32_to_cpu(r2->rmap.rm_startblock);
334*d386b402SDarrick J. Wong 	if (x < y)
335*d386b402SDarrick J. Wong 		return 1;
336*d386b402SDarrick J. Wong 	else if (x > y)
337*d386b402SDarrick J. Wong 		return 0;
338*d386b402SDarrick J. Wong 	a = be64_to_cpu(r1->rmap.rm_owner);
339*d386b402SDarrick J. Wong 	b = be64_to_cpu(r2->rmap.rm_owner);
340*d386b402SDarrick J. Wong 	if (a < b)
341*d386b402SDarrick J. Wong 		return 1;
342*d386b402SDarrick J. Wong 	else if (a > b)
343*d386b402SDarrick J. Wong 		return 0;
344*d386b402SDarrick J. Wong 	a = offset_keymask(be64_to_cpu(r1->rmap.rm_offset));
345*d386b402SDarrick J. Wong 	b = offset_keymask(be64_to_cpu(r2->rmap.rm_offset));
346*d386b402SDarrick J. Wong 	if (a <= b)
347*d386b402SDarrick J. Wong 		return 1;
348*d386b402SDarrick J. Wong 	return 0;
349*d386b402SDarrick J. Wong }
350*d386b402SDarrick J. Wong 
351*d386b402SDarrick J. Wong STATIC enum xbtree_key_contig
352*d386b402SDarrick J. Wong xfs_rtrmapbt_keys_contiguous(
353*d386b402SDarrick J. Wong 	struct xfs_btree_cur		*cur,
354*d386b402SDarrick J. Wong 	const union xfs_btree_key	*key1,
355*d386b402SDarrick J. Wong 	const union xfs_btree_key	*key2,
356*d386b402SDarrick J. Wong 	const union xfs_btree_key	*mask)
357*d386b402SDarrick J. Wong {
358*d386b402SDarrick J. Wong 	ASSERT(!mask || mask->rmap.rm_startblock);
359*d386b402SDarrick J. Wong 
360*d386b402SDarrick J. Wong 	/*
361*d386b402SDarrick J. Wong 	 * We only support checking contiguity of the physical space component.
362*d386b402SDarrick J. Wong 	 * If any callers ever need more specificity than that, they'll have to
363*d386b402SDarrick J. Wong 	 * implement it here.
364*d386b402SDarrick J. Wong 	 */
365*d386b402SDarrick J. Wong 	ASSERT(!mask || (!mask->rmap.rm_owner && !mask->rmap.rm_offset));
366*d386b402SDarrick J. Wong 
367*d386b402SDarrick J. Wong 	return xbtree_key_contig(be32_to_cpu(key1->rmap.rm_startblock),
368*d386b402SDarrick J. Wong 				 be32_to_cpu(key2->rmap.rm_startblock));
369*d386b402SDarrick J. Wong }
370*d386b402SDarrick J. Wong 
371fc6856c6SDarrick J. Wong const struct xfs_btree_ops xfs_rtrmapbt_ops = {
372fc6856c6SDarrick J. Wong 	.name			= "rtrmap",
373fc6856c6SDarrick J. Wong 	.type			= XFS_BTREE_TYPE_INODE,
374fc6856c6SDarrick J. Wong 	.geom_flags		= XFS_BTGEO_OVERLAPPING |
375fc6856c6SDarrick J. Wong 				  XFS_BTGEO_IROOT_RECORDS,
376fc6856c6SDarrick J. Wong 
377fc6856c6SDarrick J. Wong 	.rec_len		= sizeof(struct xfs_rmap_rec),
378fc6856c6SDarrick J. Wong 	/* Overlapping btree; 2 keys per pointer. */
379fc6856c6SDarrick J. Wong 	.key_len		= 2 * sizeof(struct xfs_rmap_key),
380fc6856c6SDarrick J. Wong 	.ptr_len		= XFS_BTREE_LONG_PTR_LEN,
381fc6856c6SDarrick J. Wong 
382fc6856c6SDarrick J. Wong 	.lru_refs		= XFS_RMAP_BTREE_REF,
383fc6856c6SDarrick J. Wong 	.statoff		= XFS_STATS_CALC_INDEX(xs_rtrmap_2),
384fc6856c6SDarrick J. Wong 
385fc6856c6SDarrick J. Wong 	.dup_cursor		= xfs_rtrmapbt_dup_cursor,
386*d386b402SDarrick J. Wong 	.alloc_block		= xfs_btree_alloc_metafile_block,
387*d386b402SDarrick J. Wong 	.free_block		= xfs_btree_free_metafile_block,
388*d386b402SDarrick J. Wong 	.get_minrecs		= xfs_rtrmapbt_get_minrecs,
389*d386b402SDarrick J. Wong 	.get_maxrecs		= xfs_rtrmapbt_get_maxrecs,
390*d386b402SDarrick J. Wong 	.init_key_from_rec	= xfs_rtrmapbt_init_key_from_rec,
391*d386b402SDarrick J. Wong 	.init_high_key_from_rec	= xfs_rtrmapbt_init_high_key_from_rec,
392*d386b402SDarrick J. Wong 	.init_rec_from_cur	= xfs_rtrmapbt_init_rec_from_cur,
393*d386b402SDarrick J. Wong 	.init_ptr_from_cur	= xfs_rtrmapbt_init_ptr_from_cur,
394*d386b402SDarrick J. Wong 	.key_diff		= xfs_rtrmapbt_key_diff,
395fc6856c6SDarrick J. Wong 	.buf_ops		= &xfs_rtrmapbt_buf_ops,
396*d386b402SDarrick J. Wong 	.diff_two_keys		= xfs_rtrmapbt_diff_two_keys,
397*d386b402SDarrick J. Wong 	.keys_inorder		= xfs_rtrmapbt_keys_inorder,
398*d386b402SDarrick J. Wong 	.recs_inorder		= xfs_rtrmapbt_recs_inorder,
399*d386b402SDarrick J. Wong 	.keys_contiguous	= xfs_rtrmapbt_keys_contiguous,
400fc6856c6SDarrick J. Wong };
401fc6856c6SDarrick J. Wong 
402fc6856c6SDarrick J. Wong /* Allocate a new rt rmap btree cursor. */
403fc6856c6SDarrick J. Wong struct xfs_btree_cur *
404fc6856c6SDarrick J. Wong xfs_rtrmapbt_init_cursor(
405fc6856c6SDarrick J. Wong 	struct xfs_trans	*tp,
406fc6856c6SDarrick J. Wong 	struct xfs_rtgroup	*rtg)
407fc6856c6SDarrick J. Wong {
408fc6856c6SDarrick J. Wong 	struct xfs_inode	*ip = NULL;
409fc6856c6SDarrick J. Wong 	struct xfs_mount	*mp = rtg_mount(rtg);
410fc6856c6SDarrick J. Wong 	struct xfs_btree_cur	*cur;
411fc6856c6SDarrick J. Wong 
412fc6856c6SDarrick J. Wong 	return NULL; /* XXX */
413fc6856c6SDarrick J. Wong 
414fc6856c6SDarrick J. Wong 	xfs_assert_ilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL);
415fc6856c6SDarrick J. Wong 
416fc6856c6SDarrick J. Wong 	cur = xfs_btree_alloc_cursor(mp, tp, &xfs_rtrmapbt_ops,
417fc6856c6SDarrick J. Wong 			mp->m_rtrmap_maxlevels, xfs_rtrmapbt_cur_cache);
418fc6856c6SDarrick J. Wong 
419fc6856c6SDarrick J. Wong 	cur->bc_ino.ip = ip;
420fc6856c6SDarrick J. Wong 	cur->bc_group = xfs_group_hold(rtg_group(rtg));
421fc6856c6SDarrick J. Wong 	cur->bc_ino.whichfork = XFS_DATA_FORK;
422fc6856c6SDarrick J. Wong 	cur->bc_nlevels = be16_to_cpu(ip->i_df.if_broot->bb_level) + 1;
423fc6856c6SDarrick J. Wong 	cur->bc_ino.forksize = xfs_inode_fork_size(ip, XFS_DATA_FORK);
424fc6856c6SDarrick J. Wong 
425fc6856c6SDarrick J. Wong 	return cur;
426fc6856c6SDarrick J. Wong }
427fc6856c6SDarrick J. Wong 
428fc6856c6SDarrick J. Wong /*
429fc6856c6SDarrick J. Wong  * Install a new rt reverse mapping btree root.  Caller is responsible for
430fc6856c6SDarrick J. Wong  * invalidating and freeing the old btree blocks.
431fc6856c6SDarrick J. Wong  */
432fc6856c6SDarrick J. Wong void
433fc6856c6SDarrick J. Wong xfs_rtrmapbt_commit_staged_btree(
434fc6856c6SDarrick J. Wong 	struct xfs_btree_cur	*cur,
435fc6856c6SDarrick J. Wong 	struct xfs_trans	*tp)
436fc6856c6SDarrick J. Wong {
437fc6856c6SDarrick J. Wong 	struct xbtree_ifakeroot	*ifake = cur->bc_ino.ifake;
438fc6856c6SDarrick J. Wong 	struct xfs_ifork	*ifp;
439fc6856c6SDarrick J. Wong 	int			flags = XFS_ILOG_CORE | XFS_ILOG_DBROOT;
440fc6856c6SDarrick J. Wong 
441fc6856c6SDarrick J. Wong 	ASSERT(cur->bc_flags & XFS_BTREE_STAGING);
442fc6856c6SDarrick J. Wong 
443fc6856c6SDarrick J. Wong 	/*
444fc6856c6SDarrick J. Wong 	 * Free any resources hanging off the real fork, then shallow-copy the
445fc6856c6SDarrick J. Wong 	 * staging fork's contents into the real fork to transfer everything
446fc6856c6SDarrick J. Wong 	 * we just built.
447fc6856c6SDarrick J. Wong 	 */
448fc6856c6SDarrick J. Wong 	ifp = xfs_ifork_ptr(cur->bc_ino.ip, XFS_DATA_FORK);
449fc6856c6SDarrick J. Wong 	xfs_idestroy_fork(ifp);
450fc6856c6SDarrick J. Wong 	memcpy(ifp, ifake->if_fork, sizeof(struct xfs_ifork));
451fc6856c6SDarrick J. Wong 
452fc6856c6SDarrick J. Wong 	cur->bc_ino.ip->i_projid = cur->bc_group->xg_gno;
453fc6856c6SDarrick J. Wong 	xfs_trans_log_inode(tp, cur->bc_ino.ip, flags);
454fc6856c6SDarrick J. Wong 	xfs_btree_commit_ifakeroot(cur, tp, XFS_DATA_FORK);
455fc6856c6SDarrick J. Wong }
456fc6856c6SDarrick J. Wong 
457fc6856c6SDarrick J. Wong /* Calculate number of records in a rt reverse mapping btree block. */
458fc6856c6SDarrick J. Wong static inline unsigned int
459fc6856c6SDarrick J. Wong xfs_rtrmapbt_block_maxrecs(
460fc6856c6SDarrick J. Wong 	unsigned int		blocklen,
461fc6856c6SDarrick J. Wong 	bool			leaf)
462fc6856c6SDarrick J. Wong {
463fc6856c6SDarrick J. Wong 	if (leaf)
464fc6856c6SDarrick J. Wong 		return blocklen / sizeof(struct xfs_rmap_rec);
465fc6856c6SDarrick J. Wong 	return blocklen /
466fc6856c6SDarrick J. Wong 		(2 * sizeof(struct xfs_rmap_key) + sizeof(xfs_rtrmap_ptr_t));
467fc6856c6SDarrick J. Wong }
468fc6856c6SDarrick J. Wong 
469fc6856c6SDarrick J. Wong /*
470fc6856c6SDarrick J. Wong  * Calculate number of records in an rt reverse mapping btree block.
471fc6856c6SDarrick J. Wong  */
472fc6856c6SDarrick J. Wong unsigned int
473fc6856c6SDarrick J. Wong xfs_rtrmapbt_maxrecs(
474fc6856c6SDarrick J. Wong 	struct xfs_mount	*mp,
475fc6856c6SDarrick J. Wong 	unsigned int		blocklen,
476fc6856c6SDarrick J. Wong 	bool			leaf)
477fc6856c6SDarrick J. Wong {
478fc6856c6SDarrick J. Wong 	blocklen -= XFS_RTRMAP_BLOCK_LEN;
479fc6856c6SDarrick J. Wong 	return xfs_rtrmapbt_block_maxrecs(blocklen, leaf);
480fc6856c6SDarrick J. Wong }
481fc6856c6SDarrick J. Wong 
482fc6856c6SDarrick J. Wong /* Compute the max possible height for realtime reverse mapping btrees. */
483fc6856c6SDarrick J. Wong unsigned int
484fc6856c6SDarrick J. Wong xfs_rtrmapbt_maxlevels_ondisk(void)
485fc6856c6SDarrick J. Wong {
486fc6856c6SDarrick J. Wong 	unsigned int		minrecs[2];
487fc6856c6SDarrick J. Wong 	unsigned int		blocklen;
488fc6856c6SDarrick J. Wong 
489fc6856c6SDarrick J. Wong 	blocklen = XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_LBLOCK_CRC_LEN;
490fc6856c6SDarrick J. Wong 
491fc6856c6SDarrick J. Wong 	minrecs[0] = xfs_rtrmapbt_block_maxrecs(blocklen, true) / 2;
492fc6856c6SDarrick J. Wong 	minrecs[1] = xfs_rtrmapbt_block_maxrecs(blocklen, false) / 2;
493fc6856c6SDarrick J. Wong 
494fc6856c6SDarrick J. Wong 	/* We need at most one record for every block in an rt group. */
495fc6856c6SDarrick J. Wong 	return xfs_btree_compute_maxlevels(minrecs, XFS_MAX_RGBLOCKS);
496fc6856c6SDarrick J. Wong }
497fc6856c6SDarrick J. Wong 
498fc6856c6SDarrick J. Wong int __init
499fc6856c6SDarrick J. Wong xfs_rtrmapbt_init_cur_cache(void)
500fc6856c6SDarrick J. Wong {
501fc6856c6SDarrick J. Wong 	xfs_rtrmapbt_cur_cache = kmem_cache_create("xfs_rtrmapbt_cur",
502fc6856c6SDarrick J. Wong 			xfs_btree_cur_sizeof(xfs_rtrmapbt_maxlevels_ondisk()),
503fc6856c6SDarrick J. Wong 			0, 0, NULL);
504fc6856c6SDarrick J. Wong 
505fc6856c6SDarrick J. Wong 	if (!xfs_rtrmapbt_cur_cache)
506fc6856c6SDarrick J. Wong 		return -ENOMEM;
507fc6856c6SDarrick J. Wong 	return 0;
508fc6856c6SDarrick J. Wong }
509fc6856c6SDarrick J. Wong 
510fc6856c6SDarrick J. Wong void
511fc6856c6SDarrick J. Wong xfs_rtrmapbt_destroy_cur_cache(void)
512fc6856c6SDarrick J. Wong {
513fc6856c6SDarrick J. Wong 	kmem_cache_destroy(xfs_rtrmapbt_cur_cache);
514fc6856c6SDarrick J. Wong 	xfs_rtrmapbt_cur_cache = NULL;
515fc6856c6SDarrick J. Wong }
516fc6856c6SDarrick J. Wong 
517fc6856c6SDarrick J. Wong /* Compute the maximum height of an rt reverse mapping btree. */
518fc6856c6SDarrick J. Wong void
519fc6856c6SDarrick J. Wong xfs_rtrmapbt_compute_maxlevels(
520fc6856c6SDarrick J. Wong 	struct xfs_mount	*mp)
521fc6856c6SDarrick J. Wong {
522fc6856c6SDarrick J. Wong 	unsigned int		d_maxlevels, r_maxlevels;
523fc6856c6SDarrick J. Wong 
524fc6856c6SDarrick J. Wong 	if (!xfs_has_rtrmapbt(mp)) {
525fc6856c6SDarrick J. Wong 		mp->m_rtrmap_maxlevels = 0;
526fc6856c6SDarrick J. Wong 		return;
527fc6856c6SDarrick J. Wong 	}
528fc6856c6SDarrick J. Wong 
529fc6856c6SDarrick J. Wong 	/*
530fc6856c6SDarrick J. Wong 	 * The realtime rmapbt lives on the data device, which means that its
531fc6856c6SDarrick J. Wong 	 * maximum height is constrained by the size of the data device and
532fc6856c6SDarrick J. Wong 	 * the height required to store one rmap record for each block in an
533fc6856c6SDarrick J. Wong 	 * rt group.
534fc6856c6SDarrick J. Wong 	 */
535fc6856c6SDarrick J. Wong 	d_maxlevels = xfs_btree_space_to_height(mp->m_rtrmap_mnr,
536fc6856c6SDarrick J. Wong 				mp->m_sb.sb_dblocks);
537fc6856c6SDarrick J. Wong 	r_maxlevels = xfs_btree_compute_maxlevels(mp->m_rtrmap_mnr,
538fc6856c6SDarrick J. Wong 				mp->m_groups[XG_TYPE_RTG].blocks);
539fc6856c6SDarrick J. Wong 
540fc6856c6SDarrick J. Wong 	/* Add one level to handle the inode root level. */
541fc6856c6SDarrick J. Wong 	mp->m_rtrmap_maxlevels = min(d_maxlevels, r_maxlevels) + 1;
542fc6856c6SDarrick J. Wong }
543