diff options
Diffstat (limited to 'fs/nilfs2')
-rw-r--r-- | fs/nilfs2/btree.c | 50 | ||||
-rw-r--r-- | fs/nilfs2/btree.h | 2 | ||||
-rw-r--r-- | fs/nilfs2/gcinode.c | 9 |
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 | */ | ||
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 | { |
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); |
81 | void nilfs_btree_init_gc(struct nilfs_bmap *); | 81 | void nilfs_btree_init_gc(struct nilfs_bmap *); |
82 | 82 | ||
83 | int 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 | ||