[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <735xahhes7x62f2yuhpfgoojerfclo2kdwf5d7h2lgxtuq57ew@jt4ijbxfpocq>
Date: Thu, 15 Jan 2026 11:20:25 +0100
From: Jan Kara <jack@...e.cz>
To: Ojaswin Mujoo <ojaswin@...ux.ibm.com>
Cc: linux-ext4@...r.kernel.org, Theodore Ts'o <tytso@....edu>,
Ritesh Harjani <ritesh.list@...il.com>, Zhang Yi <yi.zhang@...wei.com>, Jan Kara <jack@...e.cz>,
libaokun1@...wei.com, linux-kernel@...r.kernel.org
Subject: Re: [PATCH v2 1/8] ext4: kunit tests for extent splitting and
conversion
On Wed 14-01-26 20:27:45, Ojaswin Mujoo wrote:
> Add multiple KUnit tests to test various permutations of extent
> splitting and conversion.
>
> We test the following cases:
>
> 1. Split of unwritten extent into 2 parts and convert 1 part to written
> 2. Split of unwritten extent into 3 parts and convert 1 part to written
> 3. Split of written extent into 2 parts and convert 1 part to unwritten
> 4. Split of written extent into 3 parts and convert 1 part to unwritten
> 5. Zeroout fallback for all the above cases except 3-4 because zeroout
> is not supported for written to unwritten splits
>
> The main function we test here is ext4_split_convert_extents().
> Currently some of the tests are failing due to issues in implementation.
> All failures are mitigated at other layers in ext4 [1] but still point
> out the mismatch in expectation of what the caller wants vs what the
> function does.
>
> The aim is to eventually fix all the failures we see here. More detailed
> implementation notes can be found in the topmost commit in the test file.
>
> [1] for example, EXT4_GET_BLOCKS_CONVERT doesn't
> really convert the split extent to written, but rather the callers end up
> doing the conversion.
>
> Signed-off-by: Ojaswin Mujoo <ojaswin@...ux.ibm.com>
Overall this looks good to me so feel free to add:
Reviewed-by: Jan Kara <jack@...e.cz>
Couple nits below:
> +static void test_split_convert(struct kunit *test)
> +{
> + struct ext4_ext_path *path;
> + struct inode *inode = &k_ctx.k_ei->vfs_inode;
> + struct ext4_extent *ex;
> + struct ext4_map_blocks map;
> + const struct kunit_ext_test_param *param =
> + (const struct kunit_ext_test_param *)(test->param_value);
> + int blkbits = inode->i_sb->s_blocksize_bits;
> +
> + if (param->is_zeroout_test)
> + /*
> + * Force zeroout by making ext4_ext_insert_extent return ENOSPC
> + */
> + kunit_activate_static_stub(test, ext4_ext_insert_extent,
> + ext4_ext_insert_extent_stub);
> +
> + path = ext4_find_extent(inode, EX_DATA_LBLK, NULL, 0);
> + ex = path->p_ext;
> + KUNIT_EXPECT_EQ(test, 10, ex->ee_block);
> + KUNIT_EXPECT_EQ(test, 3, ext4_ext_get_actual_len(ex));
Shouldn't we use EX_DATA_LBLK and other constants instead for numbers?
...
> +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",
> + .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",
> + .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",
> + .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 },
> +
> + /* writ to unwrit splits */
> + { .desc = "split writ extent to 2 extents and convert 1st half unwrit",
> + .is_unwrit_at_start = 0,
> + .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
> + .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",
> + .is_unwrit_at_start = 0,
> + .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
> + .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",
> + .is_unwrit_at_start = 0,
> + .split_flags = EXT4_GET_BLOCKS_CONVERT_UNWRITTEN,
> + .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 },
> +
> + /*
> + * ***** zeroout tests *****
> + */
> + /* unwrit to writ splits */
> + { .desc = "split unwrit extent to 2 extents and convert 1st half writ (zeroout)",
> + .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 (zeroout)",
> + .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 (zeroout)",
> + .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 } } },
> +
> +};
Also in these definitions of split_map and exp_ext_state I think it would be
cleaner to use EX_DATA_LBLK and EX_DATA_LEN...
Honza
--
Jan Kara <jack@...e.com>
SUSE Labs, CR
Powered by blists - more mailing lists