]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ext4: add extent status cache support to kunit tests
authorOjaswin Mujoo <ojaswin@linux.ibm.com>
Fri, 23 Jan 2026 06:25:34 +0000 (11:55 +0530)
committerTheodore Ts'o <tytso@mit.edu>
Fri, 23 Jan 2026 21:49:43 +0000 (16:49 -0500)
Add support in Kunit tests to ensure that the extent status cache is
also in sync after the extent split and conversion operations.

Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Link: https://patch.msgid.link/5f9d2668feeb89a3f3e9d03dadab8c10cbea3741.1769149131.git.ojaswin@linux.ibm.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/extents-test.c
fs/ext4/extents.c
fs/ext4/extents_status.c

index 4030fa5faca55816b790afd0b89d1b6fd1fcf362..3176bf7686b5fe07f732be3b2f360c51bc584aa9 100644 (file)
@@ -149,12 +149,6 @@ static void extents_kunit_exit(struct kunit *test)
        kfree(k_ctx.k_data);
 }
 
-static void ext4_cache_extents_stub(struct inode *inode,
-                                   struct ext4_extent_header *eh)
-{
-       return;
-}
-
 static int __ext4_ext_dirty_stub(const char *where, unsigned int line,
                                 handle_t *handle, struct inode *inode,
                                 struct ext4_ext_path *path)
@@ -170,24 +164,6 @@ ext4_ext_insert_extent_stub(handle_t *handle, struct inode *inode,
        return ERR_PTR(-ENOSPC);
 }
 
-static void ext4_es_remove_extent_stub(struct inode *inode, ext4_lblk_t lblk,
-                                      ext4_lblk_t len)
-{
-       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;
-}
-
 /*
  * We will zeroout the equivalent range in the data area
  */
@@ -244,13 +220,7 @@ static int extents_kunit_init(struct kunit *test)
        struct ext4_sb_info *sbi = NULL;
        struct kunit_ext_test_param *param =
                (struct kunit_ext_test_param *)(test->param_value);
-
-       /* setup the mock inode */
-       k_ctx.k_ei = kzalloc(sizeof(struct ext4_inode_info), GFP_KERNEL);
-       if (k_ctx.k_ei == NULL)
-               return -ENOMEM;
-       ei = k_ctx.k_ei;
-       inode = &ei->vfs_inode;
+       int err;
 
        sb = sget(&ext_fs_type, NULL, ext_set, 0, NULL);
        if (IS_ERR(sb))
@@ -269,6 +239,24 @@ static int extents_kunit_init(struct kunit *test)
        if (!param || !param->disable_zeroout)
                sbi->s_extent_max_zeroout_kb = 32;
 
+       /* setup the mock inode */
+       k_ctx.k_ei = kzalloc(sizeof(struct ext4_inode_info), GFP_KERNEL);
+       if (k_ctx.k_ei == NULL)
+               return -ENOMEM;
+       ei = k_ctx.k_ei;
+       inode = &ei->vfs_inode;
+
+       err = ext4_es_register_shrinker(sbi);
+       if (err)
+               return err;
+
+       ext4_es_init_tree(&ei->i_es_tree);
+       rwlock_init(&ei->i_es_lock);
+       INIT_LIST_HEAD(&ei->i_es_list);
+       ei->i_es_all_nr = 0;
+       ei->i_es_shk_nr = 0;
+       ei->i_es_shrink_lblk = 0;
+
        ei->i_disksize = (EXT_DATA_LBLK + EXT_DATA_LEN + 10)
                         << sb->s_blocksize_bits;
        ei->i_flags = 0;
@@ -307,16 +295,15 @@ static int extents_kunit_init(struct kunit *test)
        if (!param || param->is_unwrit_at_start)
                ext4_ext_mark_unwritten(EXT_FIRST_EXTENT(eh));
 
+       ext4_es_insert_extent(inode, EXT_DATA_LBLK, EXT_DATA_LEN, EXT_DATA_PBLK,
+                             ext4_ext_is_unwritten(EXT_FIRST_EXTENT(eh)) ?
+                                     EXTENT_STATUS_UNWRITTEN :
+                                     EXTENT_STATUS_WRITTEN,
+                             0);
+
        /* Add stubs */
-       kunit_activate_static_stub(test, ext4_cache_extents,
-                                  ext4_cache_extents_stub);
        kunit_activate_static_stub(test, __ext4_ext_dirty,
                                   __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,
                                   ext4_issue_zeroout_stub);
@@ -381,7 +368,7 @@ static void test_split_convert(struct kunit *test)
                kunit_activate_static_stub(test, ext4_ext_insert_extent,
                                           ext4_ext_insert_extent_stub);
 
-       path = ext4_find_extent(inode, EXT_DATA_LBLK, NULL, 0);
+       path = ext4_find_extent(inode, EXT_DATA_LBLK, NULL, EXT4_EX_NOCACHE);
        ex = path->p_ext;
        KUNIT_EXPECT_EQ(test, EXT_DATA_LBLK, le32_to_cpu(ex->ee_block));
        KUNIT_EXPECT_EQ(test, EXT_DATA_LEN, ext4_ext_get_actual_len(ex));
@@ -407,11 +394,14 @@ static void test_split_convert(struct kunit *test)
                KUNIT_FAIL(test, "param->type %d not support.", param->type);
        }
 
-       path = ext4_find_extent(inode, EXT_DATA_LBLK, NULL, 0);
+       path = ext4_find_extent(inode, EXT_DATA_LBLK, NULL, EXT4_EX_NOCACHE);
        ex = path->p_ext;
 
        for (int i = 0; i < param->nr_exp_ext; i++) {
                struct kunit_ext_state exp_ext = param->exp_ext_state[i];
+               bool es_check_needed = param->type != TEST_SPLIT_CONVERT;
+               struct extent_status es;
+               int contains_ex, ex_end, es_end, es_pblk;
 
                KUNIT_EXPECT_EQ(test, exp_ext.ex_lblk,
                                le32_to_cpu(ex->ee_block));
@@ -419,6 +409,33 @@ static void test_split_convert(struct kunit *test)
                                ext4_ext_get_actual_len(ex));
                KUNIT_EXPECT_EQ(test, exp_ext.is_unwrit,
                                ext4_ext_is_unwritten(ex));
+               /*
+                * Confirm extent cache is in sync. Note that es cache can be
+                * merged even when on-disk extents are not so take that into
+                * account.
+                *
+                * Also, ext4_split_convert_extents() forces EXT4_EX_NOCACHE hence
+                * es status are ignored for that case.
+                */
+               if (es_check_needed) {
+                       ext4_es_lookup_extent(inode, le32_to_cpu(ex->ee_block),
+                                             NULL, &es, NULL);
+
+                       ex_end = exp_ext.ex_lblk + exp_ext.ex_len;
+                       es_end = es.es_lblk + es.es_len;
+                       contains_ex = es.es_lblk <= exp_ext.ex_lblk &&
+                                     es_end >= ex_end;
+                       es_pblk = ext4_es_pblock(&es) +
+                                 (exp_ext.ex_lblk - es.es_lblk);
+
+                       KUNIT_EXPECT_EQ(test, contains_ex, 1);
+                       KUNIT_EXPECT_EQ(test, ext4_ext_pblock(ex), es_pblk);
+                       KUNIT_EXPECT_EQ(test, 1,
+                                       (exp_ext.is_unwrit &&
+                                        ext4_es_is_unwritten(&es)) ||
+                                               (!exp_ext.is_unwrit &&
+                                                ext4_es_is_written(&es)));
+               }
 
                /* Only printed on failure */
                kunit_log(KERN_INFO, test,
@@ -429,6 +446,12 @@ static void test_split_convert(struct kunit *test)
                          le32_to_cpu(ex->ee_block),
                          ext4_ext_get_actual_len(ex),
                          ext4_ext_is_unwritten(ex));
+               if (es_check_needed)
+                       kunit_log(
+                               KERN_INFO, test,
+                               "# [extent %d] es: lblk:%d len:%d pblk:%lld type:0x%x\n",
+                               i, es.es_lblk, es.es_len, ext4_es_pblock(&es),
+                               ext4_es_type(&es));
                kunit_log(KERN_INFO, test, "------------------\n");
 
                ex = ex + 1;
index 08aa36854c116de85a2dd130f03bc08ce7b3e03e..16326d7f09b96da9ffea51bc81721740adba12be 100644 (file)
@@ -3145,8 +3145,6 @@ static void ext4_zeroout_es(struct inode *inode, struct ext4_extent *ex)
        ext4_fsblk_t ee_pblock;
        unsigned int ee_len;
 
-       KUNIT_STATIC_STUB_REDIRECT(ext4_zeroout_es, inode, ex);
-
        ee_block = le32_to_cpu(ex->ee_block);
        ee_len = ext4_ext_get_actual_len(ex);
        ee_pblock = ext4_ext_pblock(ex);
index 095ccb7ba4bac6dbcb71f871f6f481a5b828f6d1..a1538bac51c61d81881be2e3fd67113f24c16df1 100644 (file)
@@ -916,9 +916,6 @@ 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;
 
@@ -1631,8 +1628,6 @@ void ext4_es_remove_extent(struct inode *inode, ext4_lblk_t lblk,
        int reserved = 0;
        struct extent_status *es = NULL;
 
-       KUNIT_STATIC_STUB_REDIRECT(ext4_es_remove_extent, inode, lblk, len);
-
        if (EXT4_SB(inode->i_sb)->s_mount_state & EXT4_FC_REPLAY)
                return;