ext4: kunit tests for extent splitting and conversion

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.

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/22bb9d17cd88c1318a2edde48887ca7488cb8a13.1769149131.git.ojaswin@linux.ibm.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
Ojaswin Mujoo
2026-01-23 16:48:02 -05:00
committed by Theodore Ts'o
parent 3574c322b1
commit cb1e0c1d1f
4 changed files with 587 additions and 2 deletions
File diff suppressed because it is too large Load Diff
+21 -2
View File
@@ -32,6 +32,7 @@
#include "ext4_jbd2.h"
#include "ext4_extents.h"
#include "xattr.h"
#include <kunit/static_stub.h>
#include <trace/events/ext4.h>
@@ -197,6 +198,9 @@ static int __ext4_ext_dirty(const char *where, unsigned int line,
{
int err;
KUNIT_STATIC_STUB_REDIRECT(__ext4_ext_dirty, where, line, handle, inode,
path);
WARN_ON(!rwsem_is_locked(&EXT4_I(inode)->i_data_sem));
if (path->p_bh) {
ext4_extent_block_csum_set(inode, ext_block_hdr(path->p_bh));
@@ -535,6 +539,8 @@ static void ext4_cache_extents(struct inode *inode,
ext4_lblk_t prev = 0;
int i;
KUNIT_STATIC_STUB_REDIRECT(ext4_cache_extents, inode, eh);
for (i = le16_to_cpu(eh->eh_entries); i > 0; i--, ex++) {
unsigned int status = EXTENT_STATUS_WRITTEN;
ext4_lblk_t lblk = le32_to_cpu(ex->ee_block);
@@ -898,6 +904,8 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block,
int ret;
gfp_t gfp_flags = GFP_NOFS;
KUNIT_STATIC_STUB_REDIRECT(ext4_find_extent, inode, block, path, flags);
if (flags & EXT4_EX_NOFAIL)
gfp_flags |= __GFP_NOFAIL;
@@ -1990,6 +1998,9 @@ ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
ext4_lblk_t next;
int mb_flags = 0, unwritten;
KUNIT_STATIC_STUB_REDIRECT(ext4_ext_insert_extent, handle, inode, path,
newext, gb_flags);
if (gb_flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE)
mb_flags |= EXT4_MB_DELALLOC_RESERVED;
if (unlikely(ext4_ext_get_actual_len(newext) == 0)) {
@@ -3134,8 +3145,10 @@ static void ext4_zeroout_es(struct inode *inode, struct ext4_extent *ex)
ext4_fsblk_t ee_pblock;
unsigned int ee_len;
ee_block = le32_to_cpu(ex->ee_block);
ee_len = ext4_ext_get_actual_len(ex);
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);
if (ee_len == 0)
@@ -3151,6 +3164,8 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
ext4_fsblk_t ee_pblock;
unsigned int ee_len;
KUNIT_STATIC_STUB_REDIRECT(ext4_ext_zeroout, inode, ex);
ee_len = ext4_ext_get_actual_len(ex);
ee_pblock = ext4_ext_pblock(ex);
return ext4_issue_zeroout(inode, le32_to_cpu(ex->ee_block), ee_pblock,
@@ -6177,3 +6192,7 @@ out:
ext4_free_ext_path(path);
return 0;
}
#ifdef CONFIG_EXT4_KUNIT_TESTS
#include "extents-test.c"
#endif
+3
View File
@@ -16,6 +16,7 @@
#include "ext4.h"
#include <trace/events/ext4.h>
#include <kunit/static_stub.h>
/*
* According to previous discussion in Ext4 Developer Workshop, we
@@ -1627,6 +1628,8 @@ 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;
+4
View File
@@ -48,6 +48,8 @@
#include "acl.h"
#include "truncate.h"
#include <kunit/static_stub.h>
#include <trace/events/ext4.h>
static void ext4_journalled_zero_new_buffers(handle_t *handle,
@@ -400,6 +402,8 @@ int ext4_issue_zeroout(struct inode *inode, ext4_lblk_t lblk, ext4_fsblk_t pblk,
{
int ret;
KUNIT_STATIC_STUB_REDIRECT(ext4_issue_zeroout, inode, lblk, pblk, len);
if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode))
return fscrypt_zeroout_range(inode, lblk, pblk, len);