Commit 04c23151 authored by Theodore Ts'o's avatar Theodore Ts'o

ext4: fix extent sanity checking code with AGGRESSIVE_TEST

The extents sanity-checking code depends on the ext4_ext_space_*()
functions returning the maximum alloable size for eh_max; however,
when the debugging #ifdef AGGRESSIVE_TEST is enabled to test the
extent tree handling code, this prevents a normally created ext4
filesystem from being mounted with the errors:

Aug 26 15:43:50 bsd086 kernel: [   96.070277] EXT4-fs error (device sda8): ext4_ext_check_inode: bad header/extent in inode #8: too large eh_max - magic f30a, entries 1, max 4(3), depth 0(0)
Aug 26 15:43:50 bsd086 kernel: [   96.070526] EXT4-fs (sda8): no journal found

Bug reported by Akira Fujita.
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent 4ee0d137
...@@ -229,57 +229,65 @@ ext4_ext_new_meta_block(handle_t *handle, struct inode *inode, ...@@ -229,57 +229,65 @@ ext4_ext_new_meta_block(handle_t *handle, struct inode *inode,
return newblock; return newblock;
} }
static int ext4_ext_space_block(struct inode *inode) static inline int ext4_ext_space_block(struct inode *inode, int check)
{ {
int size; int size;
size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header)) size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header))
/ sizeof(struct ext4_extent); / sizeof(struct ext4_extent);
if (!check) {
#ifdef AGGRESSIVE_TEST #ifdef AGGRESSIVE_TEST
if (size > 6) if (size > 6)
size = 6; size = 6;
#endif #endif
}
return size; return size;
} }
static int ext4_ext_space_block_idx(struct inode *inode) static inline int ext4_ext_space_block_idx(struct inode *inode, int check)
{ {
int size; int size;
size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header)) size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header))
/ sizeof(struct ext4_extent_idx); / sizeof(struct ext4_extent_idx);
if (!check) {
#ifdef AGGRESSIVE_TEST #ifdef AGGRESSIVE_TEST
if (size > 5) if (size > 5)
size = 5; size = 5;
#endif #endif
}
return size; return size;
} }
static int ext4_ext_space_root(struct inode *inode) static inline int ext4_ext_space_root(struct inode *inode, int check)
{ {
int size; int size;
size = sizeof(EXT4_I(inode)->i_data); size = sizeof(EXT4_I(inode)->i_data);
size -= sizeof(struct ext4_extent_header); size -= sizeof(struct ext4_extent_header);
size /= sizeof(struct ext4_extent); size /= sizeof(struct ext4_extent);
if (!check) {
#ifdef AGGRESSIVE_TEST #ifdef AGGRESSIVE_TEST
if (size > 3) if (size > 3)
size = 3; size = 3;
#endif #endif
}
return size; return size;
} }
static int ext4_ext_space_root_idx(struct inode *inode) static inline int ext4_ext_space_root_idx(struct inode *inode, int check)
{ {
int size; int size;
size = sizeof(EXT4_I(inode)->i_data); size = sizeof(EXT4_I(inode)->i_data);
size -= sizeof(struct ext4_extent_header); size -= sizeof(struct ext4_extent_header);
size /= sizeof(struct ext4_extent_idx); size /= sizeof(struct ext4_extent_idx);
if (!check) {
#ifdef AGGRESSIVE_TEST #ifdef AGGRESSIVE_TEST
if (size > 4) if (size > 4)
size = 4; size = 4;
#endif #endif
}
return size; return size;
} }
...@@ -293,9 +301,9 @@ int ext4_ext_calc_metadata_amount(struct inode *inode, int blocks) ...@@ -293,9 +301,9 @@ int ext4_ext_calc_metadata_amount(struct inode *inode, int blocks)
int lcap, icap, rcap, leafs, idxs, num; int lcap, icap, rcap, leafs, idxs, num;
int newextents = blocks; int newextents = blocks;
rcap = ext4_ext_space_root_idx(inode); rcap = ext4_ext_space_root_idx(inode, 0);
lcap = ext4_ext_space_block(inode); lcap = ext4_ext_space_block(inode, 0);
icap = ext4_ext_space_block_idx(inode); icap = ext4_ext_space_block_idx(inode, 0);
/* number of new leaf blocks needed */ /* number of new leaf blocks needed */
num = leafs = (newextents + lcap - 1) / lcap; num = leafs = (newextents + lcap - 1) / lcap;
...@@ -320,14 +328,14 @@ ext4_ext_max_entries(struct inode *inode, int depth) ...@@ -320,14 +328,14 @@ ext4_ext_max_entries(struct inode *inode, int depth)
if (depth == ext_depth(inode)) { if (depth == ext_depth(inode)) {
if (depth == 0) if (depth == 0)
max = ext4_ext_space_root(inode); max = ext4_ext_space_root(inode, 1);
else else
max = ext4_ext_space_root_idx(inode); max = ext4_ext_space_root_idx(inode, 1);
} else { } else {
if (depth == 0) if (depth == 0)
max = ext4_ext_space_block(inode); max = ext4_ext_space_block(inode, 1);
else else
max = ext4_ext_space_block_idx(inode); max = ext4_ext_space_block_idx(inode, 1);
} }
return max; return max;
...@@ -626,7 +634,7 @@ int ext4_ext_tree_init(handle_t *handle, struct inode *inode) ...@@ -626,7 +634,7 @@ int ext4_ext_tree_init(handle_t *handle, struct inode *inode)
eh->eh_depth = 0; eh->eh_depth = 0;
eh->eh_entries = 0; eh->eh_entries = 0;
eh->eh_magic = EXT4_EXT_MAGIC; eh->eh_magic = EXT4_EXT_MAGIC;
eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode)); eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode, 0));
ext4_mark_inode_dirty(handle, inode); ext4_mark_inode_dirty(handle, inode);
ext4_ext_invalidate_cache(inode); ext4_ext_invalidate_cache(inode);
return 0; return 0;
...@@ -851,7 +859,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, ...@@ -851,7 +859,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
neh = ext_block_hdr(bh); neh = ext_block_hdr(bh);
neh->eh_entries = 0; neh->eh_entries = 0;
neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode)); neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0));
neh->eh_magic = EXT4_EXT_MAGIC; neh->eh_magic = EXT4_EXT_MAGIC;
neh->eh_depth = 0; neh->eh_depth = 0;
ex = EXT_FIRST_EXTENT(neh); ex = EXT_FIRST_EXTENT(neh);
...@@ -927,7 +935,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, ...@@ -927,7 +935,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
neh = ext_block_hdr(bh); neh = ext_block_hdr(bh);
neh->eh_entries = cpu_to_le16(1); neh->eh_entries = cpu_to_le16(1);
neh->eh_magic = EXT4_EXT_MAGIC; neh->eh_magic = EXT4_EXT_MAGIC;
neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode)); neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode, 0));
neh->eh_depth = cpu_to_le16(depth - i); neh->eh_depth = cpu_to_le16(depth - i);
fidx = EXT_FIRST_INDEX(neh); fidx = EXT_FIRST_INDEX(neh);
fidx->ei_block = border; fidx->ei_block = border;
...@@ -1052,9 +1060,9 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, ...@@ -1052,9 +1060,9 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
/* old root could have indexes or leaves /* old root could have indexes or leaves
* so calculate e_max right way */ * so calculate e_max right way */
if (ext_depth(inode)) if (ext_depth(inode))
neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode)); neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode, 0));
else else
neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode)); neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0));
neh->eh_magic = EXT4_EXT_MAGIC; neh->eh_magic = EXT4_EXT_MAGIC;
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
unlock_buffer(bh); unlock_buffer(bh);
...@@ -1069,7 +1077,7 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, ...@@ -1069,7 +1077,7 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
goto out; goto out;
curp->p_hdr->eh_magic = EXT4_EXT_MAGIC; curp->p_hdr->eh_magic = EXT4_EXT_MAGIC;
curp->p_hdr->eh_max = cpu_to_le16(ext4_ext_space_root_idx(inode)); curp->p_hdr->eh_max = cpu_to_le16(ext4_ext_space_root_idx(inode, 0));
curp->p_hdr->eh_entries = cpu_to_le16(1); curp->p_hdr->eh_entries = cpu_to_le16(1);
curp->p_idx = EXT_FIRST_INDEX(curp->p_hdr); curp->p_idx = EXT_FIRST_INDEX(curp->p_hdr);
...@@ -2348,7 +2356,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start) ...@@ -2348,7 +2356,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
if (err == 0) { if (err == 0) {
ext_inode_hdr(inode)->eh_depth = 0; ext_inode_hdr(inode)->eh_depth = 0;
ext_inode_hdr(inode)->eh_max = ext_inode_hdr(inode)->eh_max =
cpu_to_le16(ext4_ext_space_root(inode)); cpu_to_le16(ext4_ext_space_root(inode, 0));
err = ext4_ext_dirty(handle, inode, path); err = ext4_ext_dirty(handle, inode, path);
} }
} }
......
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