Commit 519b76ac authored by Ye Bin's avatar Ye Bin Committed by Theodore Ts'o
Browse files

ext4: fix mballoc-test.c is not compiled when EXT4_KUNIT_TESTS=M



Now, only EXT4_KUNIT_TESTS=Y testcase will be compiled in 'mballoc.c'.
To solve this issue, the ext4 test code needs to be decoupled. The ext4
test module is compiled into a separate module.

Reported-by: default avatarChenXiaoSong <chenxiaosong@kylinos.cn>
Closes: https://patchwork.kernel.org/project/cifs-client/patch/20260118091313.1988168-2-chenxiaosong.chenxiaosong@linux.dev/


Fixes: 7c9fa399 ("ext4: add first unit test for ext4_mb_new_blocks_simple in mballoc")
Signed-off-by: default avatarYe Bin <yebin10@huawei.com>
Reviewed-by: default avatarJan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260314075258.1317579-3-yebin@huaweicloud.com


Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent 49504a51
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@ ext4-y := balloc.o bitmap.o block_validity.o dir.o ext4_jbd2.o extents.o \

ext4-$(CONFIG_EXT4_FS_POSIX_ACL)	+= acl.o
ext4-$(CONFIG_EXT4_FS_SECURITY)		+= xattr_security.o
ext4-inode-test-objs			+= inode-test.o
obj-$(CONFIG_EXT4_KUNIT_TESTS)		+= ext4-inode-test.o
ext4-test-objs				+= inode-test.o mballoc-test.o
obj-$(CONFIG_EXT4_KUNIT_TESTS)		+= ext4-test.o
ext4-$(CONFIG_FS_VERITY)		+= verity.o
ext4-$(CONFIG_FS_ENCRYPTION)		+= crypto.o
+41 −40
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include <linux/random.h>

#include "ext4.h"
#include "mballoc.h"

struct mbt_grp_ctx {
	struct buffer_head bitmap_bh;
@@ -336,7 +337,7 @@ ext4_mb_mark_context_stub(handle_t *handle, struct super_block *sb, bool state,
	if (state)
		mb_set_bits(bitmap_bh->b_data, blkoff, len);
	else
		mb_clear_bits(bitmap_bh->b_data, blkoff, len);
		mb_clear_bits_test(bitmap_bh->b_data, blkoff, len);

	return 0;
}
@@ -413,14 +414,14 @@ static void test_new_blocks_simple(struct kunit *test)

	/* get block at goal */
	ar.goal = ext4_group_first_block_no(sb, goal_group);
	found = ext4_mb_new_blocks_simple(&ar, &err);
	found = ext4_mb_new_blocks_simple_test(&ar, &err);
	KUNIT_ASSERT_EQ_MSG(test, ar.goal, found,
		"failed to alloc block at goal, expected %llu found %llu",
		ar.goal, found);

	/* get block after goal in goal group */
	ar.goal = ext4_group_first_block_no(sb, goal_group);
	found = ext4_mb_new_blocks_simple(&ar, &err);
	found = ext4_mb_new_blocks_simple_test(&ar, &err);
	KUNIT_ASSERT_EQ_MSG(test, ar.goal + EXT4_C2B(sbi, 1), found,
		"failed to alloc block after goal in goal group, expected %llu found %llu",
		ar.goal + 1, found);
@@ -428,7 +429,7 @@ static void test_new_blocks_simple(struct kunit *test)
	/* get block after goal group */
	mbt_ctx_mark_used(sb, goal_group, 0, EXT4_CLUSTERS_PER_GROUP(sb));
	ar.goal = ext4_group_first_block_no(sb, goal_group);
	found = ext4_mb_new_blocks_simple(&ar, &err);
	found = ext4_mb_new_blocks_simple_test(&ar, &err);
	KUNIT_ASSERT_EQ_MSG(test,
		ext4_group_first_block_no(sb, goal_group + 1), found,
		"failed to alloc block after goal group, expected %llu found %llu",
@@ -438,7 +439,7 @@ static void test_new_blocks_simple(struct kunit *test)
	for (i = goal_group; i < ext4_get_groups_count(sb); i++)
		mbt_ctx_mark_used(sb, i, 0, EXT4_CLUSTERS_PER_GROUP(sb));
	ar.goal = ext4_group_first_block_no(sb, goal_group);
	found = ext4_mb_new_blocks_simple(&ar, &err);
	found = ext4_mb_new_blocks_simple_test(&ar, &err);
	KUNIT_ASSERT_EQ_MSG(test,
		ext4_group_first_block_no(sb, 0) + EXT4_C2B(sbi, 1), found,
		"failed to alloc block before goal group, expected %llu found %llu",
@@ -448,7 +449,7 @@ static void test_new_blocks_simple(struct kunit *test)
	for (i = 0; i < ext4_get_groups_count(sb); i++)
		mbt_ctx_mark_used(sb, i, 0, EXT4_CLUSTERS_PER_GROUP(sb));
	ar.goal = ext4_group_first_block_no(sb, goal_group);
	found = ext4_mb_new_blocks_simple(&ar, &err);
	found = ext4_mb_new_blocks_simple_test(&ar, &err);
	KUNIT_ASSERT_NE_MSG(test, err, 0,
		"unexpectedly get block when no block is available");
}
@@ -492,16 +493,16 @@ validate_free_blocks_simple(struct kunit *test, struct super_block *sb,
			continue;

		bitmap = mbt_ctx_bitmap(sb, i);
		bit = mb_find_next_zero_bit(bitmap, max, 0);
		bit = mb_find_next_zero_bit_test(bitmap, max, 0);
		KUNIT_ASSERT_EQ_MSG(test, bit, max,
				    "free block on unexpected group %d", i);
	}

	bitmap = mbt_ctx_bitmap(sb, goal_group);
	bit = mb_find_next_zero_bit(bitmap, max, 0);
	bit = mb_find_next_zero_bit_test(bitmap, max, 0);
	KUNIT_ASSERT_EQ(test, bit, start);

	bit = mb_find_next_bit(bitmap, max, bit + 1);
	bit = mb_find_next_bit_test(bitmap, max, bit + 1);
	KUNIT_ASSERT_EQ(test, bit, start + len);
}

@@ -524,7 +525,7 @@ test_free_blocks_simple_range(struct kunit *test, ext4_group_t goal_group,

	block = ext4_group_first_block_no(sb, goal_group) +
		EXT4_C2B(sbi, start);
	ext4_free_blocks_simple(inode, block, len);
	ext4_free_blocks_simple_test(inode, block, len);
	validate_free_blocks_simple(test, sb, goal_group, start, len);
	mbt_ctx_mark_used(sb, goal_group, 0, EXT4_CLUSTERS_PER_GROUP(sb));
}
@@ -566,15 +567,15 @@ test_mark_diskspace_used_range(struct kunit *test,

	bitmap = mbt_ctx_bitmap(sb, TEST_GOAL_GROUP);
	memset(bitmap, 0, sb->s_blocksize);
	ret = ext4_mb_mark_diskspace_used(ac, NULL);
	ret = ext4_mb_mark_diskspace_used_test(ac, NULL);
	KUNIT_ASSERT_EQ(test, ret, 0);

	max = EXT4_CLUSTERS_PER_GROUP(sb);
	i = mb_find_next_bit(bitmap, max, 0);
	i = mb_find_next_bit_test(bitmap, max, 0);
	KUNIT_ASSERT_EQ(test, i, start);
	i = mb_find_next_zero_bit(bitmap, max, i + 1);
	i = mb_find_next_zero_bit_test(bitmap, max, i + 1);
	KUNIT_ASSERT_EQ(test, i, start + len);
	i = mb_find_next_bit(bitmap, max, i + 1);
	i = mb_find_next_bit_test(bitmap, max, i + 1);
	KUNIT_ASSERT_EQ(test, max, i);
}

@@ -617,54 +618,54 @@ static void mbt_generate_buddy(struct super_block *sb, void *buddy,
	max = EXT4_CLUSTERS_PER_GROUP(sb);
	bb_h = buddy + sbi->s_mb_offsets[1];

	off = mb_find_next_zero_bit(bb, max, 0);
	off = mb_find_next_zero_bit_test(bb, max, 0);
	grp->bb_first_free = off;
	while (off < max) {
		grp->bb_counters[0]++;
		grp->bb_free++;

		if (!(off & 1) && !mb_test_bit(off + 1, bb)) {
		if (!(off & 1) && !mb_test_bit_test(off + 1, bb)) {
			grp->bb_free++;
			grp->bb_counters[0]--;
			mb_clear_bit(off >> 1, bb_h);
			mb_clear_bit_test(off >> 1, bb_h);
			grp->bb_counters[1]++;
			grp->bb_largest_free_order = 1;
			off++;
		}

		off = mb_find_next_zero_bit(bb, max, off + 1);
		off = mb_find_next_zero_bit_test(bb, max, off + 1);
	}

	for (order = 1; order < MB_NUM_ORDERS(sb) - 1; order++) {
		bb = buddy + sbi->s_mb_offsets[order];
		bb_h = buddy + sbi->s_mb_offsets[order + 1];
		max = max >> 1;
		off = mb_find_next_zero_bit(bb, max, 0);
		off = mb_find_next_zero_bit_test(bb, max, 0);

		while (off < max) {
			if (!(off & 1) && !mb_test_bit(off + 1, bb)) {
			if (!(off & 1) && !mb_test_bit_test(off + 1, bb)) {
				mb_set_bits(bb, off, 2);
				grp->bb_counters[order] -= 2;
				mb_clear_bit(off >> 1, bb_h);
				mb_clear_bit_test(off >> 1, bb_h);
				grp->bb_counters[order + 1]++;
				grp->bb_largest_free_order = order + 1;
				off++;
			}

			off = mb_find_next_zero_bit(bb, max, off + 1);
			off = mb_find_next_zero_bit_test(bb, max, off + 1);
		}
	}

	max = EXT4_CLUSTERS_PER_GROUP(sb);
	off = mb_find_next_zero_bit(bitmap, max, 0);
	off = mb_find_next_zero_bit_test(bitmap, max, 0);
	while (off < max) {
		grp->bb_fragments++;

		off = mb_find_next_bit(bitmap, max, off + 1);
		off = mb_find_next_bit_test(bitmap, max, off + 1);
		if (off + 1 >= max)
			break;

		off = mb_find_next_zero_bit(bitmap, max, off + 1);
		off = mb_find_next_zero_bit_test(bitmap, max, off + 1);
	}
}

@@ -706,7 +707,7 @@ do_test_generate_buddy(struct kunit *test, struct super_block *sb, void *bitmap,
	/* needed by validation in ext4_mb_generate_buddy */
	ext4_grp->bb_free = mbt_grp->bb_free;
	memset(ext4_buddy, 0xff, sb->s_blocksize);
	ext4_mb_generate_buddy(sb, ext4_buddy, bitmap, TEST_GOAL_GROUP,
	ext4_mb_generate_buddy_test(sb, ext4_buddy, bitmap, TEST_GOAL_GROUP,
			       ext4_grp);

	KUNIT_ASSERT_EQ(test, memcmp(mbt_buddy, ext4_buddy, sb->s_blocksize),
@@ -760,7 +761,7 @@ test_mb_mark_used_range(struct kunit *test, struct ext4_buddy *e4b,
	ex.fe_group = TEST_GOAL_GROUP;

	ext4_lock_group(sb, TEST_GOAL_GROUP);
	mb_mark_used(e4b, &ex);
	mb_mark_used_test(e4b, &ex);
	ext4_unlock_group(sb, TEST_GOAL_GROUP);

	mb_set_bits(bitmap, start, len);
@@ -769,7 +770,7 @@ test_mb_mark_used_range(struct kunit *test, struct ext4_buddy *e4b,
	memset(buddy, 0xff, sb->s_blocksize);
	for (i = 0; i < MB_NUM_ORDERS(sb); i++)
		grp->bb_counters[i] = 0;
	ext4_mb_generate_buddy(sb, buddy, bitmap, 0, grp);
	ext4_mb_generate_buddy_test(sb, buddy, bitmap, 0, grp);

	KUNIT_ASSERT_EQ(test, memcmp(buddy, e4b->bd_buddy, sb->s_blocksize),
			0);
@@ -798,7 +799,7 @@ static void test_mb_mark_used(struct kunit *test)
				bb_counters[MB_NUM_ORDERS(sb)]), GFP_KERNEL);
	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, grp);

	ret = ext4_mb_load_buddy(sb, TEST_GOAL_GROUP, &e4b);
	ret = ext4_mb_load_buddy_test(sb, TEST_GOAL_GROUP, &e4b);
	KUNIT_ASSERT_EQ(test, ret, 0);

	grp->bb_free = EXT4_CLUSTERS_PER_GROUP(sb);
@@ -809,7 +810,7 @@ static void test_mb_mark_used(struct kunit *test)
		test_mb_mark_used_range(test, &e4b, ranges[i].start,
					ranges[i].len, bitmap, buddy, grp);

	ext4_mb_unload_buddy(&e4b);
	ext4_mb_unload_buddy_test(&e4b);
}

static void
@@ -825,16 +826,16 @@ test_mb_free_blocks_range(struct kunit *test, struct ext4_buddy *e4b,
		return;

	ext4_lock_group(sb, e4b->bd_group);
	mb_free_blocks(NULL, e4b, start, len);
	mb_free_blocks_test(NULL, e4b, start, len);
	ext4_unlock_group(sb, e4b->bd_group);

	mb_clear_bits(bitmap, start, len);
	mb_clear_bits_test(bitmap, start, len);
	/* bypass bb_free validatoin in ext4_mb_generate_buddy */
	grp->bb_free += len;
	memset(buddy, 0xff, sb->s_blocksize);
	for (i = 0; i < MB_NUM_ORDERS(sb); i++)
		grp->bb_counters[i] = 0;
	ext4_mb_generate_buddy(sb, buddy, bitmap, 0, grp);
	ext4_mb_generate_buddy_test(sb, buddy, bitmap, 0, grp);

	KUNIT_ASSERT_EQ(test, memcmp(buddy, e4b->bd_buddy, sb->s_blocksize),
			0);
@@ -865,7 +866,7 @@ static void test_mb_free_blocks(struct kunit *test)
				bb_counters[MB_NUM_ORDERS(sb)]), GFP_KERNEL);
	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, grp);

	ret = ext4_mb_load_buddy(sb, TEST_GOAL_GROUP, &e4b);
	ret = ext4_mb_load_buddy_test(sb, TEST_GOAL_GROUP, &e4b);
	KUNIT_ASSERT_EQ(test, ret, 0);

	ex.fe_start = 0;
@@ -873,7 +874,7 @@ static void test_mb_free_blocks(struct kunit *test)
	ex.fe_group = TEST_GOAL_GROUP;

	ext4_lock_group(sb, TEST_GOAL_GROUP);
	mb_mark_used(&e4b, &ex);
	mb_mark_used_test(&e4b, &ex);
	ext4_unlock_group(sb, TEST_GOAL_GROUP);

	grp->bb_free = 0;
@@ -886,7 +887,7 @@ static void test_mb_free_blocks(struct kunit *test)
		test_mb_free_blocks_range(test, &e4b, ranges[i].start,
					  ranges[i].len, bitmap, buddy, grp);

	ext4_mb_unload_buddy(&e4b);
	ext4_mb_unload_buddy_test(&e4b);
}

#define COUNT_FOR_ESTIMATE 100000
@@ -904,7 +905,7 @@ static void test_mb_mark_used_cost(struct kunit *test)
	if (sb->s_blocksize > PAGE_SIZE)
		kunit_skip(test, "blocksize exceeds pagesize");

	ret = ext4_mb_load_buddy(sb, TEST_GOAL_GROUP, &e4b);
	ret = ext4_mb_load_buddy_test(sb, TEST_GOAL_GROUP, &e4b);
	KUNIT_ASSERT_EQ(test, ret, 0);

	ex.fe_group = TEST_GOAL_GROUP;
@@ -918,7 +919,7 @@ static void test_mb_mark_used_cost(struct kunit *test)
			ex.fe_start = ranges[i].start;
			ex.fe_len = ranges[i].len;
			ext4_lock_group(sb, TEST_GOAL_GROUP);
			mb_mark_used(&e4b, &ex);
			mb_mark_used_test(&e4b, &ex);
			ext4_unlock_group(sb, TEST_GOAL_GROUP);
		}
		end = jiffies;
@@ -929,14 +930,14 @@ static void test_mb_mark_used_cost(struct kunit *test)
				continue;

			ext4_lock_group(sb, TEST_GOAL_GROUP);
			mb_free_blocks(NULL, &e4b, ranges[i].start,
			mb_free_blocks_test(NULL, &e4b, ranges[i].start,
				       ranges[i].len);
			ext4_unlock_group(sb, TEST_GOAL_GROUP);
		}
	}

	kunit_info(test, "costed jiffies %lu\n", all);
	ext4_mb_unload_buddy(&e4b);
	ext4_mb_unload_buddy_test(&e4b);
}

static const struct mbt_ext4_block_layout mbt_test_layouts[] = {
+99 −3
Original line number Diff line number Diff line
@@ -4088,7 +4088,7 @@ void ext4_exit_mballoc(void)

#define EXT4_MB_BITMAP_MARKED_CHECK 0x0001
#define EXT4_MB_SYNC_UPDATE 0x0002
static int
int
ext4_mb_mark_context(handle_t *handle, struct super_block *sb, bool state,
		     ext4_group_t group, ext4_grpblk_t blkoff,
		     ext4_grpblk_t len, int flags, ext4_grpblk_t *ret_changed)
@@ -7192,6 +7192,102 @@ ext4_mballoc_query_range(
	return error;
}

#ifdef CONFIG_EXT4_KUNIT_TESTS
#include "mballoc-test.c"
#if IS_ENABLED(CONFIG_EXT4_KUNIT_TESTS)
void mb_clear_bits_test(void *bm, int cur, int len)
{
	 mb_clear_bits(bm, cur, len);
}
EXPORT_SYMBOL_FOR_EXT4_TEST(mb_clear_bits_test);

ext4_fsblk_t
ext4_mb_new_blocks_simple_test(struct ext4_allocation_request *ar,
			       int *errp)
{
	return ext4_mb_new_blocks_simple(ar, errp);
}
EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_new_blocks_simple_test);

int mb_find_next_zero_bit_test(void *addr, int max, int start)
{
	return mb_find_next_zero_bit(addr, max, start);
}
EXPORT_SYMBOL_FOR_EXT4_TEST(mb_find_next_zero_bit_test);

int mb_find_next_bit_test(void *addr, int max, int start)
{
	return mb_find_next_bit(addr, max, start);
}
EXPORT_SYMBOL_FOR_EXT4_TEST(mb_find_next_bit_test);

void mb_clear_bit_test(int bit, void *addr)
{
	mb_clear_bit(bit, addr);
}
EXPORT_SYMBOL_FOR_EXT4_TEST(mb_clear_bit_test);

int mb_test_bit_test(int bit, void *addr)
{
	return mb_test_bit(bit, addr);
}
EXPORT_SYMBOL_FOR_EXT4_TEST(mb_test_bit_test);

int ext4_mb_mark_diskspace_used_test(struct ext4_allocation_context *ac,
				     handle_t *handle)
{
	return ext4_mb_mark_diskspace_used(ac, handle);
}
EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_mark_diskspace_used_test);

int mb_mark_used_test(struct ext4_buddy *e4b, struct ext4_free_extent *ex)
{
	return mb_mark_used(e4b, ex);
}
EXPORT_SYMBOL_FOR_EXT4_TEST(mb_mark_used_test);

void ext4_mb_generate_buddy_test(struct super_block *sb, void *buddy,
				 void *bitmap, ext4_group_t group,
				 struct ext4_group_info *grp)
{
	ext4_mb_generate_buddy(sb, buddy, bitmap, group, grp);
}
EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_generate_buddy_test);

int ext4_mb_load_buddy_test(struct super_block *sb, ext4_group_t group,
			    struct ext4_buddy *e4b)
{
	return ext4_mb_load_buddy(sb, group, e4b);
}
EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_load_buddy_test);

void ext4_mb_unload_buddy_test(struct ext4_buddy *e4b)
{
	ext4_mb_unload_buddy(e4b);
}
EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_unload_buddy_test);

void mb_free_blocks_test(struct inode *inode, struct ext4_buddy *e4b,
			 int first, int count)
{
	mb_free_blocks(inode, e4b, first, count);
}
EXPORT_SYMBOL_FOR_EXT4_TEST(mb_free_blocks_test);

void ext4_free_blocks_simple_test(struct inode *inode, ext4_fsblk_t block,
				  unsigned long count)
{
	return ext4_free_blocks_simple(inode, block, count);
}
EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_free_blocks_simple_test);

EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_wait_block_bitmap);
EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_init);
EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_get_group_desc);
EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_count_free_clusters);
EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_get_group_info);
EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_free_group_clusters_set);
EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_release);
EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_read_block_bitmap_nowait);
EXPORT_SYMBOL_FOR_EXT4_TEST(mb_set_bits);
EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_fc_init_inode);
EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_mark_context);
#endif
+30 −0
Original line number Diff line number Diff line
@@ -270,4 +270,34 @@ ext4_mballoc_query_range(
	ext4_mballoc_query_range_fn	formatter,
	void				*priv);

extern int ext4_mb_mark_context(handle_t *handle,
		struct super_block *sb, bool state,
		ext4_group_t group, ext4_grpblk_t blkoff,
		ext4_grpblk_t len, int flags,
		ext4_grpblk_t *ret_changed);
#if IS_ENABLED(CONFIG_EXT4_KUNIT_TESTS)
extern void mb_clear_bits_test(void *bm, int cur, int len);
extern ext4_fsblk_t
ext4_mb_new_blocks_simple_test(struct ext4_allocation_request *ar,
			       int *errp);
extern int mb_find_next_zero_bit_test(void *addr, int max, int start);
extern int mb_find_next_bit_test(void *addr, int max, int start);
extern void mb_clear_bit_test(int bit, void *addr);
extern int mb_test_bit_test(int bit, void *addr);
extern int
ext4_mb_mark_diskspace_used_test(struct ext4_allocation_context *ac,
				 handle_t *handle);
extern int mb_mark_used_test(struct ext4_buddy *e4b,
			     struct ext4_free_extent *ex);
extern void ext4_mb_generate_buddy_test(struct super_block *sb,
		void *buddy, void *bitmap, ext4_group_t group,
		struct ext4_group_info *grp);
extern int ext4_mb_load_buddy_test(struct super_block *sb,
		ext4_group_t group, struct ext4_buddy *e4b);
extern void ext4_mb_unload_buddy_test(struct ext4_buddy *e4b);
extern void mb_free_blocks_test(struct inode *inode,
		struct ext4_buddy *e4b, int first, int count);
extern void ext4_free_blocks_simple_test(struct inode *inode,
		ext4_fsblk_t block, unsigned long count);
#endif
#endif