aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nilfs2
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
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')
-rw-r--r--fs/nilfs2/btree.c50
-rw-r--r--fs/nilfs2/btree.h2
-rw-r--r--fs/nilfs2/gcinode.c9
3 files changed, 56 insertions, 5 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{
diff --git a/fs/nilfs2/btree.h b/fs/nilfs2/btree.h
index 43c8c5b541fd..980e1e8ec53a 100644
--- a/fs/nilfs2/btree.h
+++ b/fs/nilfs2/btree.h
@@ -80,4 +80,6 @@ int nilfs_btree_convert_and_insert(struct nilfs_bmap *, __u64, __u64,
80 const __u64 *, const __u64 *, int); 80 const __u64 *, const __u64 *, int);
81void nilfs_btree_init_gc(struct nilfs_bmap *); 81void nilfs_btree_init_gc(struct nilfs_bmap *);
82 82
83int nilfs_btree_broken_node_block(struct buffer_head *bh);
84
83#endif /* _NILFS_BTREE_H */ 85#endif /* _NILFS_BTREE_H */
diff --git a/fs/nilfs2/gcinode.c b/fs/nilfs2/gcinode.c
index 145f03cd7d3e..edb53fcb7f83 100644
--- a/fs/nilfs2/gcinode.c
+++ b/fs/nilfs2/gcinode.c
@@ -164,10 +164,15 @@ int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *bh)
164 if (buffer_dirty(bh)) 164 if (buffer_dirty(bh))
165 return -EEXIST; 165 return -EEXIST;
166 166
167 if (buffer_nilfs_node(bh)) 167 if (buffer_nilfs_node(bh)) {
168 if (nilfs_btree_broken_node_block(bh)) {
169 clear_buffer_uptodate(bh);
170 return -EIO;
171 }
168 nilfs_btnode_mark_dirty(bh); 172 nilfs_btnode_mark_dirty(bh);
169 else 173 } else {
170 nilfs_mdt_mark_buffer_dirty(bh); 174 nilfs_mdt_mark_buffer_dirty(bh);
175 }
171 return 0; 176 return 0;
172} 177}
173 178