xref: /linux/fs/xfs/libxfs/xfs_rtrmap_btree.c (revision 8491a55cfc73ff5c2c637a70ade51d4d08abb90a)
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"
216b08901aSDarrick J. Wong #include "xfs_metafile.h"
22d386b402SDarrick J. Wong #include "xfs_rmap.h"
23fc6856c6SDarrick J. Wong #include "xfs_rtrmap_btree.h"
24fc6856c6SDarrick J. Wong #include "xfs_trace.h"
25fc6856c6SDarrick J. Wong #include "xfs_cksum.h"
26fc6856c6SDarrick J. Wong #include "xfs_error.h"
27fc6856c6SDarrick J. Wong #include "xfs_extent_busy.h"
28fc6856c6SDarrick J. Wong #include "xfs_rtgroup.h"
29d386b402SDarrick J. Wong #include "xfs_bmap.h"
30fc6856c6SDarrick J. Wong 
31fc6856c6SDarrick J. Wong static struct kmem_cache	*xfs_rtrmapbt_cur_cache;
32fc6856c6SDarrick J. Wong 
33fc6856c6SDarrick J. Wong /*
34fc6856c6SDarrick J. Wong  * Realtime Reverse Map btree.
35fc6856c6SDarrick J. Wong  *
36fc6856c6SDarrick J. Wong  * This is a btree used to track the owner(s) of a given extent in the realtime
37fc6856c6SDarrick J. Wong  * device.  See the comments in xfs_rmap_btree.c for more information.
38fc6856c6SDarrick J. Wong  *
39fc6856c6SDarrick J. Wong  * This tree is basically the same as the regular rmap btree except that it
40fc6856c6SDarrick J. Wong  * is rooted in an inode and does not live in free space.
41fc6856c6SDarrick J. Wong  */
42fc6856c6SDarrick J. Wong 
43fc6856c6SDarrick J. Wong static struct xfs_btree_cur *
44fc6856c6SDarrick J. Wong xfs_rtrmapbt_dup_cursor(
45fc6856c6SDarrick J. Wong 	struct xfs_btree_cur	*cur)
46fc6856c6SDarrick J. Wong {
47fc6856c6SDarrick J. Wong 	return xfs_rtrmapbt_init_cursor(cur->bc_tp, to_rtg(cur->bc_group));
48fc6856c6SDarrick J. Wong }
49fc6856c6SDarrick J. Wong 
50d386b402SDarrick J. Wong STATIC int
51d386b402SDarrick J. Wong xfs_rtrmapbt_get_minrecs(
52d386b402SDarrick J. Wong 	struct xfs_btree_cur	*cur,
53d386b402SDarrick J. Wong 	int			level)
54d386b402SDarrick J. Wong {
55d386b402SDarrick J. Wong 	if (level == cur->bc_nlevels - 1) {
56d386b402SDarrick J. Wong 		struct xfs_ifork	*ifp = xfs_btree_ifork_ptr(cur);
57d386b402SDarrick J. Wong 
58d386b402SDarrick J. Wong 		return xfs_rtrmapbt_maxrecs(cur->bc_mp, ifp->if_broot_bytes,
59d386b402SDarrick J. Wong 				level == 0) / 2;
60d386b402SDarrick J. Wong 	}
61d386b402SDarrick J. Wong 
62d386b402SDarrick J. Wong 	return cur->bc_mp->m_rtrmap_mnr[level != 0];
63d386b402SDarrick J. Wong }
64d386b402SDarrick J. Wong 
65d386b402SDarrick J. Wong STATIC int
66d386b402SDarrick J. Wong xfs_rtrmapbt_get_maxrecs(
67d386b402SDarrick J. Wong 	struct xfs_btree_cur	*cur,
68d386b402SDarrick J. Wong 	int			level)
69d386b402SDarrick J. Wong {
70d386b402SDarrick J. Wong 	if (level == cur->bc_nlevels - 1) {
71d386b402SDarrick J. Wong 		struct xfs_ifork	*ifp = xfs_btree_ifork_ptr(cur);
72d386b402SDarrick J. Wong 
73d386b402SDarrick J. Wong 		return xfs_rtrmapbt_maxrecs(cur->bc_mp, ifp->if_broot_bytes,
74d386b402SDarrick J. Wong 				level == 0);
75d386b402SDarrick J. Wong 	}
76d386b402SDarrick J. Wong 
77d386b402SDarrick J. Wong 	return cur->bc_mp->m_rtrmap_mxr[level != 0];
78d386b402SDarrick J. Wong }
79d386b402SDarrick J. Wong 
80d386b402SDarrick J. Wong /*
81d386b402SDarrick J. Wong  * Convert the ondisk record's offset field into the ondisk key's offset field.
82d386b402SDarrick J. Wong  * Fork and bmbt are significant parts of the rmap record key, but written
83d386b402SDarrick J. Wong  * status is merely a record attribute.
84d386b402SDarrick J. Wong  */
85d386b402SDarrick J. Wong static inline __be64 ondisk_rec_offset_to_key(const union xfs_btree_rec *rec)
86d386b402SDarrick J. Wong {
87d386b402SDarrick J. Wong 	return rec->rmap.rm_offset & ~cpu_to_be64(XFS_RMAP_OFF_UNWRITTEN);
88d386b402SDarrick J. Wong }
89d386b402SDarrick J. Wong 
90d386b402SDarrick J. Wong STATIC void
91d386b402SDarrick J. Wong xfs_rtrmapbt_init_key_from_rec(
92d386b402SDarrick J. Wong 	union xfs_btree_key		*key,
93d386b402SDarrick J. Wong 	const union xfs_btree_rec	*rec)
94d386b402SDarrick J. Wong {
95d386b402SDarrick J. Wong 	key->rmap.rm_startblock = rec->rmap.rm_startblock;
96d386b402SDarrick J. Wong 	key->rmap.rm_owner = rec->rmap.rm_owner;
97d386b402SDarrick J. Wong 	key->rmap.rm_offset = ondisk_rec_offset_to_key(rec);
98d386b402SDarrick J. Wong }
99d386b402SDarrick J. Wong 
100d386b402SDarrick J. Wong STATIC void
101d386b402SDarrick J. Wong xfs_rtrmapbt_init_high_key_from_rec(
102d386b402SDarrick J. Wong 	union xfs_btree_key		*key,
103d386b402SDarrick J. Wong 	const union xfs_btree_rec	*rec)
104d386b402SDarrick J. Wong {
105d386b402SDarrick J. Wong 	uint64_t			off;
106d386b402SDarrick J. Wong 	int				adj;
107d386b402SDarrick J. Wong 
108d386b402SDarrick J. Wong 	adj = be32_to_cpu(rec->rmap.rm_blockcount) - 1;
109d386b402SDarrick J. Wong 
110d386b402SDarrick J. Wong 	key->rmap.rm_startblock = rec->rmap.rm_startblock;
111d386b402SDarrick J. Wong 	be32_add_cpu(&key->rmap.rm_startblock, adj);
112d386b402SDarrick J. Wong 	key->rmap.rm_owner = rec->rmap.rm_owner;
113d386b402SDarrick J. Wong 	key->rmap.rm_offset = ondisk_rec_offset_to_key(rec);
114d386b402SDarrick J. Wong 	if (XFS_RMAP_NON_INODE_OWNER(be64_to_cpu(rec->rmap.rm_owner)) ||
115d386b402SDarrick J. Wong 	    XFS_RMAP_IS_BMBT_BLOCK(be64_to_cpu(rec->rmap.rm_offset)))
116d386b402SDarrick J. Wong 		return;
117d386b402SDarrick J. Wong 	off = be64_to_cpu(key->rmap.rm_offset);
118d386b402SDarrick J. Wong 	off = (XFS_RMAP_OFF(off) + adj) | (off & ~XFS_RMAP_OFF_MASK);
119d386b402SDarrick J. Wong 	key->rmap.rm_offset = cpu_to_be64(off);
120d386b402SDarrick J. Wong }
121d386b402SDarrick J. Wong 
122d386b402SDarrick J. Wong STATIC void
123d386b402SDarrick J. Wong xfs_rtrmapbt_init_rec_from_cur(
124d386b402SDarrick J. Wong 	struct xfs_btree_cur	*cur,
125d386b402SDarrick J. Wong 	union xfs_btree_rec	*rec)
126d386b402SDarrick J. Wong {
127d386b402SDarrick J. Wong 	rec->rmap.rm_startblock = cpu_to_be32(cur->bc_rec.r.rm_startblock);
128d386b402SDarrick J. Wong 	rec->rmap.rm_blockcount = cpu_to_be32(cur->bc_rec.r.rm_blockcount);
129d386b402SDarrick J. Wong 	rec->rmap.rm_owner = cpu_to_be64(cur->bc_rec.r.rm_owner);
130d386b402SDarrick J. Wong 	rec->rmap.rm_offset = cpu_to_be64(
131d386b402SDarrick J. Wong 			xfs_rmap_irec_offset_pack(&cur->bc_rec.r));
132d386b402SDarrick J. Wong }
133d386b402SDarrick J. Wong 
134d386b402SDarrick J. Wong STATIC void
135d386b402SDarrick J. Wong xfs_rtrmapbt_init_ptr_from_cur(
136d386b402SDarrick J. Wong 	struct xfs_btree_cur	*cur,
137d386b402SDarrick J. Wong 	union xfs_btree_ptr	*ptr)
138d386b402SDarrick J. Wong {
139d386b402SDarrick J. Wong 	ptr->l = 0;
140d386b402SDarrick J. Wong }
141d386b402SDarrick J. Wong 
142d386b402SDarrick J. Wong /*
143d386b402SDarrick J. Wong  * Mask the appropriate parts of the ondisk key field for a key comparison.
144d386b402SDarrick J. Wong  * Fork and bmbt are significant parts of the rmap record key, but written
145d386b402SDarrick J. Wong  * status is merely a record attribute.
146d386b402SDarrick J. Wong  */
147d386b402SDarrick J. Wong static inline uint64_t offset_keymask(uint64_t offset)
148d386b402SDarrick J. Wong {
149d386b402SDarrick J. Wong 	return offset & ~XFS_RMAP_OFF_UNWRITTEN;
150d386b402SDarrick J. Wong }
151d386b402SDarrick J. Wong 
152d386b402SDarrick J. Wong STATIC int64_t
153d386b402SDarrick J. Wong xfs_rtrmapbt_key_diff(
154d386b402SDarrick J. Wong 	struct xfs_btree_cur		*cur,
155d386b402SDarrick J. Wong 	const union xfs_btree_key	*key)
156d386b402SDarrick J. Wong {
157d386b402SDarrick J. Wong 	struct xfs_rmap_irec		*rec = &cur->bc_rec.r;
158d386b402SDarrick J. Wong 	const struct xfs_rmap_key	*kp = &key->rmap;
159d386b402SDarrick J. Wong 	__u64				x, y;
160d386b402SDarrick J. Wong 	int64_t				d;
161d386b402SDarrick J. Wong 
162d386b402SDarrick J. Wong 	d = (int64_t)be32_to_cpu(kp->rm_startblock) - rec->rm_startblock;
163d386b402SDarrick J. Wong 	if (d)
164d386b402SDarrick J. Wong 		return d;
165d386b402SDarrick J. Wong 
166d386b402SDarrick J. Wong 	x = be64_to_cpu(kp->rm_owner);
167d386b402SDarrick J. Wong 	y = rec->rm_owner;
168d386b402SDarrick J. Wong 	if (x > y)
169d386b402SDarrick J. Wong 		return 1;
170d386b402SDarrick J. Wong 	else if (y > x)
171d386b402SDarrick J. Wong 		return -1;
172d386b402SDarrick J. Wong 
173d386b402SDarrick J. Wong 	x = offset_keymask(be64_to_cpu(kp->rm_offset));
174d386b402SDarrick J. Wong 	y = offset_keymask(xfs_rmap_irec_offset_pack(rec));
175d386b402SDarrick J. Wong 	if (x > y)
176d386b402SDarrick J. Wong 		return 1;
177d386b402SDarrick J. Wong 	else if (y > x)
178d386b402SDarrick J. Wong 		return -1;
179d386b402SDarrick J. Wong 	return 0;
180d386b402SDarrick J. Wong }
181d386b402SDarrick J. Wong 
182d386b402SDarrick J. Wong STATIC int64_t
183d386b402SDarrick J. Wong xfs_rtrmapbt_diff_two_keys(
184d386b402SDarrick J. Wong 	struct xfs_btree_cur		*cur,
185d386b402SDarrick J. Wong 	const union xfs_btree_key	*k1,
186d386b402SDarrick J. Wong 	const union xfs_btree_key	*k2,
187d386b402SDarrick J. Wong 	const union xfs_btree_key	*mask)
188d386b402SDarrick J. Wong {
189d386b402SDarrick J. Wong 	const struct xfs_rmap_key	*kp1 = &k1->rmap;
190d386b402SDarrick J. Wong 	const struct xfs_rmap_key	*kp2 = &k2->rmap;
191d386b402SDarrick J. Wong 	int64_t				d;
192d386b402SDarrick J. Wong 	__u64				x, y;
193d386b402SDarrick J. Wong 
194d386b402SDarrick J. Wong 	/* Doesn't make sense to mask off the physical space part */
195d386b402SDarrick J. Wong 	ASSERT(!mask || mask->rmap.rm_startblock);
196d386b402SDarrick J. Wong 
197d386b402SDarrick J. Wong 	d = (int64_t)be32_to_cpu(kp1->rm_startblock) -
198d386b402SDarrick J. Wong 		     be32_to_cpu(kp2->rm_startblock);
199d386b402SDarrick J. Wong 	if (d)
200d386b402SDarrick J. Wong 		return d;
201d386b402SDarrick J. Wong 
202d386b402SDarrick J. Wong 	if (!mask || mask->rmap.rm_owner) {
203d386b402SDarrick J. Wong 		x = be64_to_cpu(kp1->rm_owner);
204d386b402SDarrick J. Wong 		y = be64_to_cpu(kp2->rm_owner);
205d386b402SDarrick J. Wong 		if (x > y)
206d386b402SDarrick J. Wong 			return 1;
207d386b402SDarrick J. Wong 		else if (y > x)
208d386b402SDarrick J. Wong 			return -1;
209d386b402SDarrick J. Wong 	}
210d386b402SDarrick J. Wong 
211d386b402SDarrick J. Wong 	if (!mask || mask->rmap.rm_offset) {
212d386b402SDarrick J. Wong 		/* Doesn't make sense to allow offset but not owner */
213d386b402SDarrick J. Wong 		ASSERT(!mask || mask->rmap.rm_owner);
214d386b402SDarrick J. Wong 
215d386b402SDarrick J. Wong 		x = offset_keymask(be64_to_cpu(kp1->rm_offset));
216d386b402SDarrick J. Wong 		y = offset_keymask(be64_to_cpu(kp2->rm_offset));
217d386b402SDarrick J. Wong 		if (x > y)
218d386b402SDarrick J. Wong 			return 1;
219d386b402SDarrick J. Wong 		else if (y > x)
220d386b402SDarrick J. Wong 			return -1;
221d386b402SDarrick J. Wong 	}
222d386b402SDarrick J. Wong 
223d386b402SDarrick J. Wong 	return 0;
224d386b402SDarrick J. Wong }
225d386b402SDarrick J. Wong 
226fc6856c6SDarrick J. Wong static xfs_failaddr_t
227fc6856c6SDarrick J. Wong xfs_rtrmapbt_verify(
228fc6856c6SDarrick J. Wong 	struct xfs_buf		*bp)
229fc6856c6SDarrick J. Wong {
230fc6856c6SDarrick J. Wong 	struct xfs_mount	*mp = bp->b_target->bt_mount;
231fc6856c6SDarrick J. Wong 	struct xfs_btree_block	*block = XFS_BUF_TO_BLOCK(bp);
232fc6856c6SDarrick J. Wong 	xfs_failaddr_t		fa;
233fc6856c6SDarrick J. Wong 	int			level;
234fc6856c6SDarrick J. Wong 
235fc6856c6SDarrick J. Wong 	if (!xfs_verify_magic(bp, block->bb_magic))
236fc6856c6SDarrick J. Wong 		return __this_address;
237fc6856c6SDarrick J. Wong 
238fc6856c6SDarrick J. Wong 	if (!xfs_has_rmapbt(mp))
239fc6856c6SDarrick J. Wong 		return __this_address;
240fc6856c6SDarrick J. Wong 	fa = xfs_btree_fsblock_v5hdr_verify(bp, XFS_RMAP_OWN_UNKNOWN);
241fc6856c6SDarrick J. Wong 	if (fa)
242fc6856c6SDarrick J. Wong 		return fa;
243fc6856c6SDarrick J. Wong 	level = be16_to_cpu(block->bb_level);
244fc6856c6SDarrick J. Wong 	if (level > mp->m_rtrmap_maxlevels)
245fc6856c6SDarrick J. Wong 		return __this_address;
246fc6856c6SDarrick J. Wong 
247fc6856c6SDarrick J. Wong 	return xfs_btree_fsblock_verify(bp, mp->m_rtrmap_mxr[level != 0]);
248fc6856c6SDarrick J. Wong }
249fc6856c6SDarrick J. Wong 
250fc6856c6SDarrick J. Wong static void
251fc6856c6SDarrick J. Wong xfs_rtrmapbt_read_verify(
252fc6856c6SDarrick J. Wong 	struct xfs_buf	*bp)
253fc6856c6SDarrick J. Wong {
254fc6856c6SDarrick J. Wong 	xfs_failaddr_t	fa;
255fc6856c6SDarrick J. Wong 
256fc6856c6SDarrick J. Wong 	if (!xfs_btree_fsblock_verify_crc(bp))
257fc6856c6SDarrick J. Wong 		xfs_verifier_error(bp, -EFSBADCRC, __this_address);
258fc6856c6SDarrick J. Wong 	else {
259fc6856c6SDarrick J. Wong 		fa = xfs_rtrmapbt_verify(bp);
260fc6856c6SDarrick J. Wong 		if (fa)
261fc6856c6SDarrick J. Wong 			xfs_verifier_error(bp, -EFSCORRUPTED, fa);
262fc6856c6SDarrick J. Wong 	}
263fc6856c6SDarrick J. Wong 
264fc6856c6SDarrick J. Wong 	if (bp->b_error)
265fc6856c6SDarrick J. Wong 		trace_xfs_btree_corrupt(bp, _RET_IP_);
266fc6856c6SDarrick J. Wong }
267fc6856c6SDarrick J. Wong 
268fc6856c6SDarrick J. Wong static void
269fc6856c6SDarrick J. Wong xfs_rtrmapbt_write_verify(
270fc6856c6SDarrick J. Wong 	struct xfs_buf	*bp)
271fc6856c6SDarrick J. Wong {
272fc6856c6SDarrick J. Wong 	xfs_failaddr_t	fa;
273fc6856c6SDarrick J. Wong 
274fc6856c6SDarrick J. Wong 	fa = xfs_rtrmapbt_verify(bp);
275fc6856c6SDarrick J. Wong 	if (fa) {
276fc6856c6SDarrick J. Wong 		trace_xfs_btree_corrupt(bp, _RET_IP_);
277fc6856c6SDarrick J. Wong 		xfs_verifier_error(bp, -EFSCORRUPTED, fa);
278fc6856c6SDarrick J. Wong 		return;
279fc6856c6SDarrick J. Wong 	}
280fc6856c6SDarrick J. Wong 	xfs_btree_fsblock_calc_crc(bp);
281fc6856c6SDarrick J. Wong 
282fc6856c6SDarrick J. Wong }
283fc6856c6SDarrick J. Wong 
284fc6856c6SDarrick J. Wong const struct xfs_buf_ops xfs_rtrmapbt_buf_ops = {
285fc6856c6SDarrick J. Wong 	.name			= "xfs_rtrmapbt",
286fc6856c6SDarrick J. Wong 	.magic			= { 0, cpu_to_be32(XFS_RTRMAP_CRC_MAGIC) },
287fc6856c6SDarrick J. Wong 	.verify_read		= xfs_rtrmapbt_read_verify,
288fc6856c6SDarrick J. Wong 	.verify_write		= xfs_rtrmapbt_write_verify,
289fc6856c6SDarrick J. Wong 	.verify_struct		= xfs_rtrmapbt_verify,
290fc6856c6SDarrick J. Wong };
291fc6856c6SDarrick J. Wong 
292d386b402SDarrick J. Wong STATIC int
293d386b402SDarrick J. Wong xfs_rtrmapbt_keys_inorder(
294d386b402SDarrick J. Wong 	struct xfs_btree_cur		*cur,
295d386b402SDarrick J. Wong 	const union xfs_btree_key	*k1,
296d386b402SDarrick J. Wong 	const union xfs_btree_key	*k2)
297d386b402SDarrick J. Wong {
298d386b402SDarrick J. Wong 	uint32_t			x;
299d386b402SDarrick J. Wong 	uint32_t			y;
300d386b402SDarrick J. Wong 	uint64_t			a;
301d386b402SDarrick J. Wong 	uint64_t			b;
302d386b402SDarrick J. Wong 
303d386b402SDarrick J. Wong 	x = be32_to_cpu(k1->rmap.rm_startblock);
304d386b402SDarrick J. Wong 	y = be32_to_cpu(k2->rmap.rm_startblock);
305d386b402SDarrick J. Wong 	if (x < y)
306d386b402SDarrick J. Wong 		return 1;
307d386b402SDarrick J. Wong 	else if (x > y)
308d386b402SDarrick J. Wong 		return 0;
309d386b402SDarrick J. Wong 	a = be64_to_cpu(k1->rmap.rm_owner);
310d386b402SDarrick J. Wong 	b = be64_to_cpu(k2->rmap.rm_owner);
311d386b402SDarrick J. Wong 	if (a < b)
312d386b402SDarrick J. Wong 		return 1;
313d386b402SDarrick J. Wong 	else if (a > b)
314d386b402SDarrick J. Wong 		return 0;
315d386b402SDarrick J. Wong 	a = offset_keymask(be64_to_cpu(k1->rmap.rm_offset));
316d386b402SDarrick J. Wong 	b = offset_keymask(be64_to_cpu(k2->rmap.rm_offset));
317d386b402SDarrick J. Wong 	if (a <= b)
318d386b402SDarrick J. Wong 		return 1;
319d386b402SDarrick J. Wong 	return 0;
320d386b402SDarrick J. Wong }
321d386b402SDarrick J. Wong 
322d386b402SDarrick J. Wong STATIC int
323d386b402SDarrick J. Wong xfs_rtrmapbt_recs_inorder(
324d386b402SDarrick J. Wong 	struct xfs_btree_cur		*cur,
325d386b402SDarrick J. Wong 	const union xfs_btree_rec	*r1,
326d386b402SDarrick J. Wong 	const union xfs_btree_rec	*r2)
327d386b402SDarrick J. Wong {
328d386b402SDarrick J. Wong 	uint32_t			x;
329d386b402SDarrick J. Wong 	uint32_t			y;
330d386b402SDarrick J. Wong 	uint64_t			a;
331d386b402SDarrick J. Wong 	uint64_t			b;
332d386b402SDarrick J. Wong 
333d386b402SDarrick J. Wong 	x = be32_to_cpu(r1->rmap.rm_startblock);
334d386b402SDarrick J. Wong 	y = be32_to_cpu(r2->rmap.rm_startblock);
335d386b402SDarrick J. Wong 	if (x < y)
336d386b402SDarrick J. Wong 		return 1;
337d386b402SDarrick J. Wong 	else if (x > y)
338d386b402SDarrick J. Wong 		return 0;
339d386b402SDarrick J. Wong 	a = be64_to_cpu(r1->rmap.rm_owner);
340d386b402SDarrick J. Wong 	b = be64_to_cpu(r2->rmap.rm_owner);
341d386b402SDarrick J. Wong 	if (a < b)
342d386b402SDarrick J. Wong 		return 1;
343d386b402SDarrick J. Wong 	else if (a > b)
344d386b402SDarrick J. Wong 		return 0;
345d386b402SDarrick J. Wong 	a = offset_keymask(be64_to_cpu(r1->rmap.rm_offset));
346d386b402SDarrick J. Wong 	b = offset_keymask(be64_to_cpu(r2->rmap.rm_offset));
347d386b402SDarrick J. Wong 	if (a <= b)
348d386b402SDarrick J. Wong 		return 1;
349d386b402SDarrick J. Wong 	return 0;
350d386b402SDarrick J. Wong }
351d386b402SDarrick J. Wong 
352d386b402SDarrick J. Wong STATIC enum xbtree_key_contig
353d386b402SDarrick J. Wong xfs_rtrmapbt_keys_contiguous(
354d386b402SDarrick J. Wong 	struct xfs_btree_cur		*cur,
355d386b402SDarrick J. Wong 	const union xfs_btree_key	*key1,
356d386b402SDarrick J. Wong 	const union xfs_btree_key	*key2,
357d386b402SDarrick J. Wong 	const union xfs_btree_key	*mask)
358d386b402SDarrick J. Wong {
359d386b402SDarrick J. Wong 	ASSERT(!mask || mask->rmap.rm_startblock);
360d386b402SDarrick J. Wong 
361d386b402SDarrick J. Wong 	/*
362d386b402SDarrick J. Wong 	 * We only support checking contiguity of the physical space component.
363d386b402SDarrick J. Wong 	 * If any callers ever need more specificity than that, they'll have to
364d386b402SDarrick J. Wong 	 * implement it here.
365d386b402SDarrick J. Wong 	 */
366d386b402SDarrick J. Wong 	ASSERT(!mask || (!mask->rmap.rm_owner && !mask->rmap.rm_offset));
367d386b402SDarrick J. Wong 
368d386b402SDarrick J. Wong 	return xbtree_key_contig(be32_to_cpu(key1->rmap.rm_startblock),
369d386b402SDarrick J. Wong 				 be32_to_cpu(key2->rmap.rm_startblock));
370d386b402SDarrick J. Wong }
371d386b402SDarrick J. Wong 
372fc6856c6SDarrick J. Wong const struct xfs_btree_ops xfs_rtrmapbt_ops = {
373fc6856c6SDarrick J. Wong 	.name			= "rtrmap",
374fc6856c6SDarrick J. Wong 	.type			= XFS_BTREE_TYPE_INODE,
375fc6856c6SDarrick J. Wong 	.geom_flags		= XFS_BTGEO_OVERLAPPING |
376fc6856c6SDarrick J. Wong 				  XFS_BTGEO_IROOT_RECORDS,
377fc6856c6SDarrick J. Wong 
378fc6856c6SDarrick J. Wong 	.rec_len		= sizeof(struct xfs_rmap_rec),
379fc6856c6SDarrick J. Wong 	/* Overlapping btree; 2 keys per pointer. */
380fc6856c6SDarrick J. Wong 	.key_len		= 2 * sizeof(struct xfs_rmap_key),
381fc6856c6SDarrick J. Wong 	.ptr_len		= XFS_BTREE_LONG_PTR_LEN,
382fc6856c6SDarrick J. Wong 
383fc6856c6SDarrick J. Wong 	.lru_refs		= XFS_RMAP_BTREE_REF,
384fc6856c6SDarrick J. Wong 	.statoff		= XFS_STATS_CALC_INDEX(xs_rtrmap_2),
385fc6856c6SDarrick J. Wong 
386fc6856c6SDarrick J. Wong 	.dup_cursor		= xfs_rtrmapbt_dup_cursor,
387d386b402SDarrick J. Wong 	.alloc_block		= xfs_btree_alloc_metafile_block,
388d386b402SDarrick J. Wong 	.free_block		= xfs_btree_free_metafile_block,
389d386b402SDarrick J. Wong 	.get_minrecs		= xfs_rtrmapbt_get_minrecs,
390d386b402SDarrick J. Wong 	.get_maxrecs		= xfs_rtrmapbt_get_maxrecs,
391d386b402SDarrick J. Wong 	.init_key_from_rec	= xfs_rtrmapbt_init_key_from_rec,
392d386b402SDarrick J. Wong 	.init_high_key_from_rec	= xfs_rtrmapbt_init_high_key_from_rec,
393d386b402SDarrick J. Wong 	.init_rec_from_cur	= xfs_rtrmapbt_init_rec_from_cur,
394d386b402SDarrick J. Wong 	.init_ptr_from_cur	= xfs_rtrmapbt_init_ptr_from_cur,
395d386b402SDarrick J. Wong 	.key_diff		= xfs_rtrmapbt_key_diff,
396fc6856c6SDarrick J. Wong 	.buf_ops		= &xfs_rtrmapbt_buf_ops,
397d386b402SDarrick J. Wong 	.diff_two_keys		= xfs_rtrmapbt_diff_two_keys,
398d386b402SDarrick J. Wong 	.keys_inorder		= xfs_rtrmapbt_keys_inorder,
399d386b402SDarrick J. Wong 	.recs_inorder		= xfs_rtrmapbt_recs_inorder,
400d386b402SDarrick J. Wong 	.keys_contiguous	= xfs_rtrmapbt_keys_contiguous,
401fc6856c6SDarrick J. Wong };
402fc6856c6SDarrick J. Wong 
403fc6856c6SDarrick J. Wong /* Allocate a new rt rmap btree cursor. */
404fc6856c6SDarrick J. Wong struct xfs_btree_cur *
405fc6856c6SDarrick J. Wong xfs_rtrmapbt_init_cursor(
406fc6856c6SDarrick J. Wong 	struct xfs_trans	*tp,
407fc6856c6SDarrick J. Wong 	struct xfs_rtgroup	*rtg)
408fc6856c6SDarrick J. Wong {
4096b08901aSDarrick J. Wong 	struct xfs_inode	*ip = rtg_rmap(rtg);
410fc6856c6SDarrick J. Wong 	struct xfs_mount	*mp = rtg_mount(rtg);
411fc6856c6SDarrick J. Wong 	struct xfs_btree_cur	*cur;
412fc6856c6SDarrick J. Wong 
413fc6856c6SDarrick J. Wong 	xfs_assert_ilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL);
414fc6856c6SDarrick J. Wong 
415fc6856c6SDarrick J. Wong 	cur = xfs_btree_alloc_cursor(mp, tp, &xfs_rtrmapbt_ops,
416fc6856c6SDarrick J. Wong 			mp->m_rtrmap_maxlevels, xfs_rtrmapbt_cur_cache);
417fc6856c6SDarrick J. Wong 
418fc6856c6SDarrick J. Wong 	cur->bc_ino.ip = ip;
419fc6856c6SDarrick J. Wong 	cur->bc_group = xfs_group_hold(rtg_group(rtg));
420fc6856c6SDarrick J. Wong 	cur->bc_ino.whichfork = XFS_DATA_FORK;
421fc6856c6SDarrick J. Wong 	cur->bc_nlevels = be16_to_cpu(ip->i_df.if_broot->bb_level) + 1;
422fc6856c6SDarrick J. Wong 	cur->bc_ino.forksize = xfs_inode_fork_size(ip, XFS_DATA_FORK);
423fc6856c6SDarrick J. Wong 
424fc6856c6SDarrick J. Wong 	return cur;
425fc6856c6SDarrick J. Wong }
426fc6856c6SDarrick J. Wong 
427fc6856c6SDarrick J. Wong /*
428fc6856c6SDarrick J. Wong  * Install a new rt reverse mapping btree root.  Caller is responsible for
429fc6856c6SDarrick J. Wong  * invalidating and freeing the old btree blocks.
430fc6856c6SDarrick J. Wong  */
431fc6856c6SDarrick J. Wong void
432fc6856c6SDarrick J. Wong xfs_rtrmapbt_commit_staged_btree(
433fc6856c6SDarrick J. Wong 	struct xfs_btree_cur	*cur,
434fc6856c6SDarrick J. Wong 	struct xfs_trans	*tp)
435fc6856c6SDarrick J. Wong {
436fc6856c6SDarrick J. Wong 	struct xbtree_ifakeroot	*ifake = cur->bc_ino.ifake;
437fc6856c6SDarrick J. Wong 	struct xfs_ifork	*ifp;
438fc6856c6SDarrick J. Wong 	int			flags = XFS_ILOG_CORE | XFS_ILOG_DBROOT;
439fc6856c6SDarrick J. Wong 
440fc6856c6SDarrick J. Wong 	ASSERT(cur->bc_flags & XFS_BTREE_STAGING);
4416b08901aSDarrick J. Wong 	ASSERT(ifake->if_fork->if_format == XFS_DINODE_FMT_META_BTREE);
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*8491a55cSDarrick J. Wong 
544*8491a55cSDarrick J. Wong /* Calculate the rtrmap btree size for some records. */
545*8491a55cSDarrick J. Wong static unsigned long long
546*8491a55cSDarrick J. Wong xfs_rtrmapbt_calc_size(
547*8491a55cSDarrick J. Wong 	struct xfs_mount	*mp,
548*8491a55cSDarrick J. Wong 	unsigned long long	len)
549*8491a55cSDarrick J. Wong {
550*8491a55cSDarrick J. Wong 	return xfs_btree_calc_size(mp->m_rtrmap_mnr, len);
551*8491a55cSDarrick J. Wong }
552*8491a55cSDarrick J. Wong 
553*8491a55cSDarrick J. Wong /*
554*8491a55cSDarrick J. Wong  * Calculate the maximum rmap btree size.
555*8491a55cSDarrick J. Wong  */
556*8491a55cSDarrick J. Wong static unsigned long long
557*8491a55cSDarrick J. Wong xfs_rtrmapbt_max_size(
558*8491a55cSDarrick J. Wong 	struct xfs_mount	*mp,
559*8491a55cSDarrick J. Wong 	xfs_rtblock_t		rtblocks)
560*8491a55cSDarrick J. Wong {
561*8491a55cSDarrick J. Wong 	/* Bail out if we're uninitialized, which can happen in mkfs. */
562*8491a55cSDarrick J. Wong 	if (mp->m_rtrmap_mxr[0] == 0)
563*8491a55cSDarrick J. Wong 		return 0;
564*8491a55cSDarrick J. Wong 
565*8491a55cSDarrick J. Wong 	return xfs_rtrmapbt_calc_size(mp, rtblocks);
566*8491a55cSDarrick J. Wong }
567*8491a55cSDarrick J. Wong 
568*8491a55cSDarrick J. Wong /*
569*8491a55cSDarrick J. Wong  * Figure out how many blocks to reserve and how many are used by this btree.
570*8491a55cSDarrick J. Wong  */
571*8491a55cSDarrick J. Wong xfs_filblks_t
572*8491a55cSDarrick J. Wong xfs_rtrmapbt_calc_reserves(
573*8491a55cSDarrick J. Wong 	struct xfs_mount	*mp)
574*8491a55cSDarrick J. Wong {
575*8491a55cSDarrick J. Wong 	uint32_t		blocks = mp->m_groups[XG_TYPE_RTG].blocks;
576*8491a55cSDarrick J. Wong 
577*8491a55cSDarrick J. Wong 	if (!xfs_has_rtrmapbt(mp))
578*8491a55cSDarrick J. Wong 		return 0;
579*8491a55cSDarrick J. Wong 
580*8491a55cSDarrick J. Wong 	/* Reserve 1% of the rtgroup or enough for 1 block per record. */
581*8491a55cSDarrick J. Wong 	return max_t(xfs_filblks_t, blocks / 100,
582*8491a55cSDarrick J. Wong 			xfs_rtrmapbt_max_size(mp, blocks));
583*8491a55cSDarrick J. Wong }
584