diff options
Diffstat (limited to 'fs/nilfs2/btree.c')
-rw-r--r-- | fs/nilfs2/btree.c | 50 |
1 files changed, 47 insertions, 3 deletions
diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index 386356707f90..6c9ec566d000 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c | |||
@@ -71,17 +71,24 @@ static int nilfs_btree_get_block(const struct nilfs_btree *btree, __u64 ptr, | |||
71 | { | 71 | { |
72 | struct address_space *btnc = | 72 | struct address_space *btnc = |
73 | &NILFS_BMAP_I((struct nilfs_bmap *)btree)->i_btnode_cache; | 73 | &NILFS_BMAP_I((struct nilfs_bmap *)btree)->i_btnode_cache; |
74 | struct buffer_head *bh; | ||
74 | int err; | 75 | int err; |
75 | 76 | ||
76 | err = nilfs_btnode_submit_block(btnc, ptr, 0, bhp); | 77 | err = nilfs_btnode_submit_block(btnc, ptr, 0, bhp); |
77 | if (err) | 78 | if (err) |
78 | return err == -EEXIST ? 0 : err; | 79 | return err == -EEXIST ? 0 : err; |
79 | 80 | ||
80 | wait_on_buffer(*bhp); | 81 | bh = *bhp; |
81 | if (!buffer_uptodate(*bhp)) { | 82 | wait_on_buffer(bh); |
82 | brelse(*bhp); | 83 | if (!buffer_uptodate(bh)) { |
84 | brelse(bh); | ||
83 | return -EIO; | 85 | return -EIO; |
84 | } | 86 | } |
87 | if (nilfs_btree_broken_node_block(bh)) { | ||
88 | clear_buffer_uptodate(bh); | ||
89 | brelse(bh); | ||
90 | return -EINVAL; | ||
91 | } | ||
85 | return 0; | 92 | return 0; |
86 | } | 93 | } |
87 | 94 | ||
@@ -382,6 +389,43 @@ static int nilfs_btree_node_lookup(const struct nilfs_btree_node *node, | |||
382 | return s == 0; | 389 | return s == 0; |
383 | } | 390 | } |
384 | 391 | ||
392 | /** | ||
393 | * nilfs_btree_node_broken - verify consistency of btree node | ||
394 | * @node: btree node block to be examined | ||
395 | * @size: node size (in bytes) | ||
396 | * @blocknr: block number | ||
397 | * | ||
398 | * Return Value: If node is broken, 1 is returned. Otherwise, 0 is returned. | ||
399 | */ | ||
400 | static int nilfs_btree_node_broken(const struct nilfs_btree_node *node, | ||
401 | size_t size, sector_t blocknr) | ||
402 | { | ||
403 | int level, flags, nchildren; | ||
404 | int ret = 0; | ||
405 | |||
406 | level = nilfs_btree_node_get_level(node); | ||
407 | flags = nilfs_btree_node_get_flags(node); | ||
408 | nchildren = nilfs_btree_node_get_nchildren(node); | ||
409 | |||
410 | if (unlikely(level < NILFS_BTREE_LEVEL_NODE_MIN || | ||
411 | level >= NILFS_BTREE_LEVEL_MAX || | ||
412 | (flags & NILFS_BTREE_NODE_ROOT) || | ||
413 | nchildren < 0 || | ||
414 | nchildren > NILFS_BTREE_NODE_NCHILDREN_MAX(size))) { | ||
415 | printk(KERN_CRIT "NILFS: bad btree node (blocknr=%llu): " | ||
416 | "level = %d, flags = 0x%x, nchildren = %d\n", | ||
417 | (unsigned long long)blocknr, level, flags, nchildren); | ||
418 | ret = 1; | ||
419 | } | ||
420 | return ret; | ||
421 | } | ||
422 | |||
423 | int nilfs_btree_broken_node_block(struct buffer_head *bh) | ||
424 | { | ||
425 | return nilfs_btree_node_broken((struct nilfs_btree_node *)bh->b_data, | ||
426 | bh->b_size, bh->b_blocknr); | ||
427 | } | ||
428 | |||
385 | static inline struct nilfs_btree_node * | 429 | static inline struct nilfs_btree_node * |
386 | nilfs_btree_get_root(const struct nilfs_btree *btree) | 430 | nilfs_btree_get_root(const struct nilfs_btree *btree) |
387 | { | 431 | { |