xref: /linux/fs/xfs/libxfs/xfs_rtrmap_btree.c (revision 6d4933c221958d1e1848d5092a3e3d1c6e4a6f92)
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"
30*6d4933c2SDarrick J. Wong #include "xfs_health.h"
31fc6856c6SDarrick J. Wong 
32fc6856c6SDarrick J. Wong static struct kmem_cache	*xfs_rtrmapbt_cur_cache;
33fc6856c6SDarrick J. Wong 
34fc6856c6SDarrick J. Wong /*
35fc6856c6SDarrick J. Wong  * Realtime Reverse Map btree.
36fc6856c6SDarrick J. Wong  *
37fc6856c6SDarrick J. Wong  * This is a btree used to track the owner(s) of a given extent in the realtime
38fc6856c6SDarrick J. Wong  * device.  See the comments in xfs_rmap_btree.c for more information.
39fc6856c6SDarrick J. Wong  *
40fc6856c6SDarrick J. Wong  * This tree is basically the same as the regular rmap btree except that it
41fc6856c6SDarrick J. Wong  * is rooted in an inode and does not live in free space.
42fc6856c6SDarrick J. Wong  */
43fc6856c6SDarrick J. Wong 
44fc6856c6SDarrick J. Wong static struct xfs_btree_cur *
45fc6856c6SDarrick J. Wong xfs_rtrmapbt_dup_cursor(
46fc6856c6SDarrick J. Wong 	struct xfs_btree_cur	*cur)
47fc6856c6SDarrick J. Wong {
48fc6856c6SDarrick J. Wong 	return xfs_rtrmapbt_init_cursor(cur->bc_tp, to_rtg(cur->bc_group));
49fc6856c6SDarrick J. Wong }
50fc6856c6SDarrick J. Wong 
51d386b402SDarrick J. Wong STATIC int
52d386b402SDarrick J. Wong xfs_rtrmapbt_get_minrecs(
53d386b402SDarrick J. Wong 	struct xfs_btree_cur	*cur,
54d386b402SDarrick J. Wong 	int			level)
55d386b402SDarrick J. Wong {
56d386b402SDarrick J. Wong 	if (level == cur->bc_nlevels - 1) {
57d386b402SDarrick J. Wong 		struct xfs_ifork	*ifp = xfs_btree_ifork_ptr(cur);
58d386b402SDarrick J. Wong 
59d386b402SDarrick J. Wong 		return xfs_rtrmapbt_maxrecs(cur->bc_mp, ifp->if_broot_bytes,
60d386b402SDarrick J. Wong 				level == 0) / 2;
61d386b402SDarrick J. Wong 	}
62d386b402SDarrick J. Wong 
63d386b402SDarrick J. Wong 	return cur->bc_mp->m_rtrmap_mnr[level != 0];
64d386b402SDarrick J. Wong }
65d386b402SDarrick J. Wong 
66d386b402SDarrick J. Wong STATIC int
67d386b402SDarrick J. Wong xfs_rtrmapbt_get_maxrecs(
68d386b402SDarrick J. Wong 	struct xfs_btree_cur	*cur,
69d386b402SDarrick J. Wong 	int			level)
70d386b402SDarrick J. Wong {
71d386b402SDarrick J. Wong 	if (level == cur->bc_nlevels - 1) {
72d386b402SDarrick J. Wong 		struct xfs_ifork	*ifp = xfs_btree_ifork_ptr(cur);
73d386b402SDarrick J. Wong 
74d386b402SDarrick J. Wong 		return xfs_rtrmapbt_maxrecs(cur->bc_mp, ifp->if_broot_bytes,
75d386b402SDarrick J. Wong 				level == 0);
76d386b402SDarrick J. Wong 	}
77d386b402SDarrick J. Wong 
78d386b402SDarrick J. Wong 	return cur->bc_mp->m_rtrmap_mxr[level != 0];
79d386b402SDarrick J. Wong }
80d386b402SDarrick J. Wong 
81f33659e8SDarrick J. Wong /* Calculate number of records in the ondisk realtime rmap btree inode root. */
82f33659e8SDarrick J. Wong unsigned int
83f33659e8SDarrick J. Wong xfs_rtrmapbt_droot_maxrecs(
84f33659e8SDarrick J. Wong 	unsigned int		blocklen,
85f33659e8SDarrick J. Wong 	bool			leaf)
86f33659e8SDarrick J. Wong {
87f33659e8SDarrick J. Wong 	blocklen -= sizeof(struct xfs_rtrmap_root);
88f33659e8SDarrick J. Wong 
89f33659e8SDarrick J. Wong 	if (leaf)
90f33659e8SDarrick J. Wong 		return blocklen / sizeof(struct xfs_rmap_rec);
91f33659e8SDarrick J. Wong 	return blocklen / (2 * sizeof(struct xfs_rmap_key) +
92f33659e8SDarrick J. Wong 			sizeof(xfs_rtrmap_ptr_t));
93f33659e8SDarrick J. Wong }
94f33659e8SDarrick J. Wong 
95f33659e8SDarrick J. Wong /*
96f33659e8SDarrick J. Wong  * Get the maximum records we could store in the on-disk format.
97f33659e8SDarrick J. Wong  *
98f33659e8SDarrick J. Wong  * For non-root nodes this is equivalent to xfs_rtrmapbt_get_maxrecs, but
99f33659e8SDarrick J. Wong  * for the root node this checks the available space in the dinode fork
100f33659e8SDarrick J. Wong  * so that we can resize the in-memory buffer to match it.  After a
101f33659e8SDarrick J. Wong  * resize to the maximum size this function returns the same value
102f33659e8SDarrick J. Wong  * as xfs_rtrmapbt_get_maxrecs for the root node, too.
103f33659e8SDarrick J. Wong  */
104f33659e8SDarrick J. Wong STATIC int
105f33659e8SDarrick J. Wong xfs_rtrmapbt_get_dmaxrecs(
106f33659e8SDarrick J. Wong 	struct xfs_btree_cur	*cur,
107f33659e8SDarrick J. Wong 	int			level)
108f33659e8SDarrick J. Wong {
109f33659e8SDarrick J. Wong 	if (level != cur->bc_nlevels - 1)
110f33659e8SDarrick J. Wong 		return cur->bc_mp->m_rtrmap_mxr[level != 0];
111f33659e8SDarrick J. Wong 	return xfs_rtrmapbt_droot_maxrecs(cur->bc_ino.forksize, level == 0);
112f33659e8SDarrick J. Wong }
113f33659e8SDarrick J. Wong 
114d386b402SDarrick J. Wong /*
115d386b402SDarrick J. Wong  * Convert the ondisk record's offset field into the ondisk key's offset field.
116d386b402SDarrick J. Wong  * Fork and bmbt are significant parts of the rmap record key, but written
117d386b402SDarrick J. Wong  * status is merely a record attribute.
118d386b402SDarrick J. Wong  */
119d386b402SDarrick J. Wong static inline __be64 ondisk_rec_offset_to_key(const union xfs_btree_rec *rec)
120d386b402SDarrick J. Wong {
121d386b402SDarrick J. Wong 	return rec->rmap.rm_offset & ~cpu_to_be64(XFS_RMAP_OFF_UNWRITTEN);
122d386b402SDarrick J. Wong }
123d386b402SDarrick J. Wong 
124d386b402SDarrick J. Wong STATIC void
125d386b402SDarrick J. Wong xfs_rtrmapbt_init_key_from_rec(
126d386b402SDarrick J. Wong 	union xfs_btree_key		*key,
127d386b402SDarrick J. Wong 	const union xfs_btree_rec	*rec)
128d386b402SDarrick J. Wong {
129d386b402SDarrick J. Wong 	key->rmap.rm_startblock = rec->rmap.rm_startblock;
130d386b402SDarrick J. Wong 	key->rmap.rm_owner = rec->rmap.rm_owner;
131d386b402SDarrick J. Wong 	key->rmap.rm_offset = ondisk_rec_offset_to_key(rec);
132d386b402SDarrick J. Wong }
133d386b402SDarrick J. Wong 
134d386b402SDarrick J. Wong STATIC void
135d386b402SDarrick J. Wong xfs_rtrmapbt_init_high_key_from_rec(
136d386b402SDarrick J. Wong 	union xfs_btree_key		*key,
137d386b402SDarrick J. Wong 	const union xfs_btree_rec	*rec)
138d386b402SDarrick J. Wong {
139d386b402SDarrick J. Wong 	uint64_t			off;
140d386b402SDarrick J. Wong 	int				adj;
141d386b402SDarrick J. Wong 
142d386b402SDarrick J. Wong 	adj = be32_to_cpu(rec->rmap.rm_blockcount) - 1;
143d386b402SDarrick J. Wong 
144d386b402SDarrick J. Wong 	key->rmap.rm_startblock = rec->rmap.rm_startblock;
145d386b402SDarrick J. Wong 	be32_add_cpu(&key->rmap.rm_startblock, adj);
146d386b402SDarrick J. Wong 	key->rmap.rm_owner = rec->rmap.rm_owner;
147d386b402SDarrick J. Wong 	key->rmap.rm_offset = ondisk_rec_offset_to_key(rec);
148d386b402SDarrick J. Wong 	if (XFS_RMAP_NON_INODE_OWNER(be64_to_cpu(rec->rmap.rm_owner)) ||
149d386b402SDarrick J. Wong 	    XFS_RMAP_IS_BMBT_BLOCK(be64_to_cpu(rec->rmap.rm_offset)))
150d386b402SDarrick J. Wong 		return;
151d386b402SDarrick J. Wong 	off = be64_to_cpu(key->rmap.rm_offset);
152d386b402SDarrick J. Wong 	off = (XFS_RMAP_OFF(off) + adj) | (off & ~XFS_RMAP_OFF_MASK);
153d386b402SDarrick J. Wong 	key->rmap.rm_offset = cpu_to_be64(off);
154d386b402SDarrick J. Wong }
155d386b402SDarrick J. Wong 
156d386b402SDarrick J. Wong STATIC void
157d386b402SDarrick J. Wong xfs_rtrmapbt_init_rec_from_cur(
158d386b402SDarrick J. Wong 	struct xfs_btree_cur	*cur,
159d386b402SDarrick J. Wong 	union xfs_btree_rec	*rec)
160d386b402SDarrick J. Wong {
161d386b402SDarrick J. Wong 	rec->rmap.rm_startblock = cpu_to_be32(cur->bc_rec.r.rm_startblock);
162d386b402SDarrick J. Wong 	rec->rmap.rm_blockcount = cpu_to_be32(cur->bc_rec.r.rm_blockcount);
163d386b402SDarrick J. Wong 	rec->rmap.rm_owner = cpu_to_be64(cur->bc_rec.r.rm_owner);
164d386b402SDarrick J. Wong 	rec->rmap.rm_offset = cpu_to_be64(
165d386b402SDarrick J. Wong 			xfs_rmap_irec_offset_pack(&cur->bc_rec.r));
166d386b402SDarrick J. Wong }
167d386b402SDarrick J. Wong 
168d386b402SDarrick J. Wong STATIC void
169d386b402SDarrick J. Wong xfs_rtrmapbt_init_ptr_from_cur(
170d386b402SDarrick J. Wong 	struct xfs_btree_cur	*cur,
171d386b402SDarrick J. Wong 	union xfs_btree_ptr	*ptr)
172d386b402SDarrick J. Wong {
173d386b402SDarrick J. Wong 	ptr->l = 0;
174d386b402SDarrick J. Wong }
175d386b402SDarrick J. Wong 
176d386b402SDarrick J. Wong /*
177d386b402SDarrick J. Wong  * Mask the appropriate parts of the ondisk key field for a key comparison.
178d386b402SDarrick J. Wong  * Fork and bmbt are significant parts of the rmap record key, but written
179d386b402SDarrick J. Wong  * status is merely a record attribute.
180d386b402SDarrick J. Wong  */
181d386b402SDarrick J. Wong static inline uint64_t offset_keymask(uint64_t offset)
182d386b402SDarrick J. Wong {
183d386b402SDarrick J. Wong 	return offset & ~XFS_RMAP_OFF_UNWRITTEN;
184d386b402SDarrick J. Wong }
185d386b402SDarrick J. Wong 
186d386b402SDarrick J. Wong STATIC int64_t
187d386b402SDarrick J. Wong xfs_rtrmapbt_key_diff(
188d386b402SDarrick J. Wong 	struct xfs_btree_cur		*cur,
189d386b402SDarrick J. Wong 	const union xfs_btree_key	*key)
190d386b402SDarrick J. Wong {
191d386b402SDarrick J. Wong 	struct xfs_rmap_irec		*rec = &cur->bc_rec.r;
192d386b402SDarrick J. Wong 	const struct xfs_rmap_key	*kp = &key->rmap;
193d386b402SDarrick J. Wong 	__u64				x, y;
194d386b402SDarrick J. Wong 	int64_t				d;
195d386b402SDarrick J. Wong 
196d386b402SDarrick J. Wong 	d = (int64_t)be32_to_cpu(kp->rm_startblock) - rec->rm_startblock;
197d386b402SDarrick J. Wong 	if (d)
198d386b402SDarrick J. Wong 		return d;
199d386b402SDarrick J. Wong 
200d386b402SDarrick J. Wong 	x = be64_to_cpu(kp->rm_owner);
201d386b402SDarrick J. Wong 	y = rec->rm_owner;
202d386b402SDarrick J. Wong 	if (x > y)
203d386b402SDarrick J. Wong 		return 1;
204d386b402SDarrick J. Wong 	else if (y > x)
205d386b402SDarrick J. Wong 		return -1;
206d386b402SDarrick J. Wong 
207d386b402SDarrick J. Wong 	x = offset_keymask(be64_to_cpu(kp->rm_offset));
208d386b402SDarrick J. Wong 	y = offset_keymask(xfs_rmap_irec_offset_pack(rec));
209d386b402SDarrick J. Wong 	if (x > y)
210d386b402SDarrick J. Wong 		return 1;
211d386b402SDarrick J. Wong 	else if (y > x)
212d386b402SDarrick J. Wong 		return -1;
213d386b402SDarrick J. Wong 	return 0;
214d386b402SDarrick J. Wong }
215d386b402SDarrick J. Wong 
216d386b402SDarrick J. Wong STATIC int64_t
217d386b402SDarrick J. Wong xfs_rtrmapbt_diff_two_keys(
218d386b402SDarrick J. Wong 	struct xfs_btree_cur		*cur,
219d386b402SDarrick J. Wong 	const union xfs_btree_key	*k1,
220d386b402SDarrick J. Wong 	const union xfs_btree_key	*k2,
221d386b402SDarrick J. Wong 	const union xfs_btree_key	*mask)
222d386b402SDarrick J. Wong {
223d386b402SDarrick J. Wong 	const struct xfs_rmap_key	*kp1 = &k1->rmap;
224d386b402SDarrick J. Wong 	const struct xfs_rmap_key	*kp2 = &k2->rmap;
225d386b402SDarrick J. Wong 	int64_t				d;
226d386b402SDarrick J. Wong 	__u64				x, y;
227d386b402SDarrick J. Wong 
228d386b402SDarrick J. Wong 	/* Doesn't make sense to mask off the physical space part */
229d386b402SDarrick J. Wong 	ASSERT(!mask || mask->rmap.rm_startblock);
230d386b402SDarrick J. Wong 
231d386b402SDarrick J. Wong 	d = (int64_t)be32_to_cpu(kp1->rm_startblock) -
232d386b402SDarrick J. Wong 		     be32_to_cpu(kp2->rm_startblock);
233d386b402SDarrick J. Wong 	if (d)
234d386b402SDarrick J. Wong 		return d;
235d386b402SDarrick J. Wong 
236d386b402SDarrick J. Wong 	if (!mask || mask->rmap.rm_owner) {
237d386b402SDarrick J. Wong 		x = be64_to_cpu(kp1->rm_owner);
238d386b402SDarrick J. Wong 		y = be64_to_cpu(kp2->rm_owner);
239d386b402SDarrick J. Wong 		if (x > y)
240d386b402SDarrick J. Wong 			return 1;
241d386b402SDarrick J. Wong 		else if (y > x)
242d386b402SDarrick J. Wong 			return -1;
243d386b402SDarrick J. Wong 	}
244d386b402SDarrick J. Wong 
245d386b402SDarrick J. Wong 	if (!mask || mask->rmap.rm_offset) {
246d386b402SDarrick J. Wong 		/* Doesn't make sense to allow offset but not owner */
247d386b402SDarrick J. Wong 		ASSERT(!mask || mask->rmap.rm_owner);
248d386b402SDarrick J. Wong 
249d386b402SDarrick J. Wong 		x = offset_keymask(be64_to_cpu(kp1->rm_offset));
250d386b402SDarrick J. Wong 		y = offset_keymask(be64_to_cpu(kp2->rm_offset));
251d386b402SDarrick J. Wong 		if (x > y)
252d386b402SDarrick J. Wong 			return 1;
253d386b402SDarrick J. Wong 		else if (y > x)
254d386b402SDarrick J. Wong 			return -1;
255d386b402SDarrick J. Wong 	}
256d386b402SDarrick J. Wong 
257d386b402SDarrick J. Wong 	return 0;
258d386b402SDarrick J. Wong }
259d386b402SDarrick J. Wong 
260fc6856c6SDarrick J. Wong static xfs_failaddr_t
261fc6856c6SDarrick J. Wong xfs_rtrmapbt_verify(
262fc6856c6SDarrick J. Wong 	struct xfs_buf		*bp)
263fc6856c6SDarrick J. Wong {
264fc6856c6SDarrick J. Wong 	struct xfs_mount	*mp = bp->b_target->bt_mount;
265fc6856c6SDarrick J. Wong 	struct xfs_btree_block	*block = XFS_BUF_TO_BLOCK(bp);
266fc6856c6SDarrick J. Wong 	xfs_failaddr_t		fa;
267fc6856c6SDarrick J. Wong 	int			level;
268fc6856c6SDarrick J. Wong 
269fc6856c6SDarrick J. Wong 	if (!xfs_verify_magic(bp, block->bb_magic))
270fc6856c6SDarrick J. Wong 		return __this_address;
271fc6856c6SDarrick J. Wong 
272fc6856c6SDarrick J. Wong 	if (!xfs_has_rmapbt(mp))
273fc6856c6SDarrick J. Wong 		return __this_address;
274fc6856c6SDarrick J. Wong 	fa = xfs_btree_fsblock_v5hdr_verify(bp, XFS_RMAP_OWN_UNKNOWN);
275fc6856c6SDarrick J. Wong 	if (fa)
276fc6856c6SDarrick J. Wong 		return fa;
277fc6856c6SDarrick J. Wong 	level = be16_to_cpu(block->bb_level);
278fc6856c6SDarrick J. Wong 	if (level > mp->m_rtrmap_maxlevels)
279fc6856c6SDarrick J. Wong 		return __this_address;
280fc6856c6SDarrick J. Wong 
281fc6856c6SDarrick J. Wong 	return xfs_btree_fsblock_verify(bp, mp->m_rtrmap_mxr[level != 0]);
282fc6856c6SDarrick J. Wong }
283fc6856c6SDarrick J. Wong 
284fc6856c6SDarrick J. Wong static void
285fc6856c6SDarrick J. Wong xfs_rtrmapbt_read_verify(
286fc6856c6SDarrick J. Wong 	struct xfs_buf	*bp)
287fc6856c6SDarrick J. Wong {
288fc6856c6SDarrick J. Wong 	xfs_failaddr_t	fa;
289fc6856c6SDarrick J. Wong 
290fc6856c6SDarrick J. Wong 	if (!xfs_btree_fsblock_verify_crc(bp))
291fc6856c6SDarrick J. Wong 		xfs_verifier_error(bp, -EFSBADCRC, __this_address);
292fc6856c6SDarrick J. Wong 	else {
293fc6856c6SDarrick J. Wong 		fa = xfs_rtrmapbt_verify(bp);
294fc6856c6SDarrick J. Wong 		if (fa)
295fc6856c6SDarrick J. Wong 			xfs_verifier_error(bp, -EFSCORRUPTED, fa);
296fc6856c6SDarrick J. Wong 	}
297fc6856c6SDarrick J. Wong 
298fc6856c6SDarrick J. Wong 	if (bp->b_error)
299fc6856c6SDarrick J. Wong 		trace_xfs_btree_corrupt(bp, _RET_IP_);
300fc6856c6SDarrick J. Wong }
301fc6856c6SDarrick J. Wong 
302fc6856c6SDarrick J. Wong static void
303fc6856c6SDarrick J. Wong xfs_rtrmapbt_write_verify(
304fc6856c6SDarrick J. Wong 	struct xfs_buf	*bp)
305fc6856c6SDarrick J. Wong {
306fc6856c6SDarrick J. Wong 	xfs_failaddr_t	fa;
307fc6856c6SDarrick J. Wong 
308fc6856c6SDarrick J. Wong 	fa = xfs_rtrmapbt_verify(bp);
309fc6856c6SDarrick J. Wong 	if (fa) {
310fc6856c6SDarrick J. Wong 		trace_xfs_btree_corrupt(bp, _RET_IP_);
311fc6856c6SDarrick J. Wong 		xfs_verifier_error(bp, -EFSCORRUPTED, fa);
312fc6856c6SDarrick J. Wong 		return;
313fc6856c6SDarrick J. Wong 	}
314fc6856c6SDarrick J. Wong 	xfs_btree_fsblock_calc_crc(bp);
315fc6856c6SDarrick J. Wong 
316fc6856c6SDarrick J. Wong }
317fc6856c6SDarrick J. Wong 
318fc6856c6SDarrick J. Wong const struct xfs_buf_ops xfs_rtrmapbt_buf_ops = {
319fc6856c6SDarrick J. Wong 	.name			= "xfs_rtrmapbt",
320fc6856c6SDarrick J. Wong 	.magic			= { 0, cpu_to_be32(XFS_RTRMAP_CRC_MAGIC) },
321fc6856c6SDarrick J. Wong 	.verify_read		= xfs_rtrmapbt_read_verify,
322fc6856c6SDarrick J. Wong 	.verify_write		= xfs_rtrmapbt_write_verify,
323fc6856c6SDarrick J. Wong 	.verify_struct		= xfs_rtrmapbt_verify,
324fc6856c6SDarrick J. Wong };
325fc6856c6SDarrick J. Wong 
326d386b402SDarrick J. Wong STATIC int
327d386b402SDarrick J. Wong xfs_rtrmapbt_keys_inorder(
328d386b402SDarrick J. Wong 	struct xfs_btree_cur		*cur,
329d386b402SDarrick J. Wong 	const union xfs_btree_key	*k1,
330d386b402SDarrick J. Wong 	const union xfs_btree_key	*k2)
331d386b402SDarrick J. Wong {
332d386b402SDarrick J. Wong 	uint32_t			x;
333d386b402SDarrick J. Wong 	uint32_t			y;
334d386b402SDarrick J. Wong 	uint64_t			a;
335d386b402SDarrick J. Wong 	uint64_t			b;
336d386b402SDarrick J. Wong 
337d386b402SDarrick J. Wong 	x = be32_to_cpu(k1->rmap.rm_startblock);
338d386b402SDarrick J. Wong 	y = be32_to_cpu(k2->rmap.rm_startblock);
339d386b402SDarrick J. Wong 	if (x < y)
340d386b402SDarrick J. Wong 		return 1;
341d386b402SDarrick J. Wong 	else if (x > y)
342d386b402SDarrick J. Wong 		return 0;
343d386b402SDarrick J. Wong 	a = be64_to_cpu(k1->rmap.rm_owner);
344d386b402SDarrick J. Wong 	b = be64_to_cpu(k2->rmap.rm_owner);
345d386b402SDarrick J. Wong 	if (a < b)
346d386b402SDarrick J. Wong 		return 1;
347d386b402SDarrick J. Wong 	else if (a > b)
348d386b402SDarrick J. Wong 		return 0;
349d386b402SDarrick J. Wong 	a = offset_keymask(be64_to_cpu(k1->rmap.rm_offset));
350d386b402SDarrick J. Wong 	b = offset_keymask(be64_to_cpu(k2->rmap.rm_offset));
351d386b402SDarrick J. Wong 	if (a <= b)
352d386b402SDarrick J. Wong 		return 1;
353d386b402SDarrick J. Wong 	return 0;
354d386b402SDarrick J. Wong }
355d386b402SDarrick J. Wong 
356d386b402SDarrick J. Wong STATIC int
357d386b402SDarrick J. Wong xfs_rtrmapbt_recs_inorder(
358d386b402SDarrick J. Wong 	struct xfs_btree_cur		*cur,
359d386b402SDarrick J. Wong 	const union xfs_btree_rec	*r1,
360d386b402SDarrick J. Wong 	const union xfs_btree_rec	*r2)
361d386b402SDarrick J. Wong {
362d386b402SDarrick J. Wong 	uint32_t			x;
363d386b402SDarrick J. Wong 	uint32_t			y;
364d386b402SDarrick J. Wong 	uint64_t			a;
365d386b402SDarrick J. Wong 	uint64_t			b;
366d386b402SDarrick J. Wong 
367d386b402SDarrick J. Wong 	x = be32_to_cpu(r1->rmap.rm_startblock);
368d386b402SDarrick J. Wong 	y = be32_to_cpu(r2->rmap.rm_startblock);
369d386b402SDarrick J. Wong 	if (x < y)
370d386b402SDarrick J. Wong 		return 1;
371d386b402SDarrick J. Wong 	else if (x > y)
372d386b402SDarrick J. Wong 		return 0;
373d386b402SDarrick J. Wong 	a = be64_to_cpu(r1->rmap.rm_owner);
374d386b402SDarrick J. Wong 	b = be64_to_cpu(r2->rmap.rm_owner);
375d386b402SDarrick J. Wong 	if (a < b)
376d386b402SDarrick J. Wong 		return 1;
377d386b402SDarrick J. Wong 	else if (a > b)
378d386b402SDarrick J. Wong 		return 0;
379d386b402SDarrick J. Wong 	a = offset_keymask(be64_to_cpu(r1->rmap.rm_offset));
380d386b402SDarrick J. Wong 	b = offset_keymask(be64_to_cpu(r2->rmap.rm_offset));
381d386b402SDarrick J. Wong 	if (a <= b)
382d386b402SDarrick J. Wong 		return 1;
383d386b402SDarrick J. Wong 	return 0;
384d386b402SDarrick J. Wong }
385d386b402SDarrick J. Wong 
386d386b402SDarrick J. Wong STATIC enum xbtree_key_contig
387d386b402SDarrick J. Wong xfs_rtrmapbt_keys_contiguous(
388d386b402SDarrick J. Wong 	struct xfs_btree_cur		*cur,
389d386b402SDarrick J. Wong 	const union xfs_btree_key	*key1,
390d386b402SDarrick J. Wong 	const union xfs_btree_key	*key2,
391d386b402SDarrick J. Wong 	const union xfs_btree_key	*mask)
392d386b402SDarrick J. Wong {
393d386b402SDarrick J. Wong 	ASSERT(!mask || mask->rmap.rm_startblock);
394d386b402SDarrick J. Wong 
395d386b402SDarrick J. Wong 	/*
396d386b402SDarrick J. Wong 	 * We only support checking contiguity of the physical space component.
397d386b402SDarrick J. Wong 	 * If any callers ever need more specificity than that, they'll have to
398d386b402SDarrick J. Wong 	 * implement it here.
399d386b402SDarrick J. Wong 	 */
400d386b402SDarrick J. Wong 	ASSERT(!mask || (!mask->rmap.rm_owner && !mask->rmap.rm_offset));
401d386b402SDarrick J. Wong 
402d386b402SDarrick J. Wong 	return xbtree_key_contig(be32_to_cpu(key1->rmap.rm_startblock),
403d386b402SDarrick J. Wong 				 be32_to_cpu(key2->rmap.rm_startblock));
404d386b402SDarrick J. Wong }
405d386b402SDarrick J. Wong 
406f33659e8SDarrick J. Wong static inline void
407f33659e8SDarrick J. Wong xfs_rtrmapbt_move_ptrs(
408f33659e8SDarrick J. Wong 	struct xfs_mount	*mp,
409f33659e8SDarrick J. Wong 	struct xfs_btree_block	*broot,
410f33659e8SDarrick J. Wong 	short			old_size,
411f33659e8SDarrick J. Wong 	size_t			new_size,
412f33659e8SDarrick J. Wong 	unsigned int		numrecs)
413f33659e8SDarrick J. Wong {
414f33659e8SDarrick J. Wong 	void			*dptr;
415f33659e8SDarrick J. Wong 	void			*sptr;
416f33659e8SDarrick J. Wong 
417f33659e8SDarrick J. Wong 	sptr = xfs_rtrmap_broot_ptr_addr(mp, broot, 1, old_size);
418f33659e8SDarrick J. Wong 	dptr = xfs_rtrmap_broot_ptr_addr(mp, broot, 1, new_size);
419f33659e8SDarrick J. Wong 	memmove(dptr, sptr, numrecs * sizeof(xfs_rtrmap_ptr_t));
420f33659e8SDarrick J. Wong }
421f33659e8SDarrick J. Wong 
422f33659e8SDarrick J. Wong static struct xfs_btree_block *
423f33659e8SDarrick J. Wong xfs_rtrmapbt_broot_realloc(
424f33659e8SDarrick J. Wong 	struct xfs_btree_cur	*cur,
425f33659e8SDarrick J. Wong 	unsigned int		new_numrecs)
426f33659e8SDarrick J. Wong {
427f33659e8SDarrick J. Wong 	struct xfs_mount	*mp = cur->bc_mp;
428f33659e8SDarrick J. Wong 	struct xfs_ifork	*ifp = xfs_btree_ifork_ptr(cur);
429f33659e8SDarrick J. Wong 	struct xfs_btree_block	*broot;
430f33659e8SDarrick J. Wong 	unsigned int		new_size;
431f33659e8SDarrick J. Wong 	unsigned int		old_size = ifp->if_broot_bytes;
432f33659e8SDarrick J. Wong 	const unsigned int	level = cur->bc_nlevels - 1;
433f33659e8SDarrick J. Wong 
434f33659e8SDarrick J. Wong 	new_size = xfs_rtrmap_broot_space_calc(mp, level, new_numrecs);
435f33659e8SDarrick J. Wong 
436f33659e8SDarrick J. Wong 	/* Handle the nop case quietly. */
437f33659e8SDarrick J. Wong 	if (new_size == old_size)
438f33659e8SDarrick J. Wong 		return ifp->if_broot;
439f33659e8SDarrick J. Wong 
440f33659e8SDarrick J. Wong 	if (new_size > old_size) {
441f33659e8SDarrick J. Wong 		unsigned int	old_numrecs;
442f33659e8SDarrick J. Wong 
443f33659e8SDarrick J. Wong 		/*
444f33659e8SDarrick J. Wong 		 * If there wasn't any memory allocated before, just allocate
445f33659e8SDarrick J. Wong 		 * it now and get out.
446f33659e8SDarrick J. Wong 		 */
447f33659e8SDarrick J. Wong 		if (old_size == 0)
448f33659e8SDarrick J. Wong 			return xfs_broot_realloc(ifp, new_size);
449f33659e8SDarrick J. Wong 
450f33659e8SDarrick J. Wong 		/*
451f33659e8SDarrick J. Wong 		 * If there is already an existing if_broot, then we need to
452f33659e8SDarrick J. Wong 		 * realloc it and possibly move the node block pointers because
453f33659e8SDarrick J. Wong 		 * those are not butted up against the btree block header.
454f33659e8SDarrick J. Wong 		 */
455f33659e8SDarrick J. Wong 		old_numrecs = xfs_rtrmapbt_maxrecs(mp, old_size, level == 0);
456f33659e8SDarrick J. Wong 		broot = xfs_broot_realloc(ifp, new_size);
457f33659e8SDarrick J. Wong 		if (level > 0)
458f33659e8SDarrick J. Wong 			xfs_rtrmapbt_move_ptrs(mp, broot, old_size, new_size,
459f33659e8SDarrick J. Wong 					old_numrecs);
460f33659e8SDarrick J. Wong 		goto out_broot;
461f33659e8SDarrick J. Wong 	}
462f33659e8SDarrick J. Wong 
463f33659e8SDarrick J. Wong 	/*
464f33659e8SDarrick J. Wong 	 * We're reducing numrecs.  If we're going all the way to zero, just
465f33659e8SDarrick J. Wong 	 * free the block.
466f33659e8SDarrick J. Wong 	 */
467f33659e8SDarrick J. Wong 	ASSERT(ifp->if_broot != NULL && old_size > 0);
468f33659e8SDarrick J. Wong 	if (new_size == 0)
469f33659e8SDarrick J. Wong 		return xfs_broot_realloc(ifp, 0);
470f33659e8SDarrick J. Wong 
471f33659e8SDarrick J. Wong 	/*
472f33659e8SDarrick J. Wong 	 * Shrink the btree root by possibly moving the rtrmapbt pointers,
473f33659e8SDarrick J. Wong 	 * since they are not butted up against the btree block header.  Then
474f33659e8SDarrick J. Wong 	 * reallocate broot.
475f33659e8SDarrick J. Wong 	 */
476f33659e8SDarrick J. Wong 	if (level > 0)
477f33659e8SDarrick J. Wong 		xfs_rtrmapbt_move_ptrs(mp, ifp->if_broot, old_size, new_size,
478f33659e8SDarrick J. Wong 				new_numrecs);
479f33659e8SDarrick J. Wong 	broot = xfs_broot_realloc(ifp, new_size);
480f33659e8SDarrick J. Wong 
481f33659e8SDarrick J. Wong out_broot:
482f33659e8SDarrick J. Wong 	ASSERT(xfs_rtrmap_droot_space(broot) <=
483f33659e8SDarrick J. Wong 	       xfs_inode_fork_size(cur->bc_ino.ip, cur->bc_ino.whichfork));
484f33659e8SDarrick J. Wong 	return broot;
485f33659e8SDarrick J. Wong }
486f33659e8SDarrick J. Wong 
487fc6856c6SDarrick J. Wong const struct xfs_btree_ops xfs_rtrmapbt_ops = {
488fc6856c6SDarrick J. Wong 	.name			= "rtrmap",
489fc6856c6SDarrick J. Wong 	.type			= XFS_BTREE_TYPE_INODE,
490fc6856c6SDarrick J. Wong 	.geom_flags		= XFS_BTGEO_OVERLAPPING |
491fc6856c6SDarrick J. Wong 				  XFS_BTGEO_IROOT_RECORDS,
492fc6856c6SDarrick J. Wong 
493fc6856c6SDarrick J. Wong 	.rec_len		= sizeof(struct xfs_rmap_rec),
494fc6856c6SDarrick J. Wong 	/* Overlapping btree; 2 keys per pointer. */
495fc6856c6SDarrick J. Wong 	.key_len		= 2 * sizeof(struct xfs_rmap_key),
496fc6856c6SDarrick J. Wong 	.ptr_len		= XFS_BTREE_LONG_PTR_LEN,
497fc6856c6SDarrick J. Wong 
498fc6856c6SDarrick J. Wong 	.lru_refs		= XFS_RMAP_BTREE_REF,
499fc6856c6SDarrick J. Wong 	.statoff		= XFS_STATS_CALC_INDEX(xs_rtrmap_2),
500*6d4933c2SDarrick J. Wong 	.sick_mask		= XFS_SICK_RG_RMAPBT,
501fc6856c6SDarrick J. Wong 
502fc6856c6SDarrick J. Wong 	.dup_cursor		= xfs_rtrmapbt_dup_cursor,
503d386b402SDarrick J. Wong 	.alloc_block		= xfs_btree_alloc_metafile_block,
504d386b402SDarrick J. Wong 	.free_block		= xfs_btree_free_metafile_block,
505d386b402SDarrick J. Wong 	.get_minrecs		= xfs_rtrmapbt_get_minrecs,
506d386b402SDarrick J. Wong 	.get_maxrecs		= xfs_rtrmapbt_get_maxrecs,
507f33659e8SDarrick J. Wong 	.get_dmaxrecs		= xfs_rtrmapbt_get_dmaxrecs,
508d386b402SDarrick J. Wong 	.init_key_from_rec	= xfs_rtrmapbt_init_key_from_rec,
509d386b402SDarrick J. Wong 	.init_high_key_from_rec	= xfs_rtrmapbt_init_high_key_from_rec,
510d386b402SDarrick J. Wong 	.init_rec_from_cur	= xfs_rtrmapbt_init_rec_from_cur,
511d386b402SDarrick J. Wong 	.init_ptr_from_cur	= xfs_rtrmapbt_init_ptr_from_cur,
512d386b402SDarrick J. Wong 	.key_diff		= xfs_rtrmapbt_key_diff,
513fc6856c6SDarrick J. Wong 	.buf_ops		= &xfs_rtrmapbt_buf_ops,
514d386b402SDarrick J. Wong 	.diff_two_keys		= xfs_rtrmapbt_diff_two_keys,
515d386b402SDarrick J. Wong 	.keys_inorder		= xfs_rtrmapbt_keys_inorder,
516d386b402SDarrick J. Wong 	.recs_inorder		= xfs_rtrmapbt_recs_inorder,
517d386b402SDarrick J. Wong 	.keys_contiguous	= xfs_rtrmapbt_keys_contiguous,
518f33659e8SDarrick J. Wong 	.broot_realloc		= xfs_rtrmapbt_broot_realloc,
519fc6856c6SDarrick J. Wong };
520fc6856c6SDarrick J. Wong 
521fc6856c6SDarrick J. Wong /* Allocate a new rt rmap btree cursor. */
522fc6856c6SDarrick J. Wong struct xfs_btree_cur *
523fc6856c6SDarrick J. Wong xfs_rtrmapbt_init_cursor(
524fc6856c6SDarrick J. Wong 	struct xfs_trans	*tp,
525fc6856c6SDarrick J. Wong 	struct xfs_rtgroup	*rtg)
526fc6856c6SDarrick J. Wong {
5276b08901aSDarrick J. Wong 	struct xfs_inode	*ip = rtg_rmap(rtg);
528fc6856c6SDarrick J. Wong 	struct xfs_mount	*mp = rtg_mount(rtg);
529fc6856c6SDarrick J. Wong 	struct xfs_btree_cur	*cur;
530fc6856c6SDarrick J. Wong 
531fc6856c6SDarrick J. Wong 	xfs_assert_ilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL);
532fc6856c6SDarrick J. Wong 
533fc6856c6SDarrick J. Wong 	cur = xfs_btree_alloc_cursor(mp, tp, &xfs_rtrmapbt_ops,
534fc6856c6SDarrick J. Wong 			mp->m_rtrmap_maxlevels, xfs_rtrmapbt_cur_cache);
535fc6856c6SDarrick J. Wong 
536fc6856c6SDarrick J. Wong 	cur->bc_ino.ip = ip;
537fc6856c6SDarrick J. Wong 	cur->bc_group = xfs_group_hold(rtg_group(rtg));
538fc6856c6SDarrick J. Wong 	cur->bc_ino.whichfork = XFS_DATA_FORK;
539fc6856c6SDarrick J. Wong 	cur->bc_nlevels = be16_to_cpu(ip->i_df.if_broot->bb_level) + 1;
540fc6856c6SDarrick J. Wong 	cur->bc_ino.forksize = xfs_inode_fork_size(ip, XFS_DATA_FORK);
541fc6856c6SDarrick J. Wong 
542fc6856c6SDarrick J. Wong 	return cur;
543fc6856c6SDarrick J. Wong }
544fc6856c6SDarrick J. Wong 
545fc6856c6SDarrick J. Wong /*
546fc6856c6SDarrick J. Wong  * Install a new rt reverse mapping btree root.  Caller is responsible for
547fc6856c6SDarrick J. Wong  * invalidating and freeing the old btree blocks.
548fc6856c6SDarrick J. Wong  */
549fc6856c6SDarrick J. Wong void
550fc6856c6SDarrick J. Wong xfs_rtrmapbt_commit_staged_btree(
551fc6856c6SDarrick J. Wong 	struct xfs_btree_cur	*cur,
552fc6856c6SDarrick J. Wong 	struct xfs_trans	*tp)
553fc6856c6SDarrick J. Wong {
554fc6856c6SDarrick J. Wong 	struct xbtree_ifakeroot	*ifake = cur->bc_ino.ifake;
555fc6856c6SDarrick J. Wong 	struct xfs_ifork	*ifp;
556fc6856c6SDarrick J. Wong 	int			flags = XFS_ILOG_CORE | XFS_ILOG_DBROOT;
557fc6856c6SDarrick J. Wong 
558fc6856c6SDarrick J. Wong 	ASSERT(cur->bc_flags & XFS_BTREE_STAGING);
5596b08901aSDarrick J. Wong 	ASSERT(ifake->if_fork->if_format == XFS_DINODE_FMT_META_BTREE);
560fc6856c6SDarrick J. Wong 
561fc6856c6SDarrick J. Wong 	/*
562fc6856c6SDarrick J. Wong 	 * Free any resources hanging off the real fork, then shallow-copy the
563fc6856c6SDarrick J. Wong 	 * staging fork's contents into the real fork to transfer everything
564fc6856c6SDarrick J. Wong 	 * we just built.
565fc6856c6SDarrick J. Wong 	 */
566fc6856c6SDarrick J. Wong 	ifp = xfs_ifork_ptr(cur->bc_ino.ip, XFS_DATA_FORK);
567fc6856c6SDarrick J. Wong 	xfs_idestroy_fork(ifp);
568fc6856c6SDarrick J. Wong 	memcpy(ifp, ifake->if_fork, sizeof(struct xfs_ifork));
569fc6856c6SDarrick J. Wong 
570fc6856c6SDarrick J. Wong 	cur->bc_ino.ip->i_projid = cur->bc_group->xg_gno;
571fc6856c6SDarrick J. Wong 	xfs_trans_log_inode(tp, cur->bc_ino.ip, flags);
572fc6856c6SDarrick J. Wong 	xfs_btree_commit_ifakeroot(cur, tp, XFS_DATA_FORK);
573fc6856c6SDarrick J. Wong }
574fc6856c6SDarrick J. Wong 
575fc6856c6SDarrick J. Wong /* Calculate number of records in a rt reverse mapping btree block. */
576fc6856c6SDarrick J. Wong static inline unsigned int
577fc6856c6SDarrick J. Wong xfs_rtrmapbt_block_maxrecs(
578fc6856c6SDarrick J. Wong 	unsigned int		blocklen,
579fc6856c6SDarrick J. Wong 	bool			leaf)
580fc6856c6SDarrick J. Wong {
581fc6856c6SDarrick J. Wong 	if (leaf)
582fc6856c6SDarrick J. Wong 		return blocklen / sizeof(struct xfs_rmap_rec);
583fc6856c6SDarrick J. Wong 	return blocklen /
584fc6856c6SDarrick J. Wong 		(2 * sizeof(struct xfs_rmap_key) + sizeof(xfs_rtrmap_ptr_t));
585fc6856c6SDarrick J. Wong }
586fc6856c6SDarrick J. Wong 
587fc6856c6SDarrick J. Wong /*
588fc6856c6SDarrick J. Wong  * Calculate number of records in an rt reverse mapping btree block.
589fc6856c6SDarrick J. Wong  */
590fc6856c6SDarrick J. Wong unsigned int
591fc6856c6SDarrick J. Wong xfs_rtrmapbt_maxrecs(
592fc6856c6SDarrick J. Wong 	struct xfs_mount	*mp,
593fc6856c6SDarrick J. Wong 	unsigned int		blocklen,
594fc6856c6SDarrick J. Wong 	bool			leaf)
595fc6856c6SDarrick J. Wong {
596fc6856c6SDarrick J. Wong 	blocklen -= XFS_RTRMAP_BLOCK_LEN;
597fc6856c6SDarrick J. Wong 	return xfs_rtrmapbt_block_maxrecs(blocklen, leaf);
598fc6856c6SDarrick J. Wong }
599fc6856c6SDarrick J. Wong 
600fc6856c6SDarrick J. Wong /* Compute the max possible height for realtime reverse mapping btrees. */
601fc6856c6SDarrick J. Wong unsigned int
602fc6856c6SDarrick J. Wong xfs_rtrmapbt_maxlevels_ondisk(void)
603fc6856c6SDarrick J. Wong {
604fc6856c6SDarrick J. Wong 	unsigned int		minrecs[2];
605fc6856c6SDarrick J. Wong 	unsigned int		blocklen;
606fc6856c6SDarrick J. Wong 
607fc6856c6SDarrick J. Wong 	blocklen = XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_LBLOCK_CRC_LEN;
608fc6856c6SDarrick J. Wong 
609fc6856c6SDarrick J. Wong 	minrecs[0] = xfs_rtrmapbt_block_maxrecs(blocklen, true) / 2;
610fc6856c6SDarrick J. Wong 	minrecs[1] = xfs_rtrmapbt_block_maxrecs(blocklen, false) / 2;
611fc6856c6SDarrick J. Wong 
612fc6856c6SDarrick J. Wong 	/* We need at most one record for every block in an rt group. */
613fc6856c6SDarrick J. Wong 	return xfs_btree_compute_maxlevels(minrecs, XFS_MAX_RGBLOCKS);
614fc6856c6SDarrick J. Wong }
615fc6856c6SDarrick J. Wong 
616fc6856c6SDarrick J. Wong int __init
617fc6856c6SDarrick J. Wong xfs_rtrmapbt_init_cur_cache(void)
618fc6856c6SDarrick J. Wong {
619fc6856c6SDarrick J. Wong 	xfs_rtrmapbt_cur_cache = kmem_cache_create("xfs_rtrmapbt_cur",
620fc6856c6SDarrick J. Wong 			xfs_btree_cur_sizeof(xfs_rtrmapbt_maxlevels_ondisk()),
621fc6856c6SDarrick J. Wong 			0, 0, NULL);
622fc6856c6SDarrick J. Wong 
623fc6856c6SDarrick J. Wong 	if (!xfs_rtrmapbt_cur_cache)
624fc6856c6SDarrick J. Wong 		return -ENOMEM;
625fc6856c6SDarrick J. Wong 	return 0;
626fc6856c6SDarrick J. Wong }
627fc6856c6SDarrick J. Wong 
628fc6856c6SDarrick J. Wong void
629fc6856c6SDarrick J. Wong xfs_rtrmapbt_destroy_cur_cache(void)
630fc6856c6SDarrick J. Wong {
631fc6856c6SDarrick J. Wong 	kmem_cache_destroy(xfs_rtrmapbt_cur_cache);
632fc6856c6SDarrick J. Wong 	xfs_rtrmapbt_cur_cache = NULL;
633fc6856c6SDarrick J. Wong }
634fc6856c6SDarrick J. Wong 
635fc6856c6SDarrick J. Wong /* Compute the maximum height of an rt reverse mapping btree. */
636fc6856c6SDarrick J. Wong void
637fc6856c6SDarrick J. Wong xfs_rtrmapbt_compute_maxlevels(
638fc6856c6SDarrick J. Wong 	struct xfs_mount	*mp)
639fc6856c6SDarrick J. Wong {
640fc6856c6SDarrick J. Wong 	unsigned int		d_maxlevels, r_maxlevels;
641fc6856c6SDarrick J. Wong 
642fc6856c6SDarrick J. Wong 	if (!xfs_has_rtrmapbt(mp)) {
643fc6856c6SDarrick J. Wong 		mp->m_rtrmap_maxlevels = 0;
644fc6856c6SDarrick J. Wong 		return;
645fc6856c6SDarrick J. Wong 	}
646fc6856c6SDarrick J. Wong 
647fc6856c6SDarrick J. Wong 	/*
648fc6856c6SDarrick J. Wong 	 * The realtime rmapbt lives on the data device, which means that its
649fc6856c6SDarrick J. Wong 	 * maximum height is constrained by the size of the data device and
650fc6856c6SDarrick J. Wong 	 * the height required to store one rmap record for each block in an
651fc6856c6SDarrick J. Wong 	 * rt group.
652fc6856c6SDarrick J. Wong 	 */
653fc6856c6SDarrick J. Wong 	d_maxlevels = xfs_btree_space_to_height(mp->m_rtrmap_mnr,
654fc6856c6SDarrick J. Wong 				mp->m_sb.sb_dblocks);
655fc6856c6SDarrick J. Wong 	r_maxlevels = xfs_btree_compute_maxlevels(mp->m_rtrmap_mnr,
656fc6856c6SDarrick J. Wong 				mp->m_groups[XG_TYPE_RTG].blocks);
657fc6856c6SDarrick J. Wong 
658fc6856c6SDarrick J. Wong 	/* Add one level to handle the inode root level. */
659fc6856c6SDarrick J. Wong 	mp->m_rtrmap_maxlevels = min(d_maxlevels, r_maxlevels) + 1;
660fc6856c6SDarrick J. Wong }
6618491a55cSDarrick J. Wong 
6628491a55cSDarrick J. Wong /* Calculate the rtrmap btree size for some records. */
6638491a55cSDarrick J. Wong static unsigned long long
6648491a55cSDarrick J. Wong xfs_rtrmapbt_calc_size(
6658491a55cSDarrick J. Wong 	struct xfs_mount	*mp,
6668491a55cSDarrick J. Wong 	unsigned long long	len)
6678491a55cSDarrick J. Wong {
6688491a55cSDarrick J. Wong 	return xfs_btree_calc_size(mp->m_rtrmap_mnr, len);
6698491a55cSDarrick J. Wong }
6708491a55cSDarrick J. Wong 
6718491a55cSDarrick J. Wong /*
6728491a55cSDarrick J. Wong  * Calculate the maximum rmap btree size.
6738491a55cSDarrick J. Wong  */
6748491a55cSDarrick J. Wong static unsigned long long
6758491a55cSDarrick J. Wong xfs_rtrmapbt_max_size(
6768491a55cSDarrick J. Wong 	struct xfs_mount	*mp,
6778491a55cSDarrick J. Wong 	xfs_rtblock_t		rtblocks)
6788491a55cSDarrick J. Wong {
6798491a55cSDarrick J. Wong 	/* Bail out if we're uninitialized, which can happen in mkfs. */
6808491a55cSDarrick J. Wong 	if (mp->m_rtrmap_mxr[0] == 0)
6818491a55cSDarrick J. Wong 		return 0;
6828491a55cSDarrick J. Wong 
6838491a55cSDarrick J. Wong 	return xfs_rtrmapbt_calc_size(mp, rtblocks);
6848491a55cSDarrick J. Wong }
6858491a55cSDarrick J. Wong 
6868491a55cSDarrick J. Wong /*
6878491a55cSDarrick J. Wong  * Figure out how many blocks to reserve and how many are used by this btree.
6888491a55cSDarrick J. Wong  */
6898491a55cSDarrick J. Wong xfs_filblks_t
6908491a55cSDarrick J. Wong xfs_rtrmapbt_calc_reserves(
6918491a55cSDarrick J. Wong 	struct xfs_mount	*mp)
6928491a55cSDarrick J. Wong {
6938491a55cSDarrick J. Wong 	uint32_t		blocks = mp->m_groups[XG_TYPE_RTG].blocks;
6948491a55cSDarrick J. Wong 
6958491a55cSDarrick J. Wong 	if (!xfs_has_rtrmapbt(mp))
6968491a55cSDarrick J. Wong 		return 0;
6978491a55cSDarrick J. Wong 
6988491a55cSDarrick J. Wong 	/* Reserve 1% of the rtgroup or enough for 1 block per record. */
6998491a55cSDarrick J. Wong 	return max_t(xfs_filblks_t, blocks / 100,
7008491a55cSDarrick J. Wong 			xfs_rtrmapbt_max_size(mp, blocks));
7018491a55cSDarrick J. Wong }
702f33659e8SDarrick J. Wong 
703f33659e8SDarrick J. Wong /* Convert on-disk form of btree root to in-memory form. */
704f33659e8SDarrick J. Wong STATIC void
705f33659e8SDarrick J. Wong xfs_rtrmapbt_from_disk(
706f33659e8SDarrick J. Wong 	struct xfs_inode	*ip,
707f33659e8SDarrick J. Wong 	struct xfs_rtrmap_root	*dblock,
708f33659e8SDarrick J. Wong 	unsigned int		dblocklen,
709f33659e8SDarrick J. Wong 	struct xfs_btree_block	*rblock)
710f33659e8SDarrick J. Wong {
711f33659e8SDarrick J. Wong 	struct xfs_mount	*mp = ip->i_mount;
712f33659e8SDarrick J. Wong 	struct xfs_rmap_key	*fkp;
713f33659e8SDarrick J. Wong 	__be64			*fpp;
714f33659e8SDarrick J. Wong 	struct xfs_rmap_key	*tkp;
715f33659e8SDarrick J. Wong 	__be64			*tpp;
716f33659e8SDarrick J. Wong 	struct xfs_rmap_rec	*frp;
717f33659e8SDarrick J. Wong 	struct xfs_rmap_rec	*trp;
718f33659e8SDarrick J. Wong 	unsigned int		rblocklen = xfs_rtrmap_broot_space(mp, dblock);
719f33659e8SDarrick J. Wong 	unsigned int		numrecs;
720f33659e8SDarrick J. Wong 	unsigned int		maxrecs;
721f33659e8SDarrick J. Wong 
722f33659e8SDarrick J. Wong 	xfs_btree_init_block(mp, rblock, &xfs_rtrmapbt_ops, 0, 0, ip->i_ino);
723f33659e8SDarrick J. Wong 
724f33659e8SDarrick J. Wong 	rblock->bb_level = dblock->bb_level;
725f33659e8SDarrick J. Wong 	rblock->bb_numrecs = dblock->bb_numrecs;
726f33659e8SDarrick J. Wong 	numrecs = be16_to_cpu(dblock->bb_numrecs);
727f33659e8SDarrick J. Wong 
728f33659e8SDarrick J. Wong 	if (be16_to_cpu(rblock->bb_level) > 0) {
729f33659e8SDarrick J. Wong 		maxrecs = xfs_rtrmapbt_droot_maxrecs(dblocklen, false);
730f33659e8SDarrick J. Wong 		fkp = xfs_rtrmap_droot_key_addr(dblock, 1);
731f33659e8SDarrick J. Wong 		tkp = xfs_rtrmap_key_addr(rblock, 1);
732f33659e8SDarrick J. Wong 		fpp = xfs_rtrmap_droot_ptr_addr(dblock, 1, maxrecs);
733f33659e8SDarrick J. Wong 		tpp = xfs_rtrmap_broot_ptr_addr(mp, rblock, 1, rblocklen);
734f33659e8SDarrick J. Wong 		memcpy(tkp, fkp, 2 * sizeof(*fkp) * numrecs);
735f33659e8SDarrick J. Wong 		memcpy(tpp, fpp, sizeof(*fpp) * numrecs);
736f33659e8SDarrick J. Wong 	} else {
737f33659e8SDarrick J. Wong 		frp = xfs_rtrmap_droot_rec_addr(dblock, 1);
738f33659e8SDarrick J. Wong 		trp = xfs_rtrmap_rec_addr(rblock, 1);
739f33659e8SDarrick J. Wong 		memcpy(trp, frp, sizeof(*frp) * numrecs);
740f33659e8SDarrick J. Wong 	}
741f33659e8SDarrick J. Wong }
742f33659e8SDarrick J. Wong 
743f33659e8SDarrick J. Wong /* Load a realtime reverse mapping btree root in from disk. */
744f33659e8SDarrick J. Wong int
745f33659e8SDarrick J. Wong xfs_iformat_rtrmap(
746f33659e8SDarrick J. Wong 	struct xfs_inode	*ip,
747f33659e8SDarrick J. Wong 	struct xfs_dinode	*dip)
748f33659e8SDarrick J. Wong {
749f33659e8SDarrick J. Wong 	struct xfs_mount	*mp = ip->i_mount;
750f33659e8SDarrick J. Wong 	struct xfs_rtrmap_root	*dfp = XFS_DFORK_PTR(dip, XFS_DATA_FORK);
751f33659e8SDarrick J. Wong 	struct xfs_btree_block	*broot;
752f33659e8SDarrick J. Wong 	unsigned int		numrecs;
753f33659e8SDarrick J. Wong 	unsigned int		level;
754f33659e8SDarrick J. Wong 	int			dsize;
755f33659e8SDarrick J. Wong 
756f33659e8SDarrick J. Wong 	/*
757f33659e8SDarrick J. Wong 	 * growfs must create the rtrmap inodes before adding a realtime volume
758f33659e8SDarrick J. Wong 	 * to the filesystem, so we cannot use the rtrmapbt predicate here.
759f33659e8SDarrick J. Wong 	 */
760*6d4933c2SDarrick J. Wong 	if (!xfs_has_rmapbt(ip->i_mount)) {
761*6d4933c2SDarrick J. Wong 		xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);
762f33659e8SDarrick J. Wong 		return -EFSCORRUPTED;
763*6d4933c2SDarrick J. Wong 	}
764f33659e8SDarrick J. Wong 
765f33659e8SDarrick J. Wong 	dsize = XFS_DFORK_SIZE(dip, mp, XFS_DATA_FORK);
766f33659e8SDarrick J. Wong 	numrecs = be16_to_cpu(dfp->bb_numrecs);
767f33659e8SDarrick J. Wong 	level = be16_to_cpu(dfp->bb_level);
768f33659e8SDarrick J. Wong 
769f33659e8SDarrick J. Wong 	if (level > mp->m_rtrmap_maxlevels ||
770*6d4933c2SDarrick J. Wong 	    xfs_rtrmap_droot_space_calc(level, numrecs) > dsize) {
771*6d4933c2SDarrick J. Wong 		xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);
772f33659e8SDarrick J. Wong 		return -EFSCORRUPTED;
773*6d4933c2SDarrick J. Wong 	}
774f33659e8SDarrick J. Wong 
775f33659e8SDarrick J. Wong 	broot = xfs_broot_alloc(xfs_ifork_ptr(ip, XFS_DATA_FORK),
776f33659e8SDarrick J. Wong 			xfs_rtrmap_broot_space_calc(mp, level, numrecs));
777f33659e8SDarrick J. Wong 	if (broot)
778f33659e8SDarrick J. Wong 		xfs_rtrmapbt_from_disk(ip, dfp, dsize, broot);
779f33659e8SDarrick J. Wong 	return 0;
780f33659e8SDarrick J. Wong }
781f33659e8SDarrick J. Wong 
782f33659e8SDarrick J. Wong /* Convert in-memory form of btree root to on-disk form. */
783f33659e8SDarrick J. Wong void
784f33659e8SDarrick J. Wong xfs_rtrmapbt_to_disk(
785f33659e8SDarrick J. Wong 	struct xfs_mount	*mp,
786f33659e8SDarrick J. Wong 	struct xfs_btree_block	*rblock,
787f33659e8SDarrick J. Wong 	unsigned int		rblocklen,
788f33659e8SDarrick J. Wong 	struct xfs_rtrmap_root	*dblock,
789f33659e8SDarrick J. Wong 	unsigned int		dblocklen)
790f33659e8SDarrick J. Wong {
791f33659e8SDarrick J. Wong 	struct xfs_rmap_key	*fkp;
792f33659e8SDarrick J. Wong 	__be64			*fpp;
793f33659e8SDarrick J. Wong 	struct xfs_rmap_key	*tkp;
794f33659e8SDarrick J. Wong 	__be64			*tpp;
795f33659e8SDarrick J. Wong 	struct xfs_rmap_rec	*frp;
796f33659e8SDarrick J. Wong 	struct xfs_rmap_rec	*trp;
797f33659e8SDarrick J. Wong 	unsigned int		numrecs;
798f33659e8SDarrick J. Wong 	unsigned int		maxrecs;
799f33659e8SDarrick J. Wong 
800f33659e8SDarrick J. Wong 	ASSERT(rblock->bb_magic == cpu_to_be32(XFS_RTRMAP_CRC_MAGIC));
801f33659e8SDarrick J. Wong 	ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid));
802f33659e8SDarrick J. Wong 	ASSERT(rblock->bb_u.l.bb_blkno == cpu_to_be64(XFS_BUF_DADDR_NULL));
803f33659e8SDarrick J. Wong 	ASSERT(rblock->bb_u.l.bb_leftsib == cpu_to_be64(NULLFSBLOCK));
804f33659e8SDarrick J. Wong 	ASSERT(rblock->bb_u.l.bb_rightsib == cpu_to_be64(NULLFSBLOCK));
805f33659e8SDarrick J. Wong 
806f33659e8SDarrick J. Wong 	dblock->bb_level = rblock->bb_level;
807f33659e8SDarrick J. Wong 	dblock->bb_numrecs = rblock->bb_numrecs;
808f33659e8SDarrick J. Wong 	numrecs = be16_to_cpu(rblock->bb_numrecs);
809f33659e8SDarrick J. Wong 
810f33659e8SDarrick J. Wong 	if (be16_to_cpu(rblock->bb_level) > 0) {
811f33659e8SDarrick J. Wong 		maxrecs = xfs_rtrmapbt_droot_maxrecs(dblocklen, false);
812f33659e8SDarrick J. Wong 		fkp = xfs_rtrmap_key_addr(rblock, 1);
813f33659e8SDarrick J. Wong 		tkp = xfs_rtrmap_droot_key_addr(dblock, 1);
814f33659e8SDarrick J. Wong 		fpp = xfs_rtrmap_broot_ptr_addr(mp, rblock, 1, rblocklen);
815f33659e8SDarrick J. Wong 		tpp = xfs_rtrmap_droot_ptr_addr(dblock, 1, maxrecs);
816f33659e8SDarrick J. Wong 		memcpy(tkp, fkp, 2 * sizeof(*fkp) * numrecs);
817f33659e8SDarrick J. Wong 		memcpy(tpp, fpp, sizeof(*fpp) * numrecs);
818f33659e8SDarrick J. Wong 	} else {
819f33659e8SDarrick J. Wong 		frp = xfs_rtrmap_rec_addr(rblock, 1);
820f33659e8SDarrick J. Wong 		trp = xfs_rtrmap_droot_rec_addr(dblock, 1);
821f33659e8SDarrick J. Wong 		memcpy(trp, frp, sizeof(*frp) * numrecs);
822f33659e8SDarrick J. Wong 	}
823f33659e8SDarrick J. Wong }
824f33659e8SDarrick J. Wong 
825f33659e8SDarrick J. Wong /* Flush a realtime reverse mapping btree root out to disk. */
826f33659e8SDarrick J. Wong void
827f33659e8SDarrick J. Wong xfs_iflush_rtrmap(
828f33659e8SDarrick J. Wong 	struct xfs_inode	*ip,
829f33659e8SDarrick J. Wong 	struct xfs_dinode	*dip)
830f33659e8SDarrick J. Wong {
831f33659e8SDarrick J. Wong 	struct xfs_ifork	*ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);
832f33659e8SDarrick J. Wong 	struct xfs_rtrmap_root	*dfp = XFS_DFORK_PTR(dip, XFS_DATA_FORK);
833f33659e8SDarrick J. Wong 
834f33659e8SDarrick J. Wong 	ASSERT(ifp->if_broot != NULL);
835f33659e8SDarrick J. Wong 	ASSERT(ifp->if_broot_bytes > 0);
836f33659e8SDarrick J. Wong 	ASSERT(xfs_rtrmap_droot_space(ifp->if_broot) <=
837f33659e8SDarrick J. Wong 			xfs_inode_fork_size(ip, XFS_DATA_FORK));
838f33659e8SDarrick J. Wong 	xfs_rtrmapbt_to_disk(ip->i_mount, ifp->if_broot, ifp->if_broot_bytes,
839f33659e8SDarrick J. Wong 			dfp, XFS_DFORK_SIZE(dip, ip->i_mount, XFS_DATA_FORK));
840f33659e8SDarrick J. Wong }
84171b8acb4SDarrick J. Wong 
84271b8acb4SDarrick J. Wong /*
84371b8acb4SDarrick J. Wong  * Create a realtime rmap btree inode.
84471b8acb4SDarrick J. Wong  */
84571b8acb4SDarrick J. Wong int
84671b8acb4SDarrick J. Wong xfs_rtrmapbt_create(
84771b8acb4SDarrick J. Wong 	struct xfs_rtgroup	*rtg,
84871b8acb4SDarrick J. Wong 	struct xfs_inode	*ip,
84971b8acb4SDarrick J. Wong 	struct xfs_trans	*tp,
85071b8acb4SDarrick J. Wong 	bool			init)
85171b8acb4SDarrick J. Wong {
85271b8acb4SDarrick J. Wong 	struct xfs_ifork	*ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);
85371b8acb4SDarrick J. Wong 	struct xfs_mount	*mp = ip->i_mount;
85471b8acb4SDarrick J. Wong 	struct xfs_btree_block	*broot;
85571b8acb4SDarrick J. Wong 
85671b8acb4SDarrick J. Wong 	ifp->if_format = XFS_DINODE_FMT_META_BTREE;
85771b8acb4SDarrick J. Wong 	ASSERT(ifp->if_broot_bytes == 0);
85871b8acb4SDarrick J. Wong 	ASSERT(ifp->if_bytes == 0);
85971b8acb4SDarrick J. Wong 
86071b8acb4SDarrick J. Wong 	/* Initialize the empty incore btree root. */
86171b8acb4SDarrick J. Wong 	broot = xfs_broot_realloc(ifp, xfs_rtrmap_broot_space_calc(mp, 0, 0));
86271b8acb4SDarrick J. Wong 	if (broot)
86371b8acb4SDarrick J. Wong 		xfs_btree_init_block(mp, broot, &xfs_rtrmapbt_ops, 0, 0,
86471b8acb4SDarrick J. Wong 				ip->i_ino);
86571b8acb4SDarrick J. Wong 	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE | XFS_ILOG_DBROOT);
86671b8acb4SDarrick J. Wong 
86771b8acb4SDarrick J. Wong 	return 0;
86871b8acb4SDarrick J. Wong }
86971b8acb4SDarrick J. Wong 
87071b8acb4SDarrick J. Wong /*
87171b8acb4SDarrick J. Wong  * Initialize an rmap for a realtime superblock using the potentially updated
87271b8acb4SDarrick J. Wong  * rt geometry in the provided @mp.
87371b8acb4SDarrick J. Wong  */
87471b8acb4SDarrick J. Wong int
87571b8acb4SDarrick J. Wong xfs_rtrmapbt_init_rtsb(
87671b8acb4SDarrick J. Wong 	struct xfs_mount	*mp,
87771b8acb4SDarrick J. Wong 	struct xfs_rtgroup	*rtg,
87871b8acb4SDarrick J. Wong 	struct xfs_trans	*tp)
87971b8acb4SDarrick J. Wong {
88071b8acb4SDarrick J. Wong 	struct xfs_rmap_irec	rmap = {
88171b8acb4SDarrick J. Wong 		.rm_blockcount	= mp->m_sb.sb_rextsize,
88271b8acb4SDarrick J. Wong 		.rm_owner	= XFS_RMAP_OWN_FS,
88371b8acb4SDarrick J. Wong 	};
88471b8acb4SDarrick J. Wong 	struct xfs_btree_cur	*cur;
88571b8acb4SDarrick J. Wong 	int			error;
88671b8acb4SDarrick J. Wong 
88771b8acb4SDarrick J. Wong 	ASSERT(xfs_has_rtsb(mp));
88871b8acb4SDarrick J. Wong 	ASSERT(rtg_rgno(rtg) == 0);
88971b8acb4SDarrick J. Wong 
89071b8acb4SDarrick J. Wong 	cur = xfs_rtrmapbt_init_cursor(tp, rtg);
89171b8acb4SDarrick J. Wong 	error = xfs_rmap_map_raw(cur, &rmap);
89271b8acb4SDarrick J. Wong 	xfs_btree_del_cursor(cur, error);
89371b8acb4SDarrick J. Wong 	return error;
89471b8acb4SDarrick J. Wong }
895