xref: /openbmc/linux/fs/xfs/libxfs/xfs_rmap_btree.c (revision 4a200a09)
10b61f8a4SDave Chinner // SPDX-License-Identifier: GPL-2.0
2035e00acSDarrick J. Wong /*
3035e00acSDarrick J. Wong  * Copyright (c) 2014 Red Hat, Inc.
4035e00acSDarrick J. Wong  * All Rights Reserved.
5035e00acSDarrick J. Wong  */
6035e00acSDarrick J. Wong #include "xfs.h"
7035e00acSDarrick J. Wong #include "xfs_fs.h"
8035e00acSDarrick J. Wong #include "xfs_shared.h"
9035e00acSDarrick J. Wong #include "xfs_format.h"
10035e00acSDarrick J. Wong #include "xfs_log_format.h"
11035e00acSDarrick J. Wong #include "xfs_trans_resv.h"
12035e00acSDarrick J. Wong #include "xfs_mount.h"
13035e00acSDarrick J. Wong #include "xfs_trans.h"
14035e00acSDarrick J. Wong #include "xfs_alloc.h"
15035e00acSDarrick J. Wong #include "xfs_btree.h"
1659d67712SDarrick J. Wong #include "xfs_btree_staging.h"
174b8ed677SDarrick J. Wong #include "xfs_rmap.h"
18035e00acSDarrick J. Wong #include "xfs_rmap_btree.h"
19035e00acSDarrick J. Wong #include "xfs_trace.h"
20035e00acSDarrick J. Wong #include "xfs_error.h"
21035e00acSDarrick J. Wong #include "xfs_extent_busy.h"
229bbafc71SDave Chinner #include "xfs_ag.h"
2384d69619SDarrick J. Wong #include "xfs_ag_resv.h"
24035e00acSDarrick J. Wong 
25e7720afaSDarrick J. Wong static struct kmem_cache	*xfs_rmapbt_cur_cache;
269fa47bdcSDarrick J. Wong 
274b8ed677SDarrick J. Wong /*
284b8ed677SDarrick J. Wong  * Reverse map btree.
294b8ed677SDarrick J. Wong  *
304b8ed677SDarrick J. Wong  * This is a per-ag tree used to track the owner(s) of a given extent. With
314b8ed677SDarrick J. Wong  * reflink it is possible for there to be multiple owners, which is a departure
324b8ed677SDarrick J. Wong  * from classic XFS. Owner records for data extents are inserted when the
334b8ed677SDarrick J. Wong  * extent is mapped and removed when an extent is unmapped.  Owner records for
344b8ed677SDarrick J. Wong  * all other block types (i.e. metadata) are inserted when an extent is
354b8ed677SDarrick J. Wong  * allocated and removed when an extent is freed. There can only be one owner
364b8ed677SDarrick J. Wong  * of a metadata extent, usually an inode or some other metadata structure like
374b8ed677SDarrick J. Wong  * an AG btree.
384b8ed677SDarrick J. Wong  *
394b8ed677SDarrick J. Wong  * The rmap btree is part of the free space management, so blocks for the tree
404b8ed677SDarrick J. Wong  * are sourced from the agfl. Hence we need transaction reservation support for
414b8ed677SDarrick J. Wong  * this tree so that the freelist is always large enough. This also impacts on
424b8ed677SDarrick J. Wong  * the minimum space we need to leave free in the AG.
434b8ed677SDarrick J. Wong  *
444b8ed677SDarrick J. Wong  * The tree is ordered by [ag block, owner, offset]. This is a large key size,
454b8ed677SDarrick J. Wong  * but it is the only way to enforce unique keys when a block can be owned by
464b8ed677SDarrick J. Wong  * multiple files at any offset. There's no need to order/search by extent
474b8ed677SDarrick J. Wong  * size for online updating/management of the tree. It is intended that most
484b8ed677SDarrick J. Wong  * reverse lookups will be to find the owner(s) of a particular block, or to
494b8ed677SDarrick J. Wong  * try to recover tree and file data from corrupt primary metadata.
504b8ed677SDarrick J. Wong  */
514b8ed677SDarrick J. Wong 
52035e00acSDarrick J. Wong static struct xfs_btree_cur *
xfs_rmapbt_dup_cursor(struct xfs_btree_cur * cur)53035e00acSDarrick J. Wong xfs_rmapbt_dup_cursor(
54035e00acSDarrick J. Wong 	struct xfs_btree_cur	*cur)
55035e00acSDarrick J. Wong {
56035e00acSDarrick J. Wong 	return xfs_rmapbt_init_cursor(cur->bc_mp, cur->bc_tp,
57fa9c3c19SDave Chinner 				cur->bc_ag.agbp, cur->bc_ag.pag);
58035e00acSDarrick J. Wong }
59035e00acSDarrick J. Wong 
604b8ed677SDarrick J. Wong STATIC void
xfs_rmapbt_set_root(struct xfs_btree_cur * cur,const union xfs_btree_ptr * ptr,int inc)614b8ed677SDarrick J. Wong xfs_rmapbt_set_root(
624b8ed677SDarrick J. Wong 	struct xfs_btree_cur		*cur,
63b5a6e5feSDarrick J. Wong 	const union xfs_btree_ptr	*ptr,
644b8ed677SDarrick J. Wong 	int				inc)
654b8ed677SDarrick J. Wong {
66576af732SDave Chinner 	struct xfs_buf		*agbp = cur->bc_ag.agbp;
679798f615SChristoph Hellwig 	struct xfs_agf		*agf = agbp->b_addr;
684b8ed677SDarrick J. Wong 	int			btnum = cur->bc_btnum;
694b8ed677SDarrick J. Wong 
704b8ed677SDarrick J. Wong 	ASSERT(ptr->s != 0);
714b8ed677SDarrick J. Wong 
724b8ed677SDarrick J. Wong 	agf->agf_roots[btnum] = ptr->s;
734b8ed677SDarrick J. Wong 	be32_add_cpu(&agf->agf_levels[btnum], inc);
74fa9c3c19SDave Chinner 	cur->bc_ag.pag->pagf_levels[btnum] += inc;
754b8ed677SDarrick J. Wong 
764b8ed677SDarrick J. Wong 	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS);
774b8ed677SDarrick J. Wong }
784b8ed677SDarrick J. Wong 
794b8ed677SDarrick J. Wong STATIC int
xfs_rmapbt_alloc_block(struct xfs_btree_cur * cur,const union xfs_btree_ptr * start,union xfs_btree_ptr * new,int * stat)804b8ed677SDarrick J. Wong xfs_rmapbt_alloc_block(
814b8ed677SDarrick J. Wong 	struct xfs_btree_cur		*cur,
82deb06b9aSDarrick J. Wong 	const union xfs_btree_ptr	*start,
834b8ed677SDarrick J. Wong 	union xfs_btree_ptr		*new,
844b8ed677SDarrick J. Wong 	int				*stat)
854b8ed677SDarrick J. Wong {
86576af732SDave Chinner 	struct xfs_buf		*agbp = cur->bc_ag.agbp;
879798f615SChristoph Hellwig 	struct xfs_agf		*agf = agbp->b_addr;
88fa9c3c19SDave Chinner 	struct xfs_perag	*pag = cur->bc_ag.pag;
894b8ed677SDarrick J. Wong 	int			error;
904b8ed677SDarrick J. Wong 	xfs_agblock_t		bno;
914b8ed677SDarrick J. Wong 
924b8ed677SDarrick J. Wong 	/* Allocate the new block from the freelist. If we can't, give up.  */
9349f0d84eSDave Chinner 	error = xfs_alloc_get_freelist(pag, cur->bc_tp, cur->bc_ag.agbp,
944b8ed677SDarrick J. Wong 				       &bno, 1);
95e157ebdcSCarlos Maiolino 	if (error)
964b8ed677SDarrick J. Wong 		return error;
974b8ed677SDarrick J. Wong 
98fa9c3c19SDave Chinner 	trace_xfs_rmapbt_alloc_block(cur->bc_mp, pag->pag_agno, bno, 1);
994b8ed677SDarrick J. Wong 	if (bno == NULLAGBLOCK) {
1004b8ed677SDarrick J. Wong 		*stat = 0;
1014b8ed677SDarrick J. Wong 		return 0;
1024b8ed677SDarrick J. Wong 	}
1034b8ed677SDarrick J. Wong 
104fa9c3c19SDave Chinner 	xfs_extent_busy_reuse(cur->bc_mp, pag, bno, 1, false);
1054b8ed677SDarrick J. Wong 
1064b8ed677SDarrick J. Wong 	new->s = cpu_to_be32(bno);
107f32866fdSDarrick J. Wong 	be32_add_cpu(&agf->agf_rmap_blocks, 1);
108f32866fdSDarrick J. Wong 	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS);
1094b8ed677SDarrick J. Wong 
110fa9c3c19SDave Chinner 	xfs_ag_resv_rmapbt_alloc(cur->bc_mp, pag->pag_agno);
1110ab32086SBrian Foster 
1124b8ed677SDarrick J. Wong 	*stat = 1;
1134b8ed677SDarrick J. Wong 	return 0;
1144b8ed677SDarrick J. Wong }
1154b8ed677SDarrick J. Wong 
1164b8ed677SDarrick J. Wong STATIC int
xfs_rmapbt_free_block(struct xfs_btree_cur * cur,struct xfs_buf * bp)1174b8ed677SDarrick J. Wong xfs_rmapbt_free_block(
1184b8ed677SDarrick J. Wong 	struct xfs_btree_cur	*cur,
1194b8ed677SDarrick J. Wong 	struct xfs_buf		*bp)
1204b8ed677SDarrick J. Wong {
121576af732SDave Chinner 	struct xfs_buf		*agbp = cur->bc_ag.agbp;
1229798f615SChristoph Hellwig 	struct xfs_agf		*agf = agbp->b_addr;
123fa9c3c19SDave Chinner 	struct xfs_perag	*pag = cur->bc_ag.pag;
1244b8ed677SDarrick J. Wong 	xfs_agblock_t		bno;
1254b8ed677SDarrick J. Wong 	int			error;
1264b8ed677SDarrick J. Wong 
12704fcad80SDave Chinner 	bno = xfs_daddr_to_agbno(cur->bc_mp, xfs_buf_daddr(bp));
128fa9c3c19SDave Chinner 	trace_xfs_rmapbt_free_block(cur->bc_mp, pag->pag_agno,
1294b8ed677SDarrick J. Wong 			bno, 1);
130f32866fdSDarrick J. Wong 	be32_add_cpu(&agf->agf_rmap_blocks, -1);
131f32866fdSDarrick J. Wong 	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS);
1328c392eb2SDave Chinner 	error = xfs_alloc_put_freelist(pag, cur->bc_tp, agbp, NULL, bno, 1);
1334b8ed677SDarrick J. Wong 	if (error)
1344b8ed677SDarrick J. Wong 		return error;
1354b8ed677SDarrick J. Wong 
13645d06621SDave Chinner 	xfs_extent_busy_insert(cur->bc_tp, pag, bno, 1,
1374b8ed677SDarrick J. Wong 			      XFS_EXTENT_BUSY_SKIP_DISCARD);
1384b8ed677SDarrick J. Wong 
13992a00544SGao Xiang 	xfs_ag_resv_free_extent(pag, XFS_AG_RESV_RMAPBT, NULL, 1);
1404b8ed677SDarrick J. Wong 	return 0;
1414b8ed677SDarrick J. Wong }
1424b8ed677SDarrick J. Wong 
1434b8ed677SDarrick J. Wong STATIC int
xfs_rmapbt_get_minrecs(struct xfs_btree_cur * cur,int level)1444b8ed677SDarrick J. Wong xfs_rmapbt_get_minrecs(
1454b8ed677SDarrick J. Wong 	struct xfs_btree_cur	*cur,
1464b8ed677SDarrick J. Wong 	int			level)
1474b8ed677SDarrick J. Wong {
1484b8ed677SDarrick J. Wong 	return cur->bc_mp->m_rmap_mnr[level != 0];
1494b8ed677SDarrick J. Wong }
1504b8ed677SDarrick J. Wong 
1514b8ed677SDarrick J. Wong STATIC int
xfs_rmapbt_get_maxrecs(struct xfs_btree_cur * cur,int level)1524b8ed677SDarrick J. Wong xfs_rmapbt_get_maxrecs(
1534b8ed677SDarrick J. Wong 	struct xfs_btree_cur	*cur,
1544b8ed677SDarrick J. Wong 	int			level)
1554b8ed677SDarrick J. Wong {
1564b8ed677SDarrick J. Wong 	return cur->bc_mp->m_rmap_mxr[level != 0];
1574b8ed677SDarrick J. Wong }
1584b8ed677SDarrick J. Wong 
15908c987deSDarrick J. Wong /*
16008c987deSDarrick J. Wong  * Convert the ondisk record's offset field into the ondisk key's offset field.
16108c987deSDarrick J. Wong  * Fork and bmbt are significant parts of the rmap record key, but written
16208c987deSDarrick J. Wong  * status is merely a record attribute.
16308c987deSDarrick J. Wong  */
ondisk_rec_offset_to_key(const union xfs_btree_rec * rec)16408c987deSDarrick J. Wong static inline __be64 ondisk_rec_offset_to_key(const union xfs_btree_rec *rec)
16508c987deSDarrick J. Wong {
16608c987deSDarrick J. Wong 	return rec->rmap.rm_offset & ~cpu_to_be64(XFS_RMAP_OFF_UNWRITTEN);
16708c987deSDarrick J. Wong }
16808c987deSDarrick J. Wong 
1694b8ed677SDarrick J. Wong STATIC void
xfs_rmapbt_init_key_from_rec(union xfs_btree_key * key,const union xfs_btree_rec * rec)1704b8ed677SDarrick J. Wong xfs_rmapbt_init_key_from_rec(
1714b8ed677SDarrick J. Wong 	union xfs_btree_key		*key,
17223825cd1SDarrick J. Wong 	const union xfs_btree_rec	*rec)
1734b8ed677SDarrick J. Wong {
1744b8ed677SDarrick J. Wong 	key->rmap.rm_startblock = rec->rmap.rm_startblock;
1754b8ed677SDarrick J. Wong 	key->rmap.rm_owner = rec->rmap.rm_owner;
17608c987deSDarrick J. Wong 	key->rmap.rm_offset = ondisk_rec_offset_to_key(rec);
1774b8ed677SDarrick J. Wong }
1784b8ed677SDarrick J. Wong 
179cfed56aeSDarrick J. Wong /*
180cfed56aeSDarrick J. Wong  * The high key for a reverse mapping record can be computed by shifting
181cfed56aeSDarrick J. Wong  * the startblock and offset to the highest value that would still map
182cfed56aeSDarrick J. Wong  * to that record.  In practice this means that we add blockcount-1 to
183cfed56aeSDarrick J. Wong  * the startblock for all records, and if the record is for a data/attr
184cfed56aeSDarrick J. Wong  * fork mapping, we add blockcount-1 to the offset too.
185cfed56aeSDarrick J. Wong  */
186cfed56aeSDarrick J. Wong STATIC void
xfs_rmapbt_init_high_key_from_rec(union xfs_btree_key * key,const union xfs_btree_rec * rec)187cfed56aeSDarrick J. Wong xfs_rmapbt_init_high_key_from_rec(
188cfed56aeSDarrick J. Wong 	union xfs_btree_key		*key,
18923825cd1SDarrick J. Wong 	const union xfs_btree_rec	*rec)
190cfed56aeSDarrick J. Wong {
191c8ce540dSDarrick J. Wong 	uint64_t			off;
192cfed56aeSDarrick J. Wong 	int				adj;
193cfed56aeSDarrick J. Wong 
194cfed56aeSDarrick J. Wong 	adj = be32_to_cpu(rec->rmap.rm_blockcount) - 1;
195cfed56aeSDarrick J. Wong 
196cfed56aeSDarrick J. Wong 	key->rmap.rm_startblock = rec->rmap.rm_startblock;
197cfed56aeSDarrick J. Wong 	be32_add_cpu(&key->rmap.rm_startblock, adj);
198cfed56aeSDarrick J. Wong 	key->rmap.rm_owner = rec->rmap.rm_owner;
19908c987deSDarrick J. Wong 	key->rmap.rm_offset = ondisk_rec_offset_to_key(rec);
200cfed56aeSDarrick J. Wong 	if (XFS_RMAP_NON_INODE_OWNER(be64_to_cpu(rec->rmap.rm_owner)) ||
201cfed56aeSDarrick J. Wong 	    XFS_RMAP_IS_BMBT_BLOCK(be64_to_cpu(rec->rmap.rm_offset)))
202cfed56aeSDarrick J. Wong 		return;
203cfed56aeSDarrick J. Wong 	off = be64_to_cpu(key->rmap.rm_offset);
204cfed56aeSDarrick J. Wong 	off = (XFS_RMAP_OFF(off) + adj) | (off & ~XFS_RMAP_OFF_MASK);
205cfed56aeSDarrick J. Wong 	key->rmap.rm_offset = cpu_to_be64(off);
206cfed56aeSDarrick J. Wong }
207cfed56aeSDarrick J. Wong 
2084b8ed677SDarrick J. Wong STATIC void
xfs_rmapbt_init_rec_from_cur(struct xfs_btree_cur * cur,union xfs_btree_rec * rec)2094b8ed677SDarrick J. Wong xfs_rmapbt_init_rec_from_cur(
2104b8ed677SDarrick J. Wong 	struct xfs_btree_cur	*cur,
2114b8ed677SDarrick J. Wong 	union xfs_btree_rec	*rec)
2124b8ed677SDarrick J. Wong {
2134b8ed677SDarrick J. Wong 	rec->rmap.rm_startblock = cpu_to_be32(cur->bc_rec.r.rm_startblock);
2144b8ed677SDarrick J. Wong 	rec->rmap.rm_blockcount = cpu_to_be32(cur->bc_rec.r.rm_blockcount);
2154b8ed677SDarrick J. Wong 	rec->rmap.rm_owner = cpu_to_be64(cur->bc_rec.r.rm_owner);
2164b8ed677SDarrick J. Wong 	rec->rmap.rm_offset = cpu_to_be64(
2174b8ed677SDarrick J. Wong 			xfs_rmap_irec_offset_pack(&cur->bc_rec.r));
2184b8ed677SDarrick J. Wong }
2194b8ed677SDarrick J. Wong 
2204b8ed677SDarrick J. Wong STATIC void
xfs_rmapbt_init_ptr_from_cur(struct xfs_btree_cur * cur,union xfs_btree_ptr * ptr)2214b8ed677SDarrick J. Wong xfs_rmapbt_init_ptr_from_cur(
2224b8ed677SDarrick J. Wong 	struct xfs_btree_cur	*cur,
2234b8ed677SDarrick J. Wong 	union xfs_btree_ptr	*ptr)
2244b8ed677SDarrick J. Wong {
225576af732SDave Chinner 	struct xfs_agf		*agf = cur->bc_ag.agbp->b_addr;
2264b8ed677SDarrick J. Wong 
227fa9c3c19SDave Chinner 	ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agf->agf_seqno));
2284b8ed677SDarrick J. Wong 
2294b8ed677SDarrick J. Wong 	ptr->s = agf->agf_roots[cur->bc_btnum];
2304b8ed677SDarrick J. Wong }
2314b8ed677SDarrick J. Wong 
23208c987deSDarrick J. Wong /*
23308c987deSDarrick J. Wong  * Mask the appropriate parts of the ondisk key field for a key comparison.
23408c987deSDarrick J. Wong  * Fork and bmbt are significant parts of the rmap record key, but written
23508c987deSDarrick J. Wong  * status is merely a record attribute.
23608c987deSDarrick J. Wong  */
offset_keymask(uint64_t offset)23708c987deSDarrick J. Wong static inline uint64_t offset_keymask(uint64_t offset)
23808c987deSDarrick J. Wong {
23908c987deSDarrick J. Wong 	return offset & ~XFS_RMAP_OFF_UNWRITTEN;
24008c987deSDarrick J. Wong }
24108c987deSDarrick J. Wong 
242c8ce540dSDarrick J. Wong STATIC int64_t
xfs_rmapbt_key_diff(struct xfs_btree_cur * cur,const union xfs_btree_key * key)2434b8ed677SDarrick J. Wong xfs_rmapbt_key_diff(
2444b8ed677SDarrick J. Wong 	struct xfs_btree_cur		*cur,
245d29d5577SDarrick J. Wong 	const union xfs_btree_key	*key)
2464b8ed677SDarrick J. Wong {
2474b8ed677SDarrick J. Wong 	struct xfs_rmap_irec		*rec = &cur->bc_rec.r;
248d29d5577SDarrick J. Wong 	const struct xfs_rmap_key	*kp = &key->rmap;
2494b8ed677SDarrick J. Wong 	__u64				x, y;
250c8ce540dSDarrick J. Wong 	int64_t				d;
2514b8ed677SDarrick J. Wong 
252c8ce540dSDarrick J. Wong 	d = (int64_t)be32_to_cpu(kp->rm_startblock) - rec->rm_startblock;
2534b8ed677SDarrick J. Wong 	if (d)
2544b8ed677SDarrick J. Wong 		return d;
2554b8ed677SDarrick J. Wong 
2564b8ed677SDarrick J. Wong 	x = be64_to_cpu(kp->rm_owner);
2574b8ed677SDarrick J. Wong 	y = rec->rm_owner;
2584b8ed677SDarrick J. Wong 	if (x > y)
2594b8ed677SDarrick J. Wong 		return 1;
2604b8ed677SDarrick J. Wong 	else if (y > x)
2614b8ed677SDarrick J. Wong 		return -1;
2624b8ed677SDarrick J. Wong 
26308c987deSDarrick J. Wong 	x = offset_keymask(be64_to_cpu(kp->rm_offset));
26408c987deSDarrick J. Wong 	y = offset_keymask(xfs_rmap_irec_offset_pack(rec));
2654b8ed677SDarrick J. Wong 	if (x > y)
2664b8ed677SDarrick J. Wong 		return 1;
2674b8ed677SDarrick J. Wong 	else if (y > x)
2684b8ed677SDarrick J. Wong 		return -1;
2694b8ed677SDarrick J. Wong 	return 0;
2704b8ed677SDarrick J. Wong }
2714b8ed677SDarrick J. Wong 
272c8ce540dSDarrick J. Wong STATIC int64_t
xfs_rmapbt_diff_two_keys(struct xfs_btree_cur * cur,const union xfs_btree_key * k1,const union xfs_btree_key * k2,const union xfs_btree_key * mask)273cfed56aeSDarrick J. Wong xfs_rmapbt_diff_two_keys(
274cfed56aeSDarrick J. Wong 	struct xfs_btree_cur		*cur,
275d29d5577SDarrick J. Wong 	const union xfs_btree_key	*k1,
276*4a200a09SDarrick J. Wong 	const union xfs_btree_key	*k2,
277*4a200a09SDarrick J. Wong 	const union xfs_btree_key	*mask)
278cfed56aeSDarrick J. Wong {
279d29d5577SDarrick J. Wong 	const struct xfs_rmap_key	*kp1 = &k1->rmap;
280d29d5577SDarrick J. Wong 	const struct xfs_rmap_key	*kp2 = &k2->rmap;
281c8ce540dSDarrick J. Wong 	int64_t				d;
282cfed56aeSDarrick J. Wong 	__u64				x, y;
283cfed56aeSDarrick J. Wong 
284*4a200a09SDarrick J. Wong 	/* Doesn't make sense to mask off the physical space part */
285*4a200a09SDarrick J. Wong 	ASSERT(!mask || mask->rmap.rm_startblock);
286*4a200a09SDarrick J. Wong 
287c8ce540dSDarrick J. Wong 	d = (int64_t)be32_to_cpu(kp1->rm_startblock) -
288cfed56aeSDarrick J. Wong 		     be32_to_cpu(kp2->rm_startblock);
289cfed56aeSDarrick J. Wong 	if (d)
290cfed56aeSDarrick J. Wong 		return d;
291cfed56aeSDarrick J. Wong 
292*4a200a09SDarrick J. Wong 	if (!mask || mask->rmap.rm_owner) {
293cfed56aeSDarrick J. Wong 		x = be64_to_cpu(kp1->rm_owner);
294cfed56aeSDarrick J. Wong 		y = be64_to_cpu(kp2->rm_owner);
295cfed56aeSDarrick J. Wong 		if (x > y)
296cfed56aeSDarrick J. Wong 			return 1;
297cfed56aeSDarrick J. Wong 		else if (y > x)
298cfed56aeSDarrick J. Wong 			return -1;
299*4a200a09SDarrick J. Wong 	}
300*4a200a09SDarrick J. Wong 
301*4a200a09SDarrick J. Wong 	if (!mask || mask->rmap.rm_offset) {
302*4a200a09SDarrick J. Wong 		/* Doesn't make sense to allow offset but not owner */
303*4a200a09SDarrick J. Wong 		ASSERT(!mask || mask->rmap.rm_owner);
304cfed56aeSDarrick J. Wong 
30508c987deSDarrick J. Wong 		x = offset_keymask(be64_to_cpu(kp1->rm_offset));
30608c987deSDarrick J. Wong 		y = offset_keymask(be64_to_cpu(kp2->rm_offset));
307cfed56aeSDarrick J. Wong 		if (x > y)
308cfed56aeSDarrick J. Wong 			return 1;
309cfed56aeSDarrick J. Wong 		else if (y > x)
310cfed56aeSDarrick J. Wong 			return -1;
311*4a200a09SDarrick J. Wong 	}
312*4a200a09SDarrick J. Wong 
313cfed56aeSDarrick J. Wong 	return 0;
314cfed56aeSDarrick J. Wong }
315cfed56aeSDarrick J. Wong 
316a6a781a5SDarrick J. Wong static xfs_failaddr_t
xfs_rmapbt_verify(struct xfs_buf * bp)317035e00acSDarrick J. Wong xfs_rmapbt_verify(
318035e00acSDarrick J. Wong 	struct xfs_buf		*bp)
319035e00acSDarrick J. Wong {
320dbd329f1SChristoph Hellwig 	struct xfs_mount	*mp = bp->b_mount;
321035e00acSDarrick J. Wong 	struct xfs_btree_block	*block = XFS_BUF_TO_BLOCK(bp);
322035e00acSDarrick J. Wong 	struct xfs_perag	*pag = bp->b_pag;
323a6a781a5SDarrick J. Wong 	xfs_failaddr_t		fa;
324035e00acSDarrick J. Wong 	unsigned int		level;
325035e00acSDarrick J. Wong 
326035e00acSDarrick J. Wong 	/*
327035e00acSDarrick J. Wong 	 * magic number and level verification
328035e00acSDarrick J. Wong 	 *
329035e00acSDarrick J. Wong 	 * During growfs operations, we can't verify the exact level or owner as
330035e00acSDarrick J. Wong 	 * the perag is not fully initialised and hence not attached to the
331035e00acSDarrick J. Wong 	 * buffer.  In this case, check against the maximum tree depth.
332035e00acSDarrick J. Wong 	 *
333035e00acSDarrick J. Wong 	 * Similarly, during log recovery we will have a perag structure
334035e00acSDarrick J. Wong 	 * attached, but the agf information will not yet have been initialised
335035e00acSDarrick J. Wong 	 * from the on disk AGF. Again, we can only check against maximum limits
336035e00acSDarrick J. Wong 	 * in this case.
337035e00acSDarrick J. Wong 	 */
33839708c20SBrian Foster 	if (!xfs_verify_magic(bp, block->bb_magic))
339a6a781a5SDarrick J. Wong 		return __this_address;
340035e00acSDarrick J. Wong 
34138c26bfdSDave Chinner 	if (!xfs_has_rmapbt(mp))
342a6a781a5SDarrick J. Wong 		return __this_address;
343a6a781a5SDarrick J. Wong 	fa = xfs_btree_sblock_v5hdr_verify(bp);
344a6a781a5SDarrick J. Wong 	if (fa)
345a6a781a5SDarrick J. Wong 		return fa;
346035e00acSDarrick J. Wong 
347035e00acSDarrick J. Wong 	level = be16_to_cpu(block->bb_level);
3487ac2ff8bSDave Chinner 	if (pag && xfs_perag_initialised_agf(pag)) {
349035e00acSDarrick J. Wong 		if (level >= pag->pagf_levels[XFS_BTNUM_RMAPi])
350a6a781a5SDarrick J. Wong 			return __this_address;
351035e00acSDarrick J. Wong 	} else if (level >= mp->m_rmap_maxlevels)
352a6a781a5SDarrick J. Wong 		return __this_address;
353035e00acSDarrick J. Wong 
354035e00acSDarrick J. Wong 	return xfs_btree_sblock_verify(bp, mp->m_rmap_mxr[level != 0]);
355035e00acSDarrick J. Wong }
356035e00acSDarrick J. Wong 
357035e00acSDarrick J. Wong static void
xfs_rmapbt_read_verify(struct xfs_buf * bp)358035e00acSDarrick J. Wong xfs_rmapbt_read_verify(
359035e00acSDarrick J. Wong 	struct xfs_buf	*bp)
360035e00acSDarrick J. Wong {
361bc1a09b8SDarrick J. Wong 	xfs_failaddr_t	fa;
362bc1a09b8SDarrick J. Wong 
363035e00acSDarrick J. Wong 	if (!xfs_btree_sblock_verify_crc(bp))
364bc1a09b8SDarrick J. Wong 		xfs_verifier_error(bp, -EFSBADCRC, __this_address);
365bc1a09b8SDarrick J. Wong 	else {
366bc1a09b8SDarrick J. Wong 		fa = xfs_rmapbt_verify(bp);
367bc1a09b8SDarrick J. Wong 		if (fa)
368bc1a09b8SDarrick J. Wong 			xfs_verifier_error(bp, -EFSCORRUPTED, fa);
369bc1a09b8SDarrick J. Wong 	}
370035e00acSDarrick J. Wong 
37131ca03c9SDarrick J. Wong 	if (bp->b_error)
372035e00acSDarrick J. Wong 		trace_xfs_btree_corrupt(bp, _RET_IP_);
373035e00acSDarrick J. Wong }
374035e00acSDarrick J. Wong 
375035e00acSDarrick J. Wong static void
xfs_rmapbt_write_verify(struct xfs_buf * bp)376035e00acSDarrick J. Wong xfs_rmapbt_write_verify(
377035e00acSDarrick J. Wong 	struct xfs_buf	*bp)
378035e00acSDarrick J. Wong {
379bc1a09b8SDarrick J. Wong 	xfs_failaddr_t	fa;
380bc1a09b8SDarrick J. Wong 
381bc1a09b8SDarrick J. Wong 	fa = xfs_rmapbt_verify(bp);
382bc1a09b8SDarrick J. Wong 	if (fa) {
383035e00acSDarrick J. Wong 		trace_xfs_btree_corrupt(bp, _RET_IP_);
384bc1a09b8SDarrick J. Wong 		xfs_verifier_error(bp, -EFSCORRUPTED, fa);
385035e00acSDarrick J. Wong 		return;
386035e00acSDarrick J. Wong 	}
387035e00acSDarrick J. Wong 	xfs_btree_sblock_calc_crc(bp);
388035e00acSDarrick J. Wong 
389035e00acSDarrick J. Wong }
390035e00acSDarrick J. Wong 
391035e00acSDarrick J. Wong const struct xfs_buf_ops xfs_rmapbt_buf_ops = {
392035e00acSDarrick J. Wong 	.name			= "xfs_rmapbt",
39339708c20SBrian Foster 	.magic			= { 0, cpu_to_be32(XFS_RMAP_CRC_MAGIC) },
394035e00acSDarrick J. Wong 	.verify_read		= xfs_rmapbt_read_verify,
395035e00acSDarrick J. Wong 	.verify_write		= xfs_rmapbt_write_verify,
396b5572597SDarrick J. Wong 	.verify_struct		= xfs_rmapbt_verify,
397035e00acSDarrick J. Wong };
398035e00acSDarrick J. Wong 
3994b8ed677SDarrick J. Wong STATIC int
xfs_rmapbt_keys_inorder(struct xfs_btree_cur * cur,const union xfs_btree_key * k1,const union xfs_btree_key * k2)4004b8ed677SDarrick J. Wong xfs_rmapbt_keys_inorder(
4014b8ed677SDarrick J. Wong 	struct xfs_btree_cur		*cur,
4028e38dc88SDarrick J. Wong 	const union xfs_btree_key	*k1,
4038e38dc88SDarrick J. Wong 	const union xfs_btree_key	*k2)
4044b8ed677SDarrick J. Wong {
405c8ce540dSDarrick J. Wong 	uint32_t		x;
406c8ce540dSDarrick J. Wong 	uint32_t		y;
407c8ce540dSDarrick J. Wong 	uint64_t		a;
408c8ce540dSDarrick J. Wong 	uint64_t		b;
4094b8ed677SDarrick J. Wong 
4104b8ed677SDarrick J. Wong 	x = be32_to_cpu(k1->rmap.rm_startblock);
4114b8ed677SDarrick J. Wong 	y = be32_to_cpu(k2->rmap.rm_startblock);
4124b8ed677SDarrick J. Wong 	if (x < y)
4134b8ed677SDarrick J. Wong 		return 1;
4144b8ed677SDarrick J. Wong 	else if (x > y)
4154b8ed677SDarrick J. Wong 		return 0;
4164b8ed677SDarrick J. Wong 	a = be64_to_cpu(k1->rmap.rm_owner);
4174b8ed677SDarrick J. Wong 	b = be64_to_cpu(k2->rmap.rm_owner);
4184b8ed677SDarrick J. Wong 	if (a < b)
4194b8ed677SDarrick J. Wong 		return 1;
4204b8ed677SDarrick J. Wong 	else if (a > b)
4214b8ed677SDarrick J. Wong 		return 0;
42208c987deSDarrick J. Wong 	a = offset_keymask(be64_to_cpu(k1->rmap.rm_offset));
42308c987deSDarrick J. Wong 	b = offset_keymask(be64_to_cpu(k2->rmap.rm_offset));
4244b8ed677SDarrick J. Wong 	if (a <= b)
4254b8ed677SDarrick J. Wong 		return 1;
4264b8ed677SDarrick J. Wong 	return 0;
4274b8ed677SDarrick J. Wong }
4284b8ed677SDarrick J. Wong 
4294b8ed677SDarrick J. Wong STATIC int
xfs_rmapbt_recs_inorder(struct xfs_btree_cur * cur,const union xfs_btree_rec * r1,const union xfs_btree_rec * r2)4304b8ed677SDarrick J. Wong xfs_rmapbt_recs_inorder(
4314b8ed677SDarrick J. Wong 	struct xfs_btree_cur		*cur,
4328e38dc88SDarrick J. Wong 	const union xfs_btree_rec	*r1,
4338e38dc88SDarrick J. Wong 	const union xfs_btree_rec	*r2)
4344b8ed677SDarrick J. Wong {
435c8ce540dSDarrick J. Wong 	uint32_t		x;
436c8ce540dSDarrick J. Wong 	uint32_t		y;
437c8ce540dSDarrick J. Wong 	uint64_t		a;
438c8ce540dSDarrick J. Wong 	uint64_t		b;
4394b8ed677SDarrick J. Wong 
4404b8ed677SDarrick J. Wong 	x = be32_to_cpu(r1->rmap.rm_startblock);
4414b8ed677SDarrick J. Wong 	y = be32_to_cpu(r2->rmap.rm_startblock);
4424b8ed677SDarrick J. Wong 	if (x < y)
4434b8ed677SDarrick J. Wong 		return 1;
4444b8ed677SDarrick J. Wong 	else if (x > y)
4454b8ed677SDarrick J. Wong 		return 0;
4464b8ed677SDarrick J. Wong 	a = be64_to_cpu(r1->rmap.rm_owner);
4474b8ed677SDarrick J. Wong 	b = be64_to_cpu(r2->rmap.rm_owner);
4484b8ed677SDarrick J. Wong 	if (a < b)
4494b8ed677SDarrick J. Wong 		return 1;
4504b8ed677SDarrick J. Wong 	else if (a > b)
4514b8ed677SDarrick J. Wong 		return 0;
45208c987deSDarrick J. Wong 	a = offset_keymask(be64_to_cpu(r1->rmap.rm_offset));
45308c987deSDarrick J. Wong 	b = offset_keymask(be64_to_cpu(r2->rmap.rm_offset));
4544b8ed677SDarrick J. Wong 	if (a <= b)
4554b8ed677SDarrick J. Wong 		return 1;
4564b8ed677SDarrick J. Wong 	return 0;
4574b8ed677SDarrick J. Wong }
4584b8ed677SDarrick J. Wong 
4596abc7aefSDarrick J. Wong STATIC enum xbtree_key_contig
xfs_rmapbt_keys_contiguous(struct xfs_btree_cur * cur,const union xfs_btree_key * key1,const union xfs_btree_key * key2,const union xfs_btree_key * mask)4606abc7aefSDarrick J. Wong xfs_rmapbt_keys_contiguous(
4616abc7aefSDarrick J. Wong 	struct xfs_btree_cur		*cur,
4626abc7aefSDarrick J. Wong 	const union xfs_btree_key	*key1,
463*4a200a09SDarrick J. Wong 	const union xfs_btree_key	*key2,
464*4a200a09SDarrick J. Wong 	const union xfs_btree_key	*mask)
4656abc7aefSDarrick J. Wong {
466*4a200a09SDarrick J. Wong 	ASSERT(!mask || mask->rmap.rm_startblock);
467*4a200a09SDarrick J. Wong 
4686abc7aefSDarrick J. Wong 	/*
4696abc7aefSDarrick J. Wong 	 * We only support checking contiguity of the physical space component.
4706abc7aefSDarrick J. Wong 	 * If any callers ever need more specificity than that, they'll have to
4716abc7aefSDarrick J. Wong 	 * implement it here.
4726abc7aefSDarrick J. Wong 	 */
473*4a200a09SDarrick J. Wong 	ASSERT(!mask || (!mask->rmap.rm_owner && !mask->rmap.rm_offset));
474*4a200a09SDarrick J. Wong 
4756abc7aefSDarrick J. Wong 	return xbtree_key_contig(be32_to_cpu(key1->rmap.rm_startblock),
4766abc7aefSDarrick J. Wong 				 be32_to_cpu(key2->rmap.rm_startblock));
4776abc7aefSDarrick J. Wong }
4786abc7aefSDarrick J. Wong 
479035e00acSDarrick J. Wong static const struct xfs_btree_ops xfs_rmapbt_ops = {
480035e00acSDarrick J. Wong 	.rec_len		= sizeof(struct xfs_rmap_rec),
481035e00acSDarrick J. Wong 	.key_len		= 2 * sizeof(struct xfs_rmap_key),
482035e00acSDarrick J. Wong 
483035e00acSDarrick J. Wong 	.dup_cursor		= xfs_rmapbt_dup_cursor,
4844b8ed677SDarrick J. Wong 	.set_root		= xfs_rmapbt_set_root,
4854b8ed677SDarrick J. Wong 	.alloc_block		= xfs_rmapbt_alloc_block,
4864b8ed677SDarrick J. Wong 	.free_block		= xfs_rmapbt_free_block,
4874b8ed677SDarrick J. Wong 	.get_minrecs		= xfs_rmapbt_get_minrecs,
4884b8ed677SDarrick J. Wong 	.get_maxrecs		= xfs_rmapbt_get_maxrecs,
4894b8ed677SDarrick J. Wong 	.init_key_from_rec	= xfs_rmapbt_init_key_from_rec,
490cfed56aeSDarrick J. Wong 	.init_high_key_from_rec	= xfs_rmapbt_init_high_key_from_rec,
4914b8ed677SDarrick J. Wong 	.init_rec_from_cur	= xfs_rmapbt_init_rec_from_cur,
4924b8ed677SDarrick J. Wong 	.init_ptr_from_cur	= xfs_rmapbt_init_ptr_from_cur,
4934b8ed677SDarrick J. Wong 	.key_diff		= xfs_rmapbt_key_diff,
494035e00acSDarrick J. Wong 	.buf_ops		= &xfs_rmapbt_buf_ops,
495cfed56aeSDarrick J. Wong 	.diff_two_keys		= xfs_rmapbt_diff_two_keys,
4964b8ed677SDarrick J. Wong 	.keys_inorder		= xfs_rmapbt_keys_inorder,
4974b8ed677SDarrick J. Wong 	.recs_inorder		= xfs_rmapbt_recs_inorder,
4986abc7aefSDarrick J. Wong 	.keys_contiguous	= xfs_rmapbt_keys_contiguous,
499035e00acSDarrick J. Wong };
500035e00acSDarrick J. Wong 
50159d67712SDarrick J. Wong static struct xfs_btree_cur *
xfs_rmapbt_init_common(struct xfs_mount * mp,struct xfs_trans * tp,struct xfs_perag * pag)50259d67712SDarrick J. Wong xfs_rmapbt_init_common(
50359d67712SDarrick J. Wong 	struct xfs_mount	*mp,
50459d67712SDarrick J. Wong 	struct xfs_trans	*tp,
505be9fb17dSDave Chinner 	struct xfs_perag	*pag)
50659d67712SDarrick J. Wong {
50759d67712SDarrick J. Wong 	struct xfs_btree_cur	*cur;
50859d67712SDarrick J. Wong 
50959d67712SDarrick J. Wong 	/* Overlapping btree; 2 keys per pointer. */
510c940a0c5SDarrick J. Wong 	cur = xfs_btree_alloc_cursor(mp, tp, XFS_BTNUM_RMAP,
5119fa47bdcSDarrick J. Wong 			mp->m_rmap_maxlevels, xfs_rmapbt_cur_cache);
51259d67712SDarrick J. Wong 	cur->bc_flags = XFS_BTREE_CRC_BLOCKS | XFS_BTREE_OVERLAPPING;
51359d67712SDarrick J. Wong 	cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_rmap_2);
51459d67712SDarrick J. Wong 	cur->bc_ops = &xfs_rmapbt_ops;
515fa9c3c19SDave Chinner 
5169b2e5a23SDarrick J. Wong 	cur->bc_ag.pag = xfs_perag_hold(pag);
51759d67712SDarrick J. Wong 	return cur;
51859d67712SDarrick J. Wong }
51959d67712SDarrick J. Wong 
52059d67712SDarrick J. Wong /* Create a new reverse mapping btree cursor. */
521035e00acSDarrick J. Wong struct xfs_btree_cur *
xfs_rmapbt_init_cursor(struct xfs_mount * mp,struct xfs_trans * tp,struct xfs_buf * agbp,struct xfs_perag * pag)522035e00acSDarrick J. Wong xfs_rmapbt_init_cursor(
523035e00acSDarrick J. Wong 	struct xfs_mount	*mp,
524035e00acSDarrick J. Wong 	struct xfs_trans	*tp,
525035e00acSDarrick J. Wong 	struct xfs_buf		*agbp,
526be9fb17dSDave Chinner 	struct xfs_perag	*pag)
527035e00acSDarrick J. Wong {
5289798f615SChristoph Hellwig 	struct xfs_agf		*agf = agbp->b_addr;
529035e00acSDarrick J. Wong 	struct xfs_btree_cur	*cur;
530035e00acSDarrick J. Wong 
531fa9c3c19SDave Chinner 	cur = xfs_rmapbt_init_common(mp, tp, pag);
532035e00acSDarrick J. Wong 	cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]);
533576af732SDave Chinner 	cur->bc_ag.agbp = agbp;
534035e00acSDarrick J. Wong 	return cur;
535035e00acSDarrick J. Wong }
536035e00acSDarrick J. Wong 
53759d67712SDarrick J. Wong /* Create a new reverse mapping btree cursor with a fake root for staging. */
53859d67712SDarrick J. Wong struct xfs_btree_cur *
xfs_rmapbt_stage_cursor(struct xfs_mount * mp,struct xbtree_afakeroot * afake,struct xfs_perag * pag)53959d67712SDarrick J. Wong xfs_rmapbt_stage_cursor(
54059d67712SDarrick J. Wong 	struct xfs_mount	*mp,
54159d67712SDarrick J. Wong 	struct xbtree_afakeroot	*afake,
542fa9c3c19SDave Chinner 	struct xfs_perag	*pag)
54359d67712SDarrick J. Wong {
54459d67712SDarrick J. Wong 	struct xfs_btree_cur	*cur;
54559d67712SDarrick J. Wong 
546fa9c3c19SDave Chinner 	cur = xfs_rmapbt_init_common(mp, NULL, pag);
54759d67712SDarrick J. Wong 	xfs_btree_stage_afakeroot(cur, afake);
54859d67712SDarrick J. Wong 	return cur;
54959d67712SDarrick J. Wong }
55059d67712SDarrick J. Wong 
55159d67712SDarrick J. Wong /*
55259d67712SDarrick J. Wong  * Install a new reverse mapping btree root.  Caller is responsible for
55359d67712SDarrick J. Wong  * invalidating and freeing the old btree blocks.
55459d67712SDarrick J. Wong  */
55559d67712SDarrick J. Wong void
xfs_rmapbt_commit_staged_btree(struct xfs_btree_cur * cur,struct xfs_trans * tp,struct xfs_buf * agbp)55659d67712SDarrick J. Wong xfs_rmapbt_commit_staged_btree(
55759d67712SDarrick J. Wong 	struct xfs_btree_cur	*cur,
55859d67712SDarrick J. Wong 	struct xfs_trans	*tp,
55959d67712SDarrick J. Wong 	struct xfs_buf		*agbp)
56059d67712SDarrick J. Wong {
56159d67712SDarrick J. Wong 	struct xfs_agf		*agf = agbp->b_addr;
56259d67712SDarrick J. Wong 	struct xbtree_afakeroot	*afake = cur->bc_ag.afake;
56359d67712SDarrick J. Wong 
56459d67712SDarrick J. Wong 	ASSERT(cur->bc_flags & XFS_BTREE_STAGING);
56559d67712SDarrick J. Wong 
56659d67712SDarrick J. Wong 	agf->agf_roots[cur->bc_btnum] = cpu_to_be32(afake->af_root);
56759d67712SDarrick J. Wong 	agf->agf_levels[cur->bc_btnum] = cpu_to_be32(afake->af_levels);
56859d67712SDarrick J. Wong 	agf->agf_rmap_blocks = cpu_to_be32(afake->af_blocks);
56959d67712SDarrick J. Wong 	xfs_alloc_log_agf(tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS |
57059d67712SDarrick J. Wong 				    XFS_AGF_RMAP_BLOCKS);
57159d67712SDarrick J. Wong 	xfs_btree_commit_afakeroot(cur, tp, agbp, &xfs_rmapbt_ops);
57259d67712SDarrick J. Wong }
57359d67712SDarrick J. Wong 
5740ed5f735SDarrick J. Wong /* Calculate number of records in a reverse mapping btree block. */
5750ed5f735SDarrick J. Wong static inline unsigned int
xfs_rmapbt_block_maxrecs(unsigned int blocklen,bool leaf)5760ed5f735SDarrick J. Wong xfs_rmapbt_block_maxrecs(
5770ed5f735SDarrick J. Wong 	unsigned int		blocklen,
5780ed5f735SDarrick J. Wong 	bool			leaf)
5790ed5f735SDarrick J. Wong {
5800ed5f735SDarrick J. Wong 	if (leaf)
5810ed5f735SDarrick J. Wong 		return blocklen / sizeof(struct xfs_rmap_rec);
5820ed5f735SDarrick J. Wong 	return blocklen /
5830ed5f735SDarrick J. Wong 		(2 * sizeof(struct xfs_rmap_key) + sizeof(xfs_rmap_ptr_t));
5840ed5f735SDarrick J. Wong }
5850ed5f735SDarrick J. Wong 
586035e00acSDarrick J. Wong /*
587035e00acSDarrick J. Wong  * Calculate number of records in an rmap btree block.
588035e00acSDarrick J. Wong  */
589035e00acSDarrick J. Wong int
xfs_rmapbt_maxrecs(int blocklen,int leaf)590035e00acSDarrick J. Wong xfs_rmapbt_maxrecs(
591035e00acSDarrick J. Wong 	int			blocklen,
592035e00acSDarrick J. Wong 	int			leaf)
593035e00acSDarrick J. Wong {
594035e00acSDarrick J. Wong 	blocklen -= XFS_RMAP_BLOCK_LEN;
5950ed5f735SDarrick J. Wong 	return xfs_rmapbt_block_maxrecs(blocklen, leaf);
5960ed5f735SDarrick J. Wong }
597035e00acSDarrick J. Wong 
5980ed5f735SDarrick J. Wong /* Compute the max possible height for reverse mapping btrees. */
5990ed5f735SDarrick J. Wong unsigned int
xfs_rmapbt_maxlevels_ondisk(void)6000ed5f735SDarrick J. Wong xfs_rmapbt_maxlevels_ondisk(void)
6010ed5f735SDarrick J. Wong {
6020ed5f735SDarrick J. Wong 	unsigned int		minrecs[2];
6030ed5f735SDarrick J. Wong 	unsigned int		blocklen;
6040ed5f735SDarrick J. Wong 
6050ed5f735SDarrick J. Wong 	blocklen = XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_SBLOCK_CRC_LEN;
6060ed5f735SDarrick J. Wong 
6070ed5f735SDarrick J. Wong 	minrecs[0] = xfs_rmapbt_block_maxrecs(blocklen, true) / 2;
6080ed5f735SDarrick J. Wong 	minrecs[1] = xfs_rmapbt_block_maxrecs(blocklen, false) / 2;
6090ed5f735SDarrick J. Wong 
6100ed5f735SDarrick J. Wong 	/*
6110ed5f735SDarrick J. Wong 	 * Compute the asymptotic maxlevels for an rmapbt on any reflink fs.
6120ed5f735SDarrick J. Wong 	 *
6130ed5f735SDarrick J. Wong 	 * On a reflink filesystem, each AG block can have up to 2^32 (per the
6140ed5f735SDarrick J. Wong 	 * refcount record format) owners, which means that theoretically we
6150ed5f735SDarrick J. Wong 	 * could face up to 2^64 rmap records.  However, we're likely to run
6160ed5f735SDarrick J. Wong 	 * out of blocks in the AG long before that happens, which means that
6170ed5f735SDarrick J. Wong 	 * we must compute the max height based on what the btree will look
6180ed5f735SDarrick J. Wong 	 * like if it consumes almost all the blocks in the AG due to maximal
6190ed5f735SDarrick J. Wong 	 * sharing factor.
6200ed5f735SDarrick J. Wong 	 */
6210ed5f735SDarrick J. Wong 	return xfs_btree_space_to_height(minrecs, XFS_MAX_CRC_AG_BLOCKS);
622035e00acSDarrick J. Wong }
623035e00acSDarrick J. Wong 
624035e00acSDarrick J. Wong /* Compute the maximum height of an rmap btree. */
625035e00acSDarrick J. Wong void
xfs_rmapbt_compute_maxlevels(struct xfs_mount * mp)626035e00acSDarrick J. Wong xfs_rmapbt_compute_maxlevels(
627035e00acSDarrick J. Wong 	struct xfs_mount		*mp)
628035e00acSDarrick J. Wong {
6299ec69120SDarrick J. Wong 	if (!xfs_has_rmapbt(mp)) {
6309ec69120SDarrick J. Wong 		mp->m_rmap_maxlevels = 0;
6319ec69120SDarrick J. Wong 		return;
6329ec69120SDarrick J. Wong 	}
6339ec69120SDarrick J. Wong 
6349ec69120SDarrick J. Wong 	if (xfs_has_reflink(mp)) {
63546eeb521SDarrick J. Wong 		/*
6369ec69120SDarrick J. Wong 		 * Compute the asymptotic maxlevels for an rmap btree on a
6379ec69120SDarrick J. Wong 		 * filesystem that supports reflink.
63846eeb521SDarrick J. Wong 		 *
6399ec69120SDarrick J. Wong 		 * On a reflink filesystem, each AG block can have up to 2^32
6409ec69120SDarrick J. Wong 		 * (per the refcount record format) owners, which means that
6419ec69120SDarrick J. Wong 		 * theoretically we could face up to 2^64 rmap records.
6429ec69120SDarrick J. Wong 		 * However, we're likely to run out of blocks in the AG long
6439ec69120SDarrick J. Wong 		 * before that happens, which means that we must compute the
6449ec69120SDarrick J. Wong 		 * max height based on what the btree will look like if it
6459ec69120SDarrick J. Wong 		 * consumes almost all the blocks in the AG due to maximal
6469ec69120SDarrick J. Wong 		 * sharing factor.
64746eeb521SDarrick J. Wong 		 */
6489ec69120SDarrick J. Wong 		mp->m_rmap_maxlevels = xfs_btree_space_to_height(mp->m_rmap_mnr,
6499ec69120SDarrick J. Wong 				mp->m_sb.sb_agblocks);
6509ec69120SDarrick J. Wong 	} else {
6519ec69120SDarrick J. Wong 		/*
6529ec69120SDarrick J. Wong 		 * If there's no block sharing, compute the maximum rmapbt
6539ec69120SDarrick J. Wong 		 * height assuming one rmap record per AG block.
6549ec69120SDarrick J. Wong 		 */
655a1f69417SEric Sandeen 		mp->m_rmap_maxlevels = xfs_btree_compute_maxlevels(
656035e00acSDarrick J. Wong 				mp->m_rmap_mnr, mp->m_sb.sb_agblocks);
657035e00acSDarrick J. Wong 	}
6580ed5f735SDarrick J. Wong 	ASSERT(mp->m_rmap_maxlevels <= xfs_rmapbt_maxlevels_ondisk());
6599ec69120SDarrick J. Wong }
66084d69619SDarrick J. Wong 
66184d69619SDarrick J. Wong /* Calculate the refcount btree size for some records. */
66284d69619SDarrick J. Wong xfs_extlen_t
xfs_rmapbt_calc_size(struct xfs_mount * mp,unsigned long long len)66384d69619SDarrick J. Wong xfs_rmapbt_calc_size(
66484d69619SDarrick J. Wong 	struct xfs_mount	*mp,
66584d69619SDarrick J. Wong 	unsigned long long	len)
66684d69619SDarrick J. Wong {
667a1f69417SEric Sandeen 	return xfs_btree_calc_size(mp->m_rmap_mnr, len);
66884d69619SDarrick J. Wong }
66984d69619SDarrick J. Wong 
67084d69619SDarrick J. Wong /*
67184d69619SDarrick J. Wong  * Calculate the maximum refcount btree size.
67284d69619SDarrick J. Wong  */
67384d69619SDarrick J. Wong xfs_extlen_t
xfs_rmapbt_max_size(struct xfs_mount * mp,xfs_agblock_t agblocks)67484d69619SDarrick J. Wong xfs_rmapbt_max_size(
67520e73b00SDarrick J. Wong 	struct xfs_mount	*mp,
67620e73b00SDarrick J. Wong 	xfs_agblock_t		agblocks)
67784d69619SDarrick J. Wong {
67884d69619SDarrick J. Wong 	/* Bail out if we're uninitialized, which can happen in mkfs. */
67984d69619SDarrick J. Wong 	if (mp->m_rmap_mxr[0] == 0)
68084d69619SDarrick J. Wong 		return 0;
68184d69619SDarrick J. Wong 
68220e73b00SDarrick J. Wong 	return xfs_rmapbt_calc_size(mp, agblocks);
68384d69619SDarrick J. Wong }
68484d69619SDarrick J. Wong 
68584d69619SDarrick J. Wong /*
68684d69619SDarrick J. Wong  * Figure out how many blocks to reserve and how many are used by this btree.
68784d69619SDarrick J. Wong  */
68884d69619SDarrick J. Wong int
xfs_rmapbt_calc_reserves(struct xfs_mount * mp,struct xfs_trans * tp,struct xfs_perag * pag,xfs_extlen_t * ask,xfs_extlen_t * used)68984d69619SDarrick J. Wong xfs_rmapbt_calc_reserves(
69084d69619SDarrick J. Wong 	struct xfs_mount	*mp,
691ebcbef3aSDarrick J. Wong 	struct xfs_trans	*tp,
69230933120SDave Chinner 	struct xfs_perag	*pag,
69384d69619SDarrick J. Wong 	xfs_extlen_t		*ask,
69484d69619SDarrick J. Wong 	xfs_extlen_t		*used)
69584d69619SDarrick J. Wong {
69684d69619SDarrick J. Wong 	struct xfs_buf		*agbp;
69784d69619SDarrick J. Wong 	struct xfs_agf		*agf;
69820e73b00SDarrick J. Wong 	xfs_agblock_t		agblocks;
69984d69619SDarrick J. Wong 	xfs_extlen_t		tree_len;
70084d69619SDarrick J. Wong 	int			error;
70184d69619SDarrick J. Wong 
70238c26bfdSDave Chinner 	if (!xfs_has_rmapbt(mp))
70384d69619SDarrick J. Wong 		return 0;
70484d69619SDarrick J. Wong 
70508d3e84fSDave Chinner 	error = xfs_alloc_read_agf(pag, tp, 0, &agbp);
70684d69619SDarrick J. Wong 	if (error)
70784d69619SDarrick J. Wong 		return error;
70884d69619SDarrick J. Wong 
7099798f615SChristoph Hellwig 	agf = agbp->b_addr;
71020e73b00SDarrick J. Wong 	agblocks = be32_to_cpu(agf->agf_length);
71184d69619SDarrick J. Wong 	tree_len = be32_to_cpu(agf->agf_rmap_blocks);
712ebcbef3aSDarrick J. Wong 	xfs_trans_brelse(tp, agbp);
71384d69619SDarrick J. Wong 
7145cd213b0SDarrick J. Wong 	/*
7155cd213b0SDarrick J. Wong 	 * The log is permanently allocated, so the space it occupies will
7165cd213b0SDarrick J. Wong 	 * never be available for the kinds of things that would require btree
7175cd213b0SDarrick J. Wong 	 * expansion.  We therefore can pretend the space isn't there.
7185cd213b0SDarrick J. Wong 	 */
71936029deeSDave Chinner 	if (xfs_ag_contains_log(mp, pag->pag_agno))
7205cd213b0SDarrick J. Wong 		agblocks -= mp->m_sb.sb_logblocks;
7215cd213b0SDarrick J. Wong 
72220e73b00SDarrick J. Wong 	/* Reserve 1% of the AG or enough for 1 block per record. */
72320e73b00SDarrick J. Wong 	*ask += max(agblocks / 100, xfs_rmapbt_max_size(mp, agblocks));
72484d69619SDarrick J. Wong 	*used += tree_len;
72584d69619SDarrick J. Wong 
72684d69619SDarrick J. Wong 	return error;
72784d69619SDarrick J. Wong }
7289fa47bdcSDarrick J. Wong 
7299fa47bdcSDarrick J. Wong int __init
xfs_rmapbt_init_cur_cache(void)7309fa47bdcSDarrick J. Wong xfs_rmapbt_init_cur_cache(void)
7319fa47bdcSDarrick J. Wong {
7329fa47bdcSDarrick J. Wong 	xfs_rmapbt_cur_cache = kmem_cache_create("xfs_rmapbt_cur",
7339fa47bdcSDarrick J. Wong 			xfs_btree_cur_sizeof(xfs_rmapbt_maxlevels_ondisk()),
7349fa47bdcSDarrick J. Wong 			0, 0, NULL);
7359fa47bdcSDarrick J. Wong 
7369fa47bdcSDarrick J. Wong 	if (!xfs_rmapbt_cur_cache)
7379fa47bdcSDarrick J. Wong 		return -ENOMEM;
7389fa47bdcSDarrick J. Wong 	return 0;
7399fa47bdcSDarrick J. Wong }
7409fa47bdcSDarrick J. Wong 
7419fa47bdcSDarrick J. Wong void
xfs_rmapbt_destroy_cur_cache(void)7429fa47bdcSDarrick J. Wong xfs_rmapbt_destroy_cur_cache(void)
7439fa47bdcSDarrick J. Wong {
7449fa47bdcSDarrick J. Wong 	kmem_cache_destroy(xfs_rmapbt_cur_cache);
7459fa47bdcSDarrick J. Wong 	xfs_rmapbt_cur_cache = NULL;
7469fa47bdcSDarrick J. Wong }
747