All of lore.kernel.org
 help / color / mirror / Atom feed
From: Zhang Yi <yizhang089@gmail.com>
To: Ojaswin Mujoo <ojaswin@linux.ibm.com>,
	linux-ext4@vger.kernel.org, Theodore Ts'o <tytso@mit.edu>
Cc: Ritesh Harjani <ritesh.list@gmail.com>,
	Zhang Yi <yi.zhang@huawei.com>, Jan Kara <jack@suse.cz>,
	libaokun1@huawei.com, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 2/8] ext4: kunit tests for higher level extent manipulation functions
Date: Sat, 17 Jan 2026 16:48:57 +0800	[thread overview]
Message-ID: <2da17870-9dab-414a-b74d-23c43cdbe58a@gmail.com> (raw)
In-Reply-To: <9d586426ba81a0b9fcb359325a23a0b7ae1d7cbf.1768402426.git.ojaswin@linux.ibm.com>

On 1/14/2026 10:57 PM, Ojaswin Mujoo wrote:
> Add more kunit tests to cover the high level caller
> ext4_map_create_blocks(). We pass flags in a manner that covers
> the below function:
> 
> 1. ext4_ext_handle_unwritten_extents()
>    1.1 - Split/Convert unwritten extent to written in endio convtext.
>    1.2 - Split/Convert unwritten extent to written in non endio context.
>    1.3 - Zeroout tests for the above 2 cases
> 2. convert_initialized_extent() - Convert written extent to unwritten
>     during zero range
> 
> Signed-off-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>


It looks good to me.

Reviewed-by: Zhang Yi <yi.zhang@huawei.com>

> ---
>   fs/ext4/ext4.h           |   4 +
>   fs/ext4/extents-test.c   | 287 ++++++++++++++++++++++++++++++++++++++-
>   fs/ext4/extents_status.c |   3 +
>   fs/ext4/inode.c          |   8 +-
>   4 files changed, 295 insertions(+), 7 deletions(-)
> 
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index 174c51402864..5f744bd19dea 100644
> --- a/fs/ext4/ext4.h
> +++ b/fs/ext4/ext4.h
> @@ -3786,6 +3786,10 @@ extern int ext4_convert_unwritten_io_end_vec(handle_t *handle,
>   					     ext4_io_end_t *io_end);
>   extern int ext4_map_blocks(handle_t *handle, struct inode *inode,
>   			   struct ext4_map_blocks *map, int flags);
> +extern int ext4_map_query_blocks(handle_t *handle, struct inode *inode,
> +				  struct ext4_map_blocks *map, int flags);
> +extern int ext4_map_create_blocks(handle_t *handle, struct inode *inode,
> +				  struct ext4_map_blocks *map, int flags);
>   extern int ext4_ext_calc_credits_for_single_extent(struct inode *inode,
>   						   int num,
>   						   struct ext4_ext_path *path);
> diff --git a/fs/ext4/extents-test.c b/fs/ext4/extents-test.c
> index 02565ad19abe..ebd7af64315a 100644
> --- a/fs/ext4/extents-test.c
> +++ b/fs/ext4/extents-test.c
> @@ -77,10 +77,18 @@ struct kunit_ext_data_state {
>   	ext4_lblk_t len_blk;
>   };
>   
> +enum kunit_test_types {
> +	TEST_SPLIT_CONVERT,
> +	TEST_CREATE_BLOCKS,
> +};
> +
>   struct kunit_ext_test_param {
>   	/* description of test */
>   	char *desc;
>   
> +	/* determines which function will be tested */
> +	int type;
> +
>   	/* is extent unwrit at beginning of test */
>   	bool is_unwrit_at_start;
>   
> @@ -90,6 +98,9 @@ struct kunit_ext_test_param {
>   	/* map describing range to split */
>   	struct ext4_map_blocks split_map;
>   
> +	/* disable zeroout */
> +	bool disable_zeroout;
> +
>   	/* no of extents expected after split */
>   	int nr_exp_ext;
>   
> @@ -131,6 +142,9 @@ static struct file_system_type ext_fs_type = {
>   
>   static void extents_kunit_exit(struct kunit *test)
>   {
> +	struct ext4_sb_info *sbi = k_ctx.k_ei->vfs_inode.i_sb->s_fs_info;
> +
> +	kfree(sbi);
>   	kfree(k_ctx.k_ei);
>   	kfree(k_ctx.k_data);
>   }
> @@ -162,6 +176,13 @@ static void ext4_es_remove_extent_stub(struct inode *inode, ext4_lblk_t lblk,
>   	return;
>   }
>   
> +void ext4_es_insert_extent_stub(struct inode *inode, ext4_lblk_t lblk,
> +				ext4_lblk_t len, ext4_fsblk_t pblk,
> +				unsigned int status, bool delalloc_reserve_used)
> +{
> +	return;
> +}
> +
>   static void ext4_zeroout_es_stub(struct inode *inode, struct ext4_extent *ex)
>   {
>   	return;
> @@ -220,6 +241,7 @@ static int extents_kunit_init(struct kunit *test)
>   	struct ext4_inode_info *ei;
>   	struct inode *inode;
>   	struct super_block *sb;
> +	struct ext4_sb_info *sbi = NULL;
>   	struct kunit_ext_test_param *param =
>   		(struct kunit_ext_test_param *)(test->param_value);
>   
> @@ -237,7 +259,20 @@ static int extents_kunit_init(struct kunit *test)
>   	sb->s_blocksize = 4096;
>   	sb->s_blocksize_bits = 12;
>   
> -	ei->i_disksize = (EX_DATA_LBLK + EX_DATA_LEN + 10) << sb->s_blocksize_bits;
> +	sbi = kzalloc(sizeof(struct ext4_sb_info), GFP_KERNEL);
> +	if (sbi == NULL)
> +		return -ENOMEM;
> +
> +	sbi->s_sb = sb;
> +	sb->s_fs_info = sbi;
> +
> +	if (!param || !param->disable_zeroout)
> +		sbi->s_extent_max_zeroout_kb = 32;
> +
> +	ei->i_disksize = (EX_DATA_LBLK + EX_DATA_LEN + 10)
> +			 << sb->s_blocksize_bits;
> +	ei->i_flags = 0;
> +	ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS);
>   	inode->i_sb = sb;
>   
>   	k_ctx.k_data = kzalloc(EX_DATA_LEN * 4096, GFP_KERNEL);
> @@ -277,6 +312,8 @@ static int extents_kunit_init(struct kunit *test)
>   				   __ext4_ext_dirty_stub);
>   	kunit_activate_static_stub(test, ext4_es_remove_extent,
>   				   ext4_es_remove_extent_stub);
> +	kunit_activate_static_stub(test, ext4_es_insert_extent,
> +				   ext4_es_insert_extent_stub);
>   	kunit_activate_static_stub(test, ext4_zeroout_es, ext4_zeroout_es_stub);
>   	kunit_activate_static_stub(test, ext4_ext_zeroout, ext4_ext_zeroout_stub);
>   	kunit_activate_static_stub(test, ext4_issue_zeroout,
> @@ -301,6 +338,30 @@ static int check_buffer(char *buf, int c, int size)
>   	return 1;
>   }
>   
> +/*
> + * Simulate a map block call by first calling ext4_map_query_blocks() to
> + * correctly populate map flags and pblk and then call the
> + * ext4_map_create_blocks() to do actual split and conversion. This is easier
> + * than calling ext4_map_blocks() because that needs mocking a lot of unrelated
> + * functions.
> + */
> +static void ext4_map_create_blocks_helper(struct kunit *test,
> +					  struct inode *inode,
> +					  struct ext4_map_blocks *map,
> +					  int flags)
> +{
> +	int retval = 0;
> +
> +	retval = ext4_map_query_blocks(NULL, inode, map, flags);
> +	if (retval < 0) {
> +		KUNIT_FAIL(test,
> +			   "ext4_map_query_blocks() failed. Cannot proceed\n");
> +		return;
> +	}
> +
> +	ext4_map_create_blocks(NULL, inode, map, flags);
> +}
> +
>   static void test_split_convert(struct kunit *test)
>   {
>   	struct ext4_ext_path *path;
> @@ -330,8 +391,18 @@ static void test_split_convert(struct kunit *test)
>   
>   	map.m_lblk = param->split_map.m_lblk;
>   	map.m_len = param->split_map.m_len;
> -	ext4_split_convert_extents(NULL, inode, &map, path,
> -				   param->split_flags, NULL);
> +
> +	switch (param->type) {
> +	case TEST_SPLIT_CONVERT:
> +		path = ext4_split_convert_extents(NULL, inode, &map, path,
> +						  param->split_flags, NULL);
> +		break;
> +	case TEST_CREATE_BLOCKS:
> +		ext4_map_create_blocks_helper(test, inode, &map, param->split_flags);
> +		break;
> +	default:
> +		KUNIT_FAIL(test, "param->type %d not support.", param->type);
> +	}
>   
>   	path = ext4_find_extent(inode, EX_DATA_LBLK, NULL, 0);
>   	ex = path->p_ext;
> @@ -383,6 +454,7 @@ static void test_split_convert(struct kunit *test)
>   static const struct kunit_ext_test_param test_split_convert_params[] = {
>   	/* unwrit to writ splits */
>   	{ .desc = "split unwrit extent to 2 extents and convert 1st half writ",
> +	  .type = TEST_SPLIT_CONVERT,
>   	  .is_unwrit_at_start = 1,
>   	  .split_flags = EXT4_GET_BLOCKS_CONVERT,
>   	  .split_map = { .m_lblk = 10, .m_len = 1 },
> @@ -391,6 +463,7 @@ static const struct kunit_ext_test_param test_split_convert_params[] = {
>   			     { .ex_lblk = 11, .ex_len = 2, .is_unwrit = 1 } },
>   	  .is_zeroout_test = 0 },
>   	{ .desc = "split unwrit extent to 2 extents and convert 2nd half writ",
> +	  .type = TEST_SPLIT_CONVERT,
>   	  .is_unwrit_at_start = 1,
>   	  .split_flags = EXT4_GET_BLOCKS_CONVERT,
>   	  .split_map = { .m_lblk = 11, .m_len = 2 },
> @@ -399,6 +472,7 @@ static const struct kunit_ext_test_param test_split_convert_params[] = {
>   			     { .ex_lblk = 11, .ex_len = 2, .is_unwrit = 0 } },
>   	  .is_zeroout_test = 0 },
>   	{ .desc = "split unwrit extent to 3 extents and convert 2nd half to writ",
> +	  .type = TEST_SPLIT_CONVERT,
>   	  .is_unwrit_at_start = 1,
>   	  .split_flags = EXT4_GET_BLOCKS_CONVERT,
>   	  .split_map = { .m_lblk = 11, .m_len = 1 },
> @@ -410,6 +484,7 @@ static const struct kunit_ext_test_param test_split_convert_params[] = {
>   
>   	/* writ to unwrit splits */
>   	{ .desc = "split writ extent to 2 extents and convert 1st half unwrit",
> +	  .type = TEST_SPLIT_CONVERT,
>   	  .is_unwrit_at_start = 0,
>   	  .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
>   	  .split_map = { .m_lblk = 10, .m_len = 1 },
> @@ -418,6 +493,7 @@ static const struct kunit_ext_test_param test_split_convert_params[] = {
>   			     { .ex_lblk = 11, .ex_len = 2, .is_unwrit = 0 } },
>   	  .is_zeroout_test = 0 },
>   	{ .desc = "split writ extent to 2 extents and convert 2nd half unwrit",
> +	  .type = TEST_SPLIT_CONVERT,
>   	  .is_unwrit_at_start = 0,
>   	  .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
>   	  .split_map = { .m_lblk = 11, .m_len = 2 },
> @@ -426,6 +502,7 @@ static const struct kunit_ext_test_param test_split_convert_params[] = {
>   			     { .ex_lblk = 11, .ex_len = 2, .is_unwrit = 1 } },
>   	  .is_zeroout_test = 0 },
>   	{ .desc = "split writ extent to 3 extents and convert 2nd half to unwrit",
> +	  .type = TEST_SPLIT_CONVERT,
>   	  .is_unwrit_at_start = 0,
>   	  .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
>   	  .split_map = { .m_lblk = 11, .m_len = 1 },
> @@ -440,6 +517,7 @@ static const struct kunit_ext_test_param test_split_convert_params[] = {
>   	 */
>   	/* unwrit to writ splits */
>   	{ .desc = "split unwrit extent to 2 extents and convert 1st half writ (zeroout)",
> +	  .type = TEST_SPLIT_CONVERT,
>   	  .is_unwrit_at_start = 1,
>   	  .split_flags = EXT4_GET_BLOCKS_CONVERT,
>   	  .split_map = { .m_lblk = 10, .m_len = 1 },
> @@ -451,6 +529,7 @@ static const struct kunit_ext_test_param test_split_convert_params[] = {
>   	  .exp_data_state = { { .exp_char = 'X', .off_blk = 0, .len_blk = 1 },
>   			      { .exp_char = 0, .off_blk = 1, .len_blk = 2 } } },
>   	{ .desc = "split unwrit extent to 2 extents and convert 2nd half writ (zeroout)",
> +	  .type = TEST_SPLIT_CONVERT,
>   	  .is_unwrit_at_start = 1,
>   	  .split_flags = EXT4_GET_BLOCKS_CONVERT,
>   	  .split_map = { .m_lblk = 11, .m_len = 2 },
> @@ -462,6 +541,7 @@ static const struct kunit_ext_test_param test_split_convert_params[] = {
>   	  .exp_data_state = { { .exp_char = 0, .off_blk = 0, .len_blk = 1 },
>   			      { .exp_char = 'X', .off_blk = 1, .len_blk = 2 } } },
>   	{ .desc = "split unwrit extent to 3 extents and convert 2nd half writ (zeroout)",
> +	  .type = TEST_SPLIT_CONVERT,
>   	  .is_unwrit_at_start = 1,
>   	  .split_flags = EXT4_GET_BLOCKS_CONVERT,
>   	  .split_map = { .m_lblk = 11, .m_len = 1 },
> @@ -476,6 +556,185 @@ static const struct kunit_ext_test_param test_split_convert_params[] = {
>   
>   };
>   
> +static const struct kunit_ext_test_param test_convert_initialized_params[] = {
> +	/* writ to unwrit splits */
> +	{ .desc = "split writ extent to 2 extents and convert 1st half unwrit",
> +	  .type = TEST_CREATE_BLOCKS,
> +	  .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
> +	  .is_unwrit_at_start = 0,
> +	  .split_map = { .m_lblk = 10, .m_len = 1 },
> +	  .nr_exp_ext = 2,
> +	  .exp_ext_state = { { .ex_lblk = 10, .ex_len = 1, .is_unwrit = 1 },
> +			     { .ex_lblk = 11, .ex_len = 2, .is_unwrit = 0 } },
> +	  .is_zeroout_test = 0 },
> +	{ .desc = "split writ extent to 2 extents and convert 2nd half unwrit",
> +	  .type = TEST_CREATE_BLOCKS,
> +	  .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
> +	  .is_unwrit_at_start = 0,
> +	  .split_map = { .m_lblk = 11, .m_len = 2 },
> +	  .nr_exp_ext = 2,
> +	  .exp_ext_state = { { .ex_lblk = 10, .ex_len = 1, .is_unwrit = 0 },
> +			     { .ex_lblk = 11, .ex_len = 2, .is_unwrit = 1 } },
> +	  .is_zeroout_test = 0 },
> +	{ .desc = "split writ extent to 3 extents and convert 2nd half to unwrit",
> +	  .type = TEST_CREATE_BLOCKS,
> +	  .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
> +	  .is_unwrit_at_start = 0,
> +	  .split_map = { .m_lblk = 11, .m_len = 1 },
> +	  .nr_exp_ext = 3,
> +	  .exp_ext_state = { { .ex_lblk = 10, .ex_len = 1, .is_unwrit = 0 },
> +			     { .ex_lblk = 11, .ex_len = 1, .is_unwrit = 1 },
> +			     { .ex_lblk = 12, .ex_len = 1, .is_unwrit = 0 } },
> +	  .is_zeroout_test = 0 },
> +};
> +
> +static const struct kunit_ext_test_param test_handle_unwritten_params[] = {
> +	/* unwrit to writ splits via endio path */
> +	{ .desc = "split unwrit extent to 2 extents and convert 1st half writ (endio)",
> +	  .type = TEST_CREATE_BLOCKS,
> +	  .is_unwrit_at_start = 1,
> +	  .split_flags = EXT4_GET_BLOCKS_CONVERT,
> +	  .split_map = { .m_lblk = 10, .m_len = 1 },
> +	  .nr_exp_ext = 2,
> +	  .exp_ext_state = { { .ex_lblk = 10, .ex_len = 1, .is_unwrit = 0 },
> +			     { .ex_lblk = 11, .ex_len = 2, .is_unwrit = 1 } },
> +	  .is_zeroout_test = 0 },
> +	{ .desc = "split unwrit extent to 2 extents and convert 2nd half writ (endio)",
> +	  .type = TEST_CREATE_BLOCKS,
> +	  .is_unwrit_at_start = 1,
> +	  .split_flags = EXT4_GET_BLOCKS_CONVERT,
> +	  .split_map = { .m_lblk = 11, .m_len = 2 },
> +	  .nr_exp_ext = 2,
> +	  .exp_ext_state = { { .ex_lblk = 10, .ex_len = 1, .is_unwrit = 1 },
> +			     { .ex_lblk = 11, .ex_len = 2, .is_unwrit = 0 } },
> +	  .is_zeroout_test = 0 },
> +	{ .desc = "split unwrit extent to 3 extents and convert 2nd half to writ (endio)",
> +	  .type = TEST_CREATE_BLOCKS,
> +	  .is_unwrit_at_start = 1,
> +	  .split_flags = EXT4_GET_BLOCKS_CONVERT,
> +	  .split_map = { .m_lblk = 11, .m_len = 1 },
> +	  .nr_exp_ext = 3,
> +	  .exp_ext_state = { { .ex_lblk = 10, .ex_len = 1, .is_unwrit = 1 },
> +			     { .ex_lblk = 11, .ex_len = 1, .is_unwrit = 0 },
> +			     { .ex_lblk = 12, .ex_len = 1, .is_unwrit = 1 } },
> +	  .is_zeroout_test = 0 },
> +
> +	/* unwrit to writ splits via non-endio path */
> +	{ .desc = "split unwrit extent to 2 extents and convert 1st half writ (non endio)",
> +	  .type = TEST_CREATE_BLOCKS,
> +	  .is_unwrit_at_start = 1,
> +	  .split_flags = EXT4_GET_BLOCKS_CREATE,
> +	  .split_map = { .m_lblk = 10, .m_len = 1 },
> +	  .nr_exp_ext = 2,
> +	  .disable_zeroout = true,
> +	  .exp_ext_state = { { .ex_lblk = 10, .ex_len = 1, .is_unwrit = 0 },
> +			     { .ex_lblk = 11, .ex_len = 2, .is_unwrit = 1 } },
> +	  .is_zeroout_test = 0 },
> +	{ .desc = "split unwrit extent to 2 extents and convert 2nd half writ (non endio)",
> +	  .type = TEST_CREATE_BLOCKS,
> +	  .is_unwrit_at_start = 1,
> +	  .split_flags = EXT4_GET_BLOCKS_CREATE,
> +	  .split_map = { .m_lblk = 11, .m_len = 2 },
> +	  .nr_exp_ext = 2,
> +	  .disable_zeroout = true,
> +	  .exp_ext_state = { { .ex_lblk = 10, .ex_len = 1, .is_unwrit = 1 },
> +			     { .ex_lblk = 11, .ex_len = 2, .is_unwrit = 0 } },
> +	  .is_zeroout_test = 0 },
> +	{ .desc = "split unwrit extent to 3 extents and convert 2nd half to writ (non endio)",
> +	  .type = TEST_CREATE_BLOCKS,
> +	  .is_unwrit_at_start = 1,
> +	  .split_flags = EXT4_GET_BLOCKS_CREATE,
> +	  .split_map = { .m_lblk = 11, .m_len = 1 },
> +	  .nr_exp_ext = 3,
> +	  .disable_zeroout = true,
> +	  .exp_ext_state = { { .ex_lblk = 10, .ex_len = 1, .is_unwrit = 1 },
> +			     { .ex_lblk = 11, .ex_len = 1, .is_unwrit = 0 },
> +			     { .ex_lblk = 12, .ex_len = 1, .is_unwrit = 1 } },
> +	  .is_zeroout_test = 0 },
> +
> +	/*
> +	 * ***** zeroout tests *****
> +	 */
> +	/* unwrit to writ splits (endio)*/
> +	{ .desc = "split unwrit extent to 2 extents and convert 1st half writ (endio, zeroout)",
> +	  .type = TEST_CREATE_BLOCKS,
> +	  .is_unwrit_at_start = 1,
> +	  .split_flags = EXT4_GET_BLOCKS_CONVERT,
> +	  .split_map = { .m_lblk = 10, .m_len = 1 },
> +	  .nr_exp_ext = 1,
> +	  .exp_ext_state = { { .ex_lblk = 10, .ex_len = 3, .is_unwrit = 0 } },
> +	  .is_zeroout_test = 1,
> +	  .nr_exp_data_segs = 2,
> +	  /* 1 block of data followed by 2 blocks of zeroes */
> +	  .exp_data_state = { { .exp_char = 'X', .off_blk = 0, .len_blk = 1 },
> +			      { .exp_char = 0, .off_blk = 1, .len_blk = 2 } } },
> +	{ .desc = "split unwrit extent to 2 extents and convert 2nd half writ (endio, zeroout)",
> +	  .type = TEST_CREATE_BLOCKS,
> +	  .is_unwrit_at_start = 1,
> +	  .split_flags = EXT4_GET_BLOCKS_CONVERT,
> +	  .split_map = { .m_lblk = 11, .m_len = 2 },
> +	  .nr_exp_ext = 1,
> +	  .exp_ext_state = { { .ex_lblk = 10, .ex_len = 3, .is_unwrit = 0 } },
> +	  .is_zeroout_test = 1,
> +	  .nr_exp_data_segs = 2,
> +	  /* 1 block of zeroes followed by 2 blocks of data */
> +	  .exp_data_state = { { .exp_char = 0, .off_blk = 0, .len_blk = 1 },
> +			      { .exp_char = 'X', .off_blk = 1, .len_blk = 2 } } },
> +	{ .desc = "split unwrit extent to 3 extents and convert 2nd half writ (endio, zeroout)",
> +	  .type = TEST_CREATE_BLOCKS,
> +	  .is_unwrit_at_start = 1,
> +	  .split_flags = EXT4_GET_BLOCKS_CONVERT,
> +	  .split_map = { .m_lblk = 11, .m_len = 1 },
> +	  .nr_exp_ext = 1,
> +	  .exp_ext_state = { { .ex_lblk = 10, .ex_len = 3, .is_unwrit = 0 } },
> +	  .is_zeroout_test = 1,
> +	  .nr_exp_data_segs = 3,
> +	  /* [zeroes] [data] [zeroes] */
> +	  .exp_data_state = { { .exp_char = 0, .off_blk = 0, .len_blk = 1 },
> +			      { .exp_char = 'X', .off_blk = 1, .len_blk = 1 },
> +			      { .exp_char = 0, .off_blk = 2, .len_blk = 1 } } },
> +
> +	/* unwrit to writ splits (non-endio)*/
> +	{ .desc = "split unwrit extent to 2 extents and convert 1st half writ (non-endio, zeroout)",
> +	  .type = TEST_CREATE_BLOCKS,
> +	  .is_unwrit_at_start = 1,
> +	  .split_flags = EXT4_GET_BLOCKS_CREATE,
> +	  .split_map = { .m_lblk = 10, .m_len = 1 },
> +	  .nr_exp_ext = 1,
> +	  .exp_ext_state = { { .ex_lblk = 10, .ex_len = 3, .is_unwrit = 0 } },
> +	  .is_zeroout_test = 1,
> +	  .nr_exp_data_segs = 2,
> +	  /* 1 block of data followed by 2 blocks of zeroes */
> +	  .exp_data_state = { { .exp_char = 'X', .off_blk = 0, .len_blk = 1 },
> +			      { .exp_char = 0, .off_blk = 1, .len_blk = 2 } } },
> +	{ .desc = "split unwrit extent to 2 extents and convert 2nd half writ (non-endio, zeroout)",
> +	  .type = TEST_CREATE_BLOCKS,
> +	  .is_unwrit_at_start = 1,
> +	  .split_flags = EXT4_GET_BLOCKS_CREATE,
> +	  .split_map = { .m_lblk = 11, .m_len = 2 },
> +	  .nr_exp_ext = 1,
> +	  .exp_ext_state = { { .ex_lblk = 10, .ex_len = 3, .is_unwrit = 0 } },
> +	  .is_zeroout_test = 1,
> +	  .nr_exp_data_segs = 2,
> +	  /* 1 block of zeroes followed by 2 blocks of data */
> +	  .exp_data_state = { { .exp_char = 0, .off_blk = 0, .len_blk = 1 },
> +			      { .exp_char = 'X', .off_blk = 1, .len_blk = 2 } } },
> +	{ .desc = "split unwrit extent to 3 extents and convert 2nd half writ (non-endio, zeroout)",
> +	  .type = TEST_CREATE_BLOCKS,
> +	  .is_unwrit_at_start = 1,
> +	  .split_flags = EXT4_GET_BLOCKS_CREATE,
> +	  .split_map = { .m_lblk = 11, .m_len = 1 },
> +	  .nr_exp_ext = 1,
> +	  .exp_ext_state = { { .ex_lblk = 10, .ex_len = 3, .is_unwrit = 0 } },
> +	  .is_zeroout_test = 1,
> +	  .nr_exp_data_segs = 3,
> +	  /* [zeroes] [data] [zeroes] */
> +	  .exp_data_state = { { .exp_char = 0, .off_blk = 0, .len_blk = 1 },
> +			      { .exp_char = 'X', .off_blk = 1, .len_blk = 1 },
> +			      { .exp_char = 0, .off_blk = 2, .len_blk = 1 } } },
> +
> +};
> +
>   static void ext_get_desc(struct kunit *test, const void *p, char *desc)
>   
>   {
> @@ -493,6 +752,24 @@ static int test_split_convert_param_init(struct kunit *test)
>   	return 0;
>   }
>   
> +static int test_convert_initialized_param_init(struct kunit *test)
> +{
> +	size_t arr_size = ARRAY_SIZE(test_convert_initialized_params);
> +
> +	kunit_register_params_array(test, test_convert_initialized_params,
> +				    arr_size, ext_get_desc);
> +	return 0;
> +}
> +
> +static int test_handle_unwritten_init(struct kunit *test)
> +{
> +	size_t arr_size = ARRAY_SIZE(test_handle_unwritten_params);
> +
> +	kunit_register_params_array(test, test_handle_unwritten_params,
> +				    arr_size, ext_get_desc);
> +	return 0;
> +}
> +
>   /*
>    * Note that we use KUNIT_CASE_PARAM_WITH_INIT() instead of the more compact
>    * KUNIT_ARRAY_PARAM() because the later currently has a limitation causing the
> @@ -503,6 +780,10 @@ static int test_split_convert_param_init(struct kunit *test)
>   static struct kunit_case extents_test_cases[] = {
>   	KUNIT_CASE_PARAM_WITH_INIT(test_split_convert, kunit_array_gen_params,
>   				   test_split_convert_param_init, NULL),
> +	KUNIT_CASE_PARAM_WITH_INIT(test_split_convert, kunit_array_gen_params,
> +				   test_convert_initialized_param_init, NULL),
> +	KUNIT_CASE_PARAM_WITH_INIT(test_split_convert, kunit_array_gen_params,
> +				   test_handle_unwritten_init, NULL),
>   	{}
>   };
>   
> diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c
> index 6c1faf7c9f2a..095ccb7ba4ba 100644
> --- a/fs/ext4/extents_status.c
> +++ b/fs/ext4/extents_status.c
> @@ -916,6 +916,9 @@ void ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk,
>   	struct pending_reservation *pr = NULL;
>   	bool revise_pending = false;
>   
> +	KUNIT_STATIC_STUB_REDIRECT(ext4_es_insert_extent, inode, lblk, len,
> +				   pblk, status, delalloc_reserve_used);
> +
>   	if (EXT4_SB(inode->i_sb)->s_mount_state & EXT4_FC_REPLAY)
>   		return;
>   
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index c60813260f9a..8a6ad16e7417 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -542,8 +542,8 @@ static int ext4_map_query_blocks_next_in_leaf(handle_t *handle,
>   	return map->m_len;
>   }
>   
> -static int ext4_map_query_blocks(handle_t *handle, struct inode *inode,
> -				 struct ext4_map_blocks *map, int flags)
> +int ext4_map_query_blocks(handle_t *handle, struct inode *inode,
> +			  struct ext4_map_blocks *map, int flags)
>   {
>   	unsigned int status;
>   	int retval;
> @@ -589,8 +589,8 @@ static int ext4_map_query_blocks(handle_t *handle, struct inode *inode,
>   	return retval;
>   }
>   
> -static int ext4_map_create_blocks(handle_t *handle, struct inode *inode,
> -				  struct ext4_map_blocks *map, int flags)
> +int ext4_map_create_blocks(handle_t *handle, struct inode *inode,
> +			   struct ext4_map_blocks *map, int flags)
>   {
>   	unsigned int status;
>   	int err, retval = 0;


  parent reply	other threads:[~2026-01-17  8:49 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-14 14:57 [PATCH v2 0/8] ext4 extent split/convert refactor and kunit tests Ojaswin Mujoo
2026-01-14 14:57 ` [PATCH v2 1/8] ext4: kunit tests for extent splitting and conversion Ojaswin Mujoo
2026-01-15 10:20   ` Jan Kara
2026-01-16  5:36     ` Ojaswin Mujoo
2026-01-17  8:47   ` Zhang Yi
2026-01-14 14:57 ` [PATCH v2 2/8] ext4: kunit tests for higher level extent manipulation functions Ojaswin Mujoo
2026-01-15 10:35   ` Jan Kara
2026-01-17  8:48   ` Zhang Yi [this message]
2026-01-14 14:57 ` [PATCH v2 3/8] ext4: Add extent status cache support to kunit tests Ojaswin Mujoo
2026-01-15 10:38   ` Jan Kara
2026-01-17  8:58   ` Zhang Yi
2026-01-14 14:57 ` [PATCH v2 4/8] ext4: propagate flags to convert_initialized_extent() Ojaswin Mujoo
2026-01-15 10:59   ` Jan Kara
2026-01-16  5:35     ` Ojaswin Mujoo
2026-01-17  8:59   ` Zhang Yi
2026-01-14 14:57 ` [PATCH v2 5/8] ext4: propagate flags to ext4_convert_unwritten_extents_endio() Ojaswin Mujoo
2026-01-17  9:00   ` Zhang Yi
2026-01-14 14:57 ` [PATCH v2 6/8] ext4: Refactor zeroout path and handle all cases Ojaswin Mujoo
2026-01-15 12:01   ` Jan Kara
2026-01-16  5:35     ` Ojaswin Mujoo
2026-01-17  8:00   ` Zhang Yi
2026-01-19 11:47     ` Ojaswin Mujoo
2026-01-14 14:57 ` [PATCH v2 7/8] ext4: Refactor split and convert extents Ojaswin Mujoo
2026-01-17  9:00   ` Zhang Yi
2026-01-14 14:57 ` [PATCH v2 8/8] ext4: Allow zeroout when doing written to unwritten split Ojaswin Mujoo
2026-01-17  9:01   ` Zhang Yi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2da17870-9dab-414a-b74d-23c43cdbe58a@gmail.com \
    --to=yizhang089@gmail.com \
    --cc=jack@suse.cz \
    --cc=libaokun1@huawei.com \
    --cc=linux-ext4@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ojaswin@linux.ibm.com \
    --cc=ritesh.list@gmail.com \
    --cc=tytso@mit.edu \
    --cc=yi.zhang@huawei.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.