xref: /openbmc/linux/fs/xfs/libxfs/xfs_rmap_btree.c (revision 035e00ac)
1035e00acSDarrick J. Wong /*
2035e00acSDarrick J. Wong  * Copyright (c) 2014 Red Hat, Inc.
3035e00acSDarrick J. Wong  * All Rights Reserved.
4035e00acSDarrick J. Wong  *
5035e00acSDarrick J. Wong  * This program is free software; you can redistribute it and/or
6035e00acSDarrick J. Wong  * modify it under the terms of the GNU General Public License as
7035e00acSDarrick J. Wong  * published by the Free Software Foundation.
8035e00acSDarrick J. Wong  *
9035e00acSDarrick J. Wong  * This program is distributed in the hope that it would be useful,
10035e00acSDarrick J. Wong  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11035e00acSDarrick J. Wong  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12035e00acSDarrick J. Wong  * GNU General Public License for more details.
13035e00acSDarrick J. Wong  *
14035e00acSDarrick J. Wong  * You should have received a copy of the GNU General Public License
15035e00acSDarrick J. Wong  * along with this program; if not, write the Free Software Foundation,
16035e00acSDarrick J. Wong  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17035e00acSDarrick J. Wong  */
18035e00acSDarrick J. Wong #include "xfs.h"
19035e00acSDarrick J. Wong #include "xfs_fs.h"
20035e00acSDarrick J. Wong #include "xfs_shared.h"
21035e00acSDarrick J. Wong #include "xfs_format.h"
22035e00acSDarrick J. Wong #include "xfs_log_format.h"
23035e00acSDarrick J. Wong #include "xfs_trans_resv.h"
24035e00acSDarrick J. Wong #include "xfs_bit.h"
25035e00acSDarrick J. Wong #include "xfs_sb.h"
26035e00acSDarrick J. Wong #include "xfs_mount.h"
27035e00acSDarrick J. Wong #include "xfs_defer.h"
28035e00acSDarrick J. Wong #include "xfs_inode.h"
29035e00acSDarrick J. Wong #include "xfs_trans.h"
30035e00acSDarrick J. Wong #include "xfs_alloc.h"
31035e00acSDarrick J. Wong #include "xfs_btree.h"
32035e00acSDarrick J. Wong #include "xfs_rmap_btree.h"
33035e00acSDarrick J. Wong #include "xfs_trace.h"
34035e00acSDarrick J. Wong #include "xfs_cksum.h"
35035e00acSDarrick J. Wong #include "xfs_error.h"
36035e00acSDarrick J. Wong #include "xfs_extent_busy.h"
37035e00acSDarrick J. Wong 
38035e00acSDarrick J. Wong static struct xfs_btree_cur *
39035e00acSDarrick J. Wong xfs_rmapbt_dup_cursor(
40035e00acSDarrick J. Wong 	struct xfs_btree_cur	*cur)
41035e00acSDarrick J. Wong {
42035e00acSDarrick J. Wong 	return xfs_rmapbt_init_cursor(cur->bc_mp, cur->bc_tp,
43035e00acSDarrick J. Wong 			cur->bc_private.a.agbp, cur->bc_private.a.agno);
44035e00acSDarrick J. Wong }
45035e00acSDarrick J. Wong 
46035e00acSDarrick J. Wong static bool
47035e00acSDarrick J. Wong xfs_rmapbt_verify(
48035e00acSDarrick J. Wong 	struct xfs_buf		*bp)
49035e00acSDarrick J. Wong {
50035e00acSDarrick J. Wong 	struct xfs_mount	*mp = bp->b_target->bt_mount;
51035e00acSDarrick J. Wong 	struct xfs_btree_block	*block = XFS_BUF_TO_BLOCK(bp);
52035e00acSDarrick J. Wong 	struct xfs_perag	*pag = bp->b_pag;
53035e00acSDarrick J. Wong 	unsigned int		level;
54035e00acSDarrick J. Wong 
55035e00acSDarrick J. Wong 	/*
56035e00acSDarrick J. Wong 	 * magic number and level verification
57035e00acSDarrick J. Wong 	 *
58035e00acSDarrick J. Wong 	 * During growfs operations, we can't verify the exact level or owner as
59035e00acSDarrick J. Wong 	 * the perag is not fully initialised and hence not attached to the
60035e00acSDarrick J. Wong 	 * buffer.  In this case, check against the maximum tree depth.
61035e00acSDarrick J. Wong 	 *
62035e00acSDarrick J. Wong 	 * Similarly, during log recovery we will have a perag structure
63035e00acSDarrick J. Wong 	 * attached, but the agf information will not yet have been initialised
64035e00acSDarrick J. Wong 	 * from the on disk AGF. Again, we can only check against maximum limits
65035e00acSDarrick J. Wong 	 * in this case.
66035e00acSDarrick J. Wong 	 */
67035e00acSDarrick J. Wong 	if (block->bb_magic != cpu_to_be32(XFS_RMAP_CRC_MAGIC))
68035e00acSDarrick J. Wong 		return false;
69035e00acSDarrick J. Wong 
70035e00acSDarrick J. Wong 	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
71035e00acSDarrick J. Wong 		return false;
72035e00acSDarrick J. Wong 	if (!xfs_btree_sblock_v5hdr_verify(bp))
73035e00acSDarrick J. Wong 		return false;
74035e00acSDarrick J. Wong 
75035e00acSDarrick J. Wong 	level = be16_to_cpu(block->bb_level);
76035e00acSDarrick J. Wong 	if (pag && pag->pagf_init) {
77035e00acSDarrick J. Wong 		if (level >= pag->pagf_levels[XFS_BTNUM_RMAPi])
78035e00acSDarrick J. Wong 			return false;
79035e00acSDarrick J. Wong 	} else if (level >= mp->m_rmap_maxlevels)
80035e00acSDarrick J. Wong 		return false;
81035e00acSDarrick J. Wong 
82035e00acSDarrick J. Wong 	return xfs_btree_sblock_verify(bp, mp->m_rmap_mxr[level != 0]);
83035e00acSDarrick J. Wong }
84035e00acSDarrick J. Wong 
85035e00acSDarrick J. Wong static void
86035e00acSDarrick J. Wong xfs_rmapbt_read_verify(
87035e00acSDarrick J. Wong 	struct xfs_buf	*bp)
88035e00acSDarrick J. Wong {
89035e00acSDarrick J. Wong 	if (!xfs_btree_sblock_verify_crc(bp))
90035e00acSDarrick J. Wong 		xfs_buf_ioerror(bp, -EFSBADCRC);
91035e00acSDarrick J. Wong 	else if (!xfs_rmapbt_verify(bp))
92035e00acSDarrick J. Wong 		xfs_buf_ioerror(bp, -EFSCORRUPTED);
93035e00acSDarrick J. Wong 
94035e00acSDarrick J. Wong 	if (bp->b_error) {
95035e00acSDarrick J. Wong 		trace_xfs_btree_corrupt(bp, _RET_IP_);
96035e00acSDarrick J. Wong 		xfs_verifier_error(bp);
97035e00acSDarrick J. Wong 	}
98035e00acSDarrick J. Wong }
99035e00acSDarrick J. Wong 
100035e00acSDarrick J. Wong static void
101035e00acSDarrick J. Wong xfs_rmapbt_write_verify(
102035e00acSDarrick J. Wong 	struct xfs_buf	*bp)
103035e00acSDarrick J. Wong {
104035e00acSDarrick J. Wong 	if (!xfs_rmapbt_verify(bp)) {
105035e00acSDarrick J. Wong 		trace_xfs_btree_corrupt(bp, _RET_IP_);
106035e00acSDarrick J. Wong 		xfs_buf_ioerror(bp, -EFSCORRUPTED);
107035e00acSDarrick J. Wong 		xfs_verifier_error(bp);
108035e00acSDarrick J. Wong 		return;
109035e00acSDarrick J. Wong 	}
110035e00acSDarrick J. Wong 	xfs_btree_sblock_calc_crc(bp);
111035e00acSDarrick J. Wong 
112035e00acSDarrick J. Wong }
113035e00acSDarrick J. Wong 
114035e00acSDarrick J. Wong const struct xfs_buf_ops xfs_rmapbt_buf_ops = {
115035e00acSDarrick J. Wong 	.name			= "xfs_rmapbt",
116035e00acSDarrick J. Wong 	.verify_read		= xfs_rmapbt_read_verify,
117035e00acSDarrick J. Wong 	.verify_write		= xfs_rmapbt_write_verify,
118035e00acSDarrick J. Wong };
119035e00acSDarrick J. Wong 
120035e00acSDarrick J. Wong static const struct xfs_btree_ops xfs_rmapbt_ops = {
121035e00acSDarrick J. Wong 	.rec_len		= sizeof(struct xfs_rmap_rec),
122035e00acSDarrick J. Wong 	.key_len		= 2 * sizeof(struct xfs_rmap_key),
123035e00acSDarrick J. Wong 
124035e00acSDarrick J. Wong 	.dup_cursor		= xfs_rmapbt_dup_cursor,
125035e00acSDarrick J. Wong 	.buf_ops		= &xfs_rmapbt_buf_ops,
126035e00acSDarrick J. Wong 
127035e00acSDarrick J. Wong 	.get_leaf_keys		= xfs_btree_get_leaf_keys_overlapped,
128035e00acSDarrick J. Wong 	.get_node_keys		= xfs_btree_get_node_keys_overlapped,
129035e00acSDarrick J. Wong 	.update_keys		= xfs_btree_update_keys_overlapped,
130035e00acSDarrick J. Wong };
131035e00acSDarrick J. Wong 
132035e00acSDarrick J. Wong /*
133035e00acSDarrick J. Wong  * Allocate a new allocation btree cursor.
134035e00acSDarrick J. Wong  */
135035e00acSDarrick J. Wong struct xfs_btree_cur *
136035e00acSDarrick J. Wong xfs_rmapbt_init_cursor(
137035e00acSDarrick J. Wong 	struct xfs_mount	*mp,
138035e00acSDarrick J. Wong 	struct xfs_trans	*tp,
139035e00acSDarrick J. Wong 	struct xfs_buf		*agbp,
140035e00acSDarrick J. Wong 	xfs_agnumber_t		agno)
141035e00acSDarrick J. Wong {
142035e00acSDarrick J. Wong 	struct xfs_agf		*agf = XFS_BUF_TO_AGF(agbp);
143035e00acSDarrick J. Wong 	struct xfs_btree_cur	*cur;
144035e00acSDarrick J. Wong 
145035e00acSDarrick J. Wong 	cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_NOFS);
146035e00acSDarrick J. Wong 	cur->bc_tp = tp;
147035e00acSDarrick J. Wong 	cur->bc_mp = mp;
148035e00acSDarrick J. Wong 	cur->bc_btnum = XFS_BTNUM_RMAP;
149035e00acSDarrick J. Wong 	cur->bc_flags = XFS_BTREE_CRC_BLOCKS;
150035e00acSDarrick J. Wong 	cur->bc_blocklog = mp->m_sb.sb_blocklog;
151035e00acSDarrick J. Wong 	cur->bc_ops = &xfs_rmapbt_ops;
152035e00acSDarrick J. Wong 	cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]);
153035e00acSDarrick J. Wong 
154035e00acSDarrick J. Wong 	cur->bc_private.a.agbp = agbp;
155035e00acSDarrick J. Wong 	cur->bc_private.a.agno = agno;
156035e00acSDarrick J. Wong 
157035e00acSDarrick J. Wong 	return cur;
158035e00acSDarrick J. Wong }
159035e00acSDarrick J. Wong 
160035e00acSDarrick J. Wong /*
161035e00acSDarrick J. Wong  * Calculate number of records in an rmap btree block.
162035e00acSDarrick J. Wong  */
163035e00acSDarrick J. Wong int
164035e00acSDarrick J. Wong xfs_rmapbt_maxrecs(
165035e00acSDarrick J. Wong 	struct xfs_mount	*mp,
166035e00acSDarrick J. Wong 	int			blocklen,
167035e00acSDarrick J. Wong 	int			leaf)
168035e00acSDarrick J. Wong {
169035e00acSDarrick J. Wong 	blocklen -= XFS_RMAP_BLOCK_LEN;
170035e00acSDarrick J. Wong 
171035e00acSDarrick J. Wong 	if (leaf)
172035e00acSDarrick J. Wong 		return blocklen / sizeof(struct xfs_rmap_rec);
173035e00acSDarrick J. Wong 	return blocklen /
174035e00acSDarrick J. Wong 		(sizeof(struct xfs_rmap_key) + sizeof(xfs_rmap_ptr_t));
175035e00acSDarrick J. Wong }
176035e00acSDarrick J. Wong 
177035e00acSDarrick J. Wong /* Compute the maximum height of an rmap btree. */
178035e00acSDarrick J. Wong void
179035e00acSDarrick J. Wong xfs_rmapbt_compute_maxlevels(
180035e00acSDarrick J. Wong 	struct xfs_mount		*mp)
181035e00acSDarrick J. Wong {
182035e00acSDarrick J. Wong 	mp->m_rmap_maxlevels = xfs_btree_compute_maxlevels(mp,
183035e00acSDarrick J. Wong 			mp->m_rmap_mnr, mp->m_sb.sb_agblocks);
184035e00acSDarrick J. Wong }
185