diff options
author | Eric Sandeen <sandeen@redhat.com> | 2007-09-19 01:46:38 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-09-19 14:24:18 -0400 |
commit | 3d82abae9523c33d4a16fdfdfd2bdde316d7b56a (patch) | |
tree | e0059b667ac7ef765814a2ee9587f9e89015b387 /fs/ext4 | |
parent | e67aa27a6179c287983c6c525beb5320f5cd1672 (diff) |
dir_index: error out instead of BUG on corrupt dx dirs
Convert asserts (BUGs) in dx_probe from bad on-disk data to recoverable
errors with helpful warnings. With help catching other asserts from Duane
Griffin <duaneg@dghda.com>
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Acked-by: Duane Griffin <duaneg@dghda.com>
Acked-by: Theodore Ts'o <tytso@mit.edu>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/namei.c | 34 |
1 files changed, 30 insertions, 4 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index da224974af78..9468289637a5 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -379,13 +379,28 @@ dx_probe(struct dentry *dentry, struct inode *dir, | |||
379 | 379 | ||
380 | entries = (struct dx_entry *) (((char *)&root->info) + | 380 | entries = (struct dx_entry *) (((char *)&root->info) + |
381 | root->info.info_length); | 381 | root->info.info_length); |
382 | assert(dx_get_limit(entries) == dx_root_limit(dir, | 382 | |
383 | root->info.info_length)); | 383 | if (dx_get_limit(entries) != dx_root_limit(dir, |
384 | root->info.info_length)) { | ||
385 | ext4_warning(dir->i_sb, __FUNCTION__, | ||
386 | "dx entry: limit != root limit"); | ||
387 | brelse(bh); | ||
388 | *err = ERR_BAD_DX_DIR; | ||
389 | goto fail; | ||
390 | } | ||
391 | |||
384 | dxtrace (printk("Look up %x", hash)); | 392 | dxtrace (printk("Look up %x", hash)); |
385 | while (1) | 393 | while (1) |
386 | { | 394 | { |
387 | count = dx_get_count(entries); | 395 | count = dx_get_count(entries); |
388 | assert (count && count <= dx_get_limit(entries)); | 396 | if (!count || count > dx_get_limit(entries)) { |
397 | ext4_warning(dir->i_sb, __FUNCTION__, | ||
398 | "dx entry: no count or count > limit"); | ||
399 | brelse(bh); | ||
400 | *err = ERR_BAD_DX_DIR; | ||
401 | goto fail2; | ||
402 | } | ||
403 | |||
389 | p = entries + 1; | 404 | p = entries + 1; |
390 | q = entries + count - 1; | 405 | q = entries + count - 1; |
391 | while (p <= q) | 406 | while (p <= q) |
@@ -423,8 +438,15 @@ dx_probe(struct dentry *dentry, struct inode *dir, | |||
423 | if (!(bh = ext4_bread (NULL,dir, dx_get_block(at), 0, err))) | 438 | if (!(bh = ext4_bread (NULL,dir, dx_get_block(at), 0, err))) |
424 | goto fail2; | 439 | goto fail2; |
425 | at = entries = ((struct dx_node *) bh->b_data)->entries; | 440 | at = entries = ((struct dx_node *) bh->b_data)->entries; |
426 | assert (dx_get_limit(entries) == dx_node_limit (dir)); | 441 | if (dx_get_limit(entries) != dx_node_limit (dir)) { |
442 | ext4_warning(dir->i_sb, __FUNCTION__, | ||
443 | "dx entry: limit != node limit"); | ||
444 | brelse(bh); | ||
445 | *err = ERR_BAD_DX_DIR; | ||
446 | goto fail2; | ||
447 | } | ||
427 | frame++; | 448 | frame++; |
449 | frame->bh = NULL; | ||
428 | } | 450 | } |
429 | fail2: | 451 | fail2: |
430 | while (frame >= frame_in) { | 452 | while (frame >= frame_in) { |
@@ -432,6 +454,10 @@ fail2: | |||
432 | frame--; | 454 | frame--; |
433 | } | 455 | } |
434 | fail: | 456 | fail: |
457 | if (*err == ERR_BAD_DX_DIR) | ||
458 | ext4_warning(dir->i_sb, __FUNCTION__, | ||
459 | "Corrupt dir inode %ld, running e2fsck is " | ||
460 | "recommended.", dir->i_ino); | ||
435 | return NULL; | 461 | return NULL; |
436 | } | 462 | } |
437 | 463 | ||