]>
Commit | Line | Data |
---|---|---|
b3a96b46 DW |
1 | /* |
2 | * Copyright (c) 2014 Red Hat, Inc. | |
3 | * All Rights Reserved. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or | |
6 | * modify it under the terms of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope that it would be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License | |
15 | * along with this program; if not, write the Free Software Foundation, | |
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
17 | */ | |
18 | #include "libxfs_priv.h" | |
19 | #include "xfs_fs.h" | |
20 | #include "xfs_shared.h" | |
21 | #include "xfs_format.h" | |
22 | #include "xfs_log_format.h" | |
23 | #include "xfs_trans_resv.h" | |
24 | #include "xfs_bit.h" | |
25 | #include "xfs_sb.h" | |
26 | #include "xfs_mount.h" | |
27 | #include "xfs_defer.h" | |
28 | #include "xfs_inode.h" | |
29 | #include "xfs_trans.h" | |
30 | #include "xfs_alloc.h" | |
31 | #include "xfs_btree.h" | |
32 | #include "xfs_rmap_btree.h" | |
33 | #include "xfs_trace.h" | |
34 | #include "xfs_cksum.h" | |
35 | ||
36 | static struct xfs_btree_cur * | |
37 | xfs_rmapbt_dup_cursor( | |
38 | struct xfs_btree_cur *cur) | |
39 | { | |
40 | return xfs_rmapbt_init_cursor(cur->bc_mp, cur->bc_tp, | |
41 | cur->bc_private.a.agbp, cur->bc_private.a.agno); | |
42 | } | |
43 | ||
44 | static bool | |
45 | xfs_rmapbt_verify( | |
46 | struct xfs_buf *bp) | |
47 | { | |
48 | struct xfs_mount *mp = bp->b_target->bt_mount; | |
49 | struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); | |
50 | struct xfs_perag *pag = bp->b_pag; | |
51 | unsigned int level; | |
52 | ||
53 | /* | |
54 | * magic number and level verification | |
55 | * | |
56 | * During growfs operations, we can't verify the exact level or owner as | |
57 | * the perag is not fully initialised and hence not attached to the | |
58 | * buffer. In this case, check against the maximum tree depth. | |
59 | * | |
60 | * Similarly, during log recovery we will have a perag structure | |
61 | * attached, but the agf information will not yet have been initialised | |
62 | * from the on disk AGF. Again, we can only check against maximum limits | |
63 | * in this case. | |
64 | */ | |
65 | if (block->bb_magic != cpu_to_be32(XFS_RMAP_CRC_MAGIC)) | |
66 | return false; | |
67 | ||
68 | if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) | |
69 | return false; | |
70 | if (!xfs_btree_sblock_v5hdr_verify(bp)) | |
71 | return false; | |
72 | ||
73 | level = be16_to_cpu(block->bb_level); | |
74 | if (pag && pag->pagf_init) { | |
75 | if (level >= pag->pagf_levels[XFS_BTNUM_RMAPi]) | |
76 | return false; | |
77 | } else if (level >= mp->m_rmap_maxlevels) | |
78 | return false; | |
79 | ||
80 | return xfs_btree_sblock_verify(bp, mp->m_rmap_mxr[level != 0]); | |
81 | } | |
82 | ||
83 | static void | |
84 | xfs_rmapbt_read_verify( | |
85 | struct xfs_buf *bp) | |
86 | { | |
87 | if (!xfs_btree_sblock_verify_crc(bp)) | |
88 | xfs_buf_ioerror(bp, -EFSBADCRC); | |
89 | else if (!xfs_rmapbt_verify(bp)) | |
90 | xfs_buf_ioerror(bp, -EFSCORRUPTED); | |
91 | ||
92 | if (bp->b_error) { | |
93 | trace_xfs_btree_corrupt(bp, _RET_IP_); | |
94 | xfs_verifier_error(bp); | |
95 | } | |
96 | } | |
97 | ||
98 | static void | |
99 | xfs_rmapbt_write_verify( | |
100 | struct xfs_buf *bp) | |
101 | { | |
102 | if (!xfs_rmapbt_verify(bp)) { | |
103 | trace_xfs_btree_corrupt(bp, _RET_IP_); | |
104 | xfs_buf_ioerror(bp, -EFSCORRUPTED); | |
105 | xfs_verifier_error(bp); | |
106 | return; | |
107 | } | |
108 | xfs_btree_sblock_calc_crc(bp); | |
109 | ||
110 | } | |
111 | ||
112 | const struct xfs_buf_ops xfs_rmapbt_buf_ops = { | |
113 | .name = "xfs_rmapbt", | |
114 | .verify_read = xfs_rmapbt_read_verify, | |
115 | .verify_write = xfs_rmapbt_write_verify, | |
116 | }; | |
117 | ||
118 | static const struct xfs_btree_ops xfs_rmapbt_ops = { | |
119 | .rec_len = sizeof(struct xfs_rmap_rec), | |
120 | .key_len = 2 * sizeof(struct xfs_rmap_key), | |
121 | ||
122 | .dup_cursor = xfs_rmapbt_dup_cursor, | |
123 | .buf_ops = &xfs_rmapbt_buf_ops, | |
124 | ||
125 | .get_leaf_keys = xfs_btree_get_leaf_keys_overlapped, | |
126 | .get_node_keys = xfs_btree_get_node_keys_overlapped, | |
127 | .update_keys = xfs_btree_update_keys_overlapped, | |
128 | }; | |
129 | ||
130 | /* | |
131 | * Allocate a new allocation btree cursor. | |
132 | */ | |
133 | struct xfs_btree_cur * | |
134 | xfs_rmapbt_init_cursor( | |
135 | struct xfs_mount *mp, | |
136 | struct xfs_trans *tp, | |
137 | struct xfs_buf *agbp, | |
138 | xfs_agnumber_t agno) | |
139 | { | |
140 | struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); | |
141 | struct xfs_btree_cur *cur; | |
142 | ||
143 | cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_NOFS); | |
144 | cur->bc_tp = tp; | |
145 | cur->bc_mp = mp; | |
146 | cur->bc_btnum = XFS_BTNUM_RMAP; | |
147 | cur->bc_flags = XFS_BTREE_CRC_BLOCKS; | |
148 | cur->bc_blocklog = mp->m_sb.sb_blocklog; | |
149 | cur->bc_ops = &xfs_rmapbt_ops; | |
150 | cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]); | |
151 | ||
152 | cur->bc_private.a.agbp = agbp; | |
153 | cur->bc_private.a.agno = agno; | |
154 | ||
155 | return cur; | |
156 | } | |
157 | ||
158 | /* | |
159 | * Calculate number of records in an rmap btree block. | |
160 | */ | |
161 | int | |
162 | xfs_rmapbt_maxrecs( | |
163 | struct xfs_mount *mp, | |
164 | int blocklen, | |
165 | int leaf) | |
166 | { | |
167 | blocklen -= XFS_RMAP_BLOCK_LEN; | |
168 | ||
169 | if (leaf) | |
170 | return blocklen / sizeof(struct xfs_rmap_rec); | |
171 | return blocklen / | |
172 | (sizeof(struct xfs_rmap_key) + sizeof(xfs_rmap_ptr_t)); | |
173 | } | |
174 | ||
175 | /* Compute the maximum height of an rmap btree. */ | |
176 | void | |
177 | xfs_rmapbt_compute_maxlevels( | |
178 | struct xfs_mount *mp) | |
179 | { | |
180 | mp->m_rmap_maxlevels = xfs_btree_compute_maxlevels(mp, | |
181 | mp->m_rmap_mnr, mp->m_sb.sb_agblocks); | |
182 | } |