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