Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 55ad63bf authored by Theodore Ts'o's avatar Theodore Ts'o
Browse files

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 a36b4498
Loading
Loading
Loading
Loading
+34 −26
Original line number Original line Diff line number Diff line
@@ -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)
	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)


	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)
	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,


	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,
		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,
	/* 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,
		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)
		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);
		}
		}
	}
	}