aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nilfs2/btree.c
diff options
context:
space:
mode:
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2010-07-16 10:52:40 -0400
committerRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2010-07-22 21:02:13 -0400
commit1d5385b9f30ae43209459db424416a3e1d8f2bde (patch)
tree202a19586853da9ec598645b5d289d4a0164b232 /fs/nilfs2/btree.c
parentcfa913a5077f7619869b2b4d1bf23ccb4f8b3d7b (diff)
nilfs2: verify btree node after reading
This inserts sanity checks soon after read btree node from disk. This allows early detection of broken btree nodes, and helps to narrow down problems due to file system corruption. Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Diffstat (limited to 'fs/nilfs2/btree.c')
-rw-r--r--fs/nilfs2/btree.c50
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 */
400static 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
423int 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
385static inline struct nilfs_btree_node * 429static inline struct nilfs_btree_node *
386nilfs_btree_get_root(const struct nilfs_btree *btree) 430nilfs_btree_get_root(const struct nilfs_btree *btree)
387{ 431{