diff options
Diffstat (limited to 'fs/xfs/xfs_alloc_btree.c')
-rw-r--r-- | fs/xfs/xfs_alloc_btree.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c index f1647caace8f..b1ddef6b2689 100644 --- a/fs/xfs/xfs_alloc_btree.c +++ b/fs/xfs/xfs_alloc_btree.c | |||
@@ -121,6 +121,8 @@ xfs_allocbt_free_block( | |||
121 | xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1, | 121 | xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1, |
122 | XFS_EXTENT_BUSY_SKIP_DISCARD); | 122 | XFS_EXTENT_BUSY_SKIP_DISCARD); |
123 | xfs_trans_agbtree_delta(cur->bc_tp, -1); | 123 | xfs_trans_agbtree_delta(cur->bc_tp, -1); |
124 | |||
125 | xfs_trans_binval(cur->bc_tp, bp); | ||
124 | return 0; | 126 | return 0; |
125 | } | 127 | } |
126 | 128 | ||
@@ -270,6 +272,82 @@ xfs_allocbt_key_diff( | |||
270 | return (__int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock; | 272 | return (__int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock; |
271 | } | 273 | } |
272 | 274 | ||
275 | static void | ||
276 | xfs_allocbt_verify( | ||
277 | struct xfs_buf *bp) | ||
278 | { | ||
279 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
280 | struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); | ||
281 | struct xfs_perag *pag = bp->b_pag; | ||
282 | unsigned int level; | ||
283 | int sblock_ok; /* block passes checks */ | ||
284 | |||
285 | /* | ||
286 | * magic number and level verification | ||
287 | * | ||
288 | * During growfs operations, we can't verify the exact level as the | ||
289 | * perag is not fully initialised and hence not attached to the buffer. | ||
290 | * In this case, check against the maximum tree depth. | ||
291 | */ | ||
292 | level = be16_to_cpu(block->bb_level); | ||
293 | switch (block->bb_magic) { | ||
294 | case cpu_to_be32(XFS_ABTB_MAGIC): | ||
295 | if (pag) | ||
296 | sblock_ok = level < pag->pagf_levels[XFS_BTNUM_BNOi]; | ||
297 | else | ||
298 | sblock_ok = level < mp->m_ag_maxlevels; | ||
299 | break; | ||
300 | case cpu_to_be32(XFS_ABTC_MAGIC): | ||
301 | if (pag) | ||
302 | sblock_ok = level < pag->pagf_levels[XFS_BTNUM_CNTi]; | ||
303 | else | ||
304 | sblock_ok = level < mp->m_ag_maxlevels; | ||
305 | break; | ||
306 | default: | ||
307 | sblock_ok = 0; | ||
308 | break; | ||
309 | } | ||
310 | |||
311 | /* numrecs verification */ | ||
312 | sblock_ok = sblock_ok && | ||
313 | be16_to_cpu(block->bb_numrecs) <= mp->m_alloc_mxr[level != 0]; | ||
314 | |||
315 | /* sibling pointer verification */ | ||
316 | sblock_ok = sblock_ok && | ||
317 | (block->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK) || | ||
318 | be32_to_cpu(block->bb_u.s.bb_leftsib) < mp->m_sb.sb_agblocks) && | ||
319 | block->bb_u.s.bb_leftsib && | ||
320 | (block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK) || | ||
321 | be32_to_cpu(block->bb_u.s.bb_rightsib) < mp->m_sb.sb_agblocks) && | ||
322 | block->bb_u.s.bb_rightsib; | ||
323 | |||
324 | if (!sblock_ok) { | ||
325 | trace_xfs_btree_corrupt(bp, _RET_IP_); | ||
326 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, block); | ||
327 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
328 | } | ||
329 | } | ||
330 | |||
331 | static void | ||
332 | xfs_allocbt_read_verify( | ||
333 | struct xfs_buf *bp) | ||
334 | { | ||
335 | xfs_allocbt_verify(bp); | ||
336 | } | ||
337 | |||
338 | static void | ||
339 | xfs_allocbt_write_verify( | ||
340 | struct xfs_buf *bp) | ||
341 | { | ||
342 | xfs_allocbt_verify(bp); | ||
343 | } | ||
344 | |||
345 | const struct xfs_buf_ops xfs_allocbt_buf_ops = { | ||
346 | .verify_read = xfs_allocbt_read_verify, | ||
347 | .verify_write = xfs_allocbt_write_verify, | ||
348 | }; | ||
349 | |||
350 | |||
273 | #ifdef DEBUG | 351 | #ifdef DEBUG |
274 | STATIC int | 352 | STATIC int |
275 | xfs_allocbt_keys_inorder( | 353 | xfs_allocbt_keys_inorder( |
@@ -325,6 +403,7 @@ static const struct xfs_btree_ops xfs_allocbt_ops = { | |||
325 | .init_rec_from_cur = xfs_allocbt_init_rec_from_cur, | 403 | .init_rec_from_cur = xfs_allocbt_init_rec_from_cur, |
326 | .init_ptr_from_cur = xfs_allocbt_init_ptr_from_cur, | 404 | .init_ptr_from_cur = xfs_allocbt_init_ptr_from_cur, |
327 | .key_diff = xfs_allocbt_key_diff, | 405 | .key_diff = xfs_allocbt_key_diff, |
406 | .buf_ops = &xfs_allocbt_buf_ops, | ||
328 | #ifdef DEBUG | 407 | #ifdef DEBUG |
329 | .keys_inorder = xfs_allocbt_keys_inorder, | 408 | .keys_inorder = xfs_allocbt_keys_inorder, |
330 | .recs_inorder = xfs_allocbt_recs_inorder, | 409 | .recs_inorder = xfs_allocbt_recs_inorder, |