Commit 3d82abae authored by Eric Sandeen's avatar Eric Sandeen Committed by Linus Torvalds

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: default avatarEric Sandeen <sandeen@redhat.com>
Acked-by: default avatarDuane Griffin <duaneg@dghda.com>
Acked-by: default avatarTheodore Ts'o <tytso@mit.edu>
Cc: <stable@kernel.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent e67aa27a
...@@ -379,13 +379,28 @@ dx_probe(struct dentry *dentry, struct inode *dir, ...@@ -379,13 +379,28 @@ dx_probe(struct dentry *dentry, struct inode *dir,
entries = (struct dx_entry *) (((char *)&root->info) + entries = (struct dx_entry *) (((char *)&root->info) +
root->info.info_length); root->info.info_length);
assert(dx_get_limit(entries) == dx_root_limit(dir,
root->info.info_length)); if (dx_get_limit(entries) != dx_root_limit(dir,
root->info.info_length)) {
ext3_warning(dir->i_sb, __FUNCTION__,
"dx entry: limit != root limit");
brelse(bh);
*err = ERR_BAD_DX_DIR;
goto fail;
}
dxtrace (printk("Look up %x", hash)); dxtrace (printk("Look up %x", hash));
while (1) while (1)
{ {
count = dx_get_count(entries); count = dx_get_count(entries);
assert (count && count <= dx_get_limit(entries)); if (!count || count > dx_get_limit(entries)) {
ext3_warning(dir->i_sb, __FUNCTION__,
"dx entry: no count or count > limit");
brelse(bh);
*err = ERR_BAD_DX_DIR;
goto fail2;
}
p = entries + 1; p = entries + 1;
q = entries + count - 1; q = entries + count - 1;
while (p <= q) while (p <= q)
...@@ -423,8 +438,15 @@ dx_probe(struct dentry *dentry, struct inode *dir, ...@@ -423,8 +438,15 @@ dx_probe(struct dentry *dentry, struct inode *dir,
if (!(bh = ext3_bread (NULL,dir, dx_get_block(at), 0, err))) if (!(bh = ext3_bread (NULL,dir, dx_get_block(at), 0, err)))
goto fail2; goto fail2;
at = entries = ((struct dx_node *) bh->b_data)->entries; at = entries = ((struct dx_node *) bh->b_data)->entries;
assert (dx_get_limit(entries) == dx_node_limit (dir)); if (dx_get_limit(entries) != dx_node_limit (dir)) {
ext3_warning(dir->i_sb, __FUNCTION__,
"dx entry: limit != node limit");
brelse(bh);
*err = ERR_BAD_DX_DIR;
goto fail2;
}
frame++; frame++;
frame->bh = NULL;
} }
fail2: fail2:
while (frame >= frame_in) { while (frame >= frame_in) {
...@@ -432,6 +454,10 @@ dx_probe(struct dentry *dentry, struct inode *dir, ...@@ -432,6 +454,10 @@ dx_probe(struct dentry *dentry, struct inode *dir,
frame--; frame--;
} }
fail: fail:
if (*err == ERR_BAD_DX_DIR)
ext3_warning(dir->i_sb, __FUNCTION__,
"Corrupt dir inode %ld, running e2fsck is "
"recommended.", dir->i_ino);
return NULL; return NULL;
} }
......
...@@ -379,13 +379,28 @@ dx_probe(struct dentry *dentry, struct inode *dir, ...@@ -379,13 +379,28 @@ dx_probe(struct dentry *dentry, struct inode *dir,
entries = (struct dx_entry *) (((char *)&root->info) + entries = (struct dx_entry *) (((char *)&root->info) +
root->info.info_length); root->info.info_length);
assert(dx_get_limit(entries) == dx_root_limit(dir,
root->info.info_length)); if (dx_get_limit(entries) != dx_root_limit(dir,
root->info.info_length)) {
ext4_warning(dir->i_sb, __FUNCTION__,
"dx entry: limit != root limit");
brelse(bh);
*err = ERR_BAD_DX_DIR;
goto fail;
}
dxtrace (printk("Look up %x", hash)); dxtrace (printk("Look up %x", hash));
while (1) while (1)
{ {
count = dx_get_count(entries); count = dx_get_count(entries);
assert (count && count <= dx_get_limit(entries)); if (!count || count > dx_get_limit(entries)) {
ext4_warning(dir->i_sb, __FUNCTION__,
"dx entry: no count or count > limit");
brelse(bh);
*err = ERR_BAD_DX_DIR;
goto fail2;
}
p = entries + 1; p = entries + 1;
q = entries + count - 1; q = entries + count - 1;
while (p <= q) while (p <= q)
...@@ -423,8 +438,15 @@ dx_probe(struct dentry *dentry, struct inode *dir, ...@@ -423,8 +438,15 @@ dx_probe(struct dentry *dentry, struct inode *dir,
if (!(bh = ext4_bread (NULL,dir, dx_get_block(at), 0, err))) if (!(bh = ext4_bread (NULL,dir, dx_get_block(at), 0, err)))
goto fail2; goto fail2;
at = entries = ((struct dx_node *) bh->b_data)->entries; at = entries = ((struct dx_node *) bh->b_data)->entries;
assert (dx_get_limit(entries) == dx_node_limit (dir)); if (dx_get_limit(entries) != dx_node_limit (dir)) {
ext4_warning(dir->i_sb, __FUNCTION__,
"dx entry: limit != node limit");
brelse(bh);
*err = ERR_BAD_DX_DIR;
goto fail2;
}
frame++; frame++;
frame->bh = NULL;
} }
fail2: fail2:
while (frame >= frame_in) { while (frame >= frame_in) {
...@@ -432,6 +454,10 @@ dx_probe(struct dentry *dentry, struct inode *dir, ...@@ -432,6 +454,10 @@ dx_probe(struct dentry *dentry, struct inode *dir,
frame--; frame--;
} }
fail: fail:
if (*err == ERR_BAD_DX_DIR)
ext4_warning(dir->i_sb, __FUNCTION__,
"Corrupt dir inode %ld, running e2fsck is "
"recommended.", dir->i_ino);
return NULL; return NULL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment