Commit 5eda8f25 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'linux_kselftest-kunit-6.7-rc1' of...

Merge tag 'linux_kselftest-kunit-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest

Pull kunit updates from Shuah Khan:

 - string-stream testing enhancements

 - several fixes memory leaks

 - fix to reset status during parameter handling

* tag 'linux_kselftest-kunit-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest:
  kunit: test: Fix the possible memory leak in executor_test
  kunit: Fix possible memory leak in kunit_filter_suites()
  kunit: Fix the wrong kfree of copy for kunit_filter_suites()
  kunit: Fix missed memory release in kunit_free_suite_set()
  kunit: Reset test status on each param iteration
  kunit: string-stream: Test performance of string_stream
  kunit: Use string_stream for test log
  kunit: string-stream: Add tests for freeing resource-managed string_stream
  kunit: string-stream: Decouple string_stream from kunit
  kunit: string-stream: Add kunit_alloc_string_stream()
  kunit: Don't use a managed alloc in is_literal()
  kunit: string-stream-test: Add cases for string_stream newline appending
  kunit: string-stream: Add option to make all lines end with newline
  kunit: string-stream: Improve testing of string_stream
  kunit: string-stream: Don't create a fragment for empty strings
parents 463f46e1 8040345f
Loading
Loading
Loading
Loading
+6 −8
Original line number Diff line number Diff line
@@ -33,9 +33,7 @@
DECLARE_STATIC_KEY_FALSE(kunit_running);

struct kunit;

/* Size of log associated with test. */
#define KUNIT_LOG_SIZE 2048
struct string_stream;

/* Maximum size of parameter description string. */
#define KUNIT_PARAM_DESC_SIZE 128
@@ -133,7 +131,7 @@ struct kunit_case {
	/* private: internal use only. */
	enum kunit_status status;
	char *module_name;
	char *log;
	struct string_stream *log;
};

static inline char *kunit_status_to_ok_not_ok(enum kunit_status status)
@@ -253,7 +251,7 @@ struct kunit_suite {
	/* private: internal use only */
	char status_comment[KUNIT_STATUS_COMMENT_SIZE];
	struct dentry *debugfs;
	char *log;
	struct string_stream *log;
	int suite_init_err;
};

@@ -279,7 +277,7 @@ struct kunit {

	/* private: internal use only. */
	const char *name; /* Read only after initialization! */
	char *log; /* Points at case log after initialization */
	struct string_stream *log; /* Points at case log after initialization */
	struct kunit_try_catch try_catch;
	/* param_value is the current parameter value for a test case. */
	const void *param_value;
@@ -315,7 +313,7 @@ const char *kunit_filter_glob(void);
char *kunit_filter(void);
char *kunit_filter_action(void);

void kunit_init_test(struct kunit *test, const char *name, char *log);
void kunit_init_test(struct kunit *test, const char *name, struct string_stream *log);

int kunit_run_tests(struct kunit_suite *suite);

@@ -473,7 +471,7 @@ static inline void *kunit_kcalloc(struct kunit *test, size_t n, size_t size, gfp

void kunit_cleanup(struct kunit *test);

void __printf(2, 3) kunit_log_append(char *log, const char *fmt, ...);
void __printf(2, 3) kunit_log_append(struct string_stream *log, const char *fmt, ...);

/**
 * kunit_mark_skipped() - Marks @test_or_suite as skipped
+6 −8
Original line number Diff line number Diff line
@@ -89,8 +89,7 @@ void kunit_ptr_not_err_assert_format(const struct kunit_assert *assert,
EXPORT_SYMBOL_GPL(kunit_ptr_not_err_assert_format);

/* Checks if `text` is a literal representing `value`, e.g. "5" and 5 */
static bool is_literal(struct kunit *test, const char *text, long long value,
		       gfp_t gfp)
static bool is_literal(const char *text, long long value)
{
	char *buffer;
	int len;
@@ -100,14 +99,15 @@ static bool is_literal(struct kunit *test, const char *text, long long value,
	if (strlen(text) != len)
		return false;

	buffer = kunit_kmalloc(test, len+1, gfp);
	buffer = kmalloc(len+1, GFP_KERNEL);
	if (!buffer)
		return false;

	snprintf(buffer, len+1, "%lld", value);
	ret = strncmp(buffer, text, len) == 0;

	kunit_kfree(test, buffer);
	kfree(buffer);

	return ret;
}

@@ -125,14 +125,12 @@ void kunit_binary_assert_format(const struct kunit_assert *assert,
			  binary_assert->text->left_text,
			  binary_assert->text->operation,
			  binary_assert->text->right_text);
	if (!is_literal(stream->test, binary_assert->text->left_text,
			binary_assert->left_value, stream->gfp))
	if (!is_literal(binary_assert->text->left_text, binary_assert->left_value))
		string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld (0x%llx)\n",
				  binary_assert->text->left_text,
				  binary_assert->left_value,
				  binary_assert->left_value);
	if (!is_literal(stream->test, binary_assert->text->right_text,
			binary_assert->right_value, stream->gfp))
	if (!is_literal(binary_assert->text->right_text, binary_assert->right_value))
		string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld (0x%llx)",
				  binary_assert->text->right_text,
				  binary_assert->right_value,
+23 −13
Original line number Diff line number Diff line
@@ -37,14 +37,21 @@ void kunit_debugfs_init(void)
		debugfs_rootdir = debugfs_create_dir(KUNIT_DEBUGFS_ROOT, NULL);
}

static void debugfs_print_result(struct seq_file *seq,
				 struct kunit_suite *suite,
				 struct kunit_case *test_case)
static void debugfs_print_result(struct seq_file *seq, struct string_stream *log)
{
	if (!test_case || !test_case->log)
	struct string_stream_fragment *frag_container;

	if (!log)
		return;

	seq_printf(seq, "%s", test_case->log);
	/*
	 * Walk the fragments so we don't need to allocate a temporary
	 * buffer to hold the entire string.
	 */
	spin_lock(&log->lock);
	list_for_each_entry(frag_container, &log->fragments, node)
		seq_printf(seq, "%s", frag_container->fragment);
	spin_unlock(&log->lock);
}

/*
@@ -69,10 +76,9 @@ static int debugfs_print_results(struct seq_file *seq, void *v)
	seq_printf(seq, KUNIT_SUBTEST_INDENT "1..%zd\n", kunit_suite_num_test_cases(suite));

	kunit_suite_for_each_test_case(suite, test_case)
		debugfs_print_result(seq, suite, test_case);
		debugfs_print_result(seq, test_case->log);

	if (suite->log)
		seq_printf(seq, "%s", suite->log);
	debugfs_print_result(seq, suite->log);

	seq_printf(seq, "%s %d %s\n",
		   kunit_status_to_ok_not_ok(success), 1, suite->name);
@@ -105,9 +111,13 @@ void kunit_debugfs_create_suite(struct kunit_suite *suite)
	struct kunit_case *test_case;

	/* Allocate logs before creating debugfs representation. */
	suite->log = kzalloc(KUNIT_LOG_SIZE, GFP_KERNEL);
	kunit_suite_for_each_test_case(suite, test_case)
		test_case->log = kzalloc(KUNIT_LOG_SIZE, GFP_KERNEL);
	suite->log = alloc_string_stream(GFP_KERNEL);
	string_stream_set_append_newlines(suite->log, true);

	kunit_suite_for_each_test_case(suite, test_case) {
		test_case->log = alloc_string_stream(GFP_KERNEL);
		string_stream_set_append_newlines(test_case->log, true);
	}

	suite->debugfs = debugfs_create_dir(suite->name, debugfs_rootdir);

@@ -121,7 +131,7 @@ void kunit_debugfs_destroy_suite(struct kunit_suite *suite)
	struct kunit_case *test_case;

	debugfs_remove_recursive(suite->debugfs);
	kfree(suite->log);
	string_stream_destroy(suite->log);
	kunit_suite_for_each_test_case(suite, test_case)
		kfree(test_case->log);
		string_stream_destroy(test_case->log);
}
+17 −6
Original line number Diff line number Diff line
@@ -137,8 +137,10 @@ void kunit_free_suite_set(struct kunit_suite_set suite_set)
{
	struct kunit_suite * const *suites;

	for (suites = suite_set.start; suites < suite_set.end; suites++)
	for (suites = suite_set.start; suites < suite_set.end; suites++) {
		kfree((*suites)->test_cases);
		kfree(*suites);
	}
	kfree(suite_set.start);
}

@@ -155,10 +157,11 @@ kunit_filter_suites(const struct kunit_suite_set *suite_set,
	struct kunit_suite_set filtered = {NULL, NULL};
	struct kunit_glob_filter parsed_glob;
	struct kunit_attr_filter *parsed_filters = NULL;
	struct kunit_suite * const *suites;

	const size_t max = suite_set->end - suite_set->start;

	copy = kmalloc_array(max, sizeof(*filtered.start), GFP_KERNEL);
	copy = kcalloc(max, sizeof(*filtered.start), GFP_KERNEL);
	if (!copy) { /* won't be able to run anything, return an empty set */
		return filtered;
	}
@@ -193,7 +196,7 @@ kunit_filter_suites(const struct kunit_suite_set *suite_set,
					parsed_glob.test_glob);
			if (IS_ERR(filtered_suite)) {
				*err = PTR_ERR(filtered_suite);
				goto free_parsed_filters;
				goto free_filtered_suite;
			}
		}
		if (filter_count > 0 && parsed_filters != NULL) {
@@ -210,11 +213,11 @@ kunit_filter_suites(const struct kunit_suite_set *suite_set,
				filtered_suite = new_filtered_suite;

				if (*err)
					goto free_parsed_filters;
					goto free_filtered_suite;

				if (IS_ERR(filtered_suite)) {
					*err = PTR_ERR(filtered_suite);
					goto free_parsed_filters;
					goto free_filtered_suite;
				}
				if (!filtered_suite)
					break;
@@ -229,6 +232,14 @@ kunit_filter_suites(const struct kunit_suite_set *suite_set,
	filtered.start = copy_start;
	filtered.end = copy;

free_filtered_suite:
	if (*err) {
		for (suites = copy_start; suites < copy; suites++) {
			kfree((*suites)->test_cases);
			kfree(*suites);
		}
	}

free_parsed_filters:
	if (filter_count)
		kfree(parsed_filters);
@@ -241,7 +252,7 @@ kunit_filter_suites(const struct kunit_suite_set *suite_set,

free_copy:
	if (*err)
		kfree(copy);
		kfree(copy_start);

	return filtered;
}
+22 −14
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@
#include <kunit/test.h>
#include <kunit/attributes.h>

static void kfree_at_end(struct kunit *test, const void *to_free);
static void free_suite_set_at_end(struct kunit *test, const void *to_free);
static struct kunit_suite *alloc_fake_suite(struct kunit *test,
					    const char *suite_name,
					    struct kunit_case *test_cases);
@@ -56,7 +56,7 @@ static void filter_suites_test(struct kunit *test)
	got = kunit_filter_suites(&suite_set, "suite2", NULL, NULL, &err);
	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start);
	KUNIT_ASSERT_EQ(test, err, 0);
	kfree_at_end(test, got.start);
	free_suite_set_at_end(test, &got);

	/* Validate we just have suite2 */
	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]);
@@ -82,7 +82,7 @@ static void filter_suites_test_glob_test(struct kunit *test)
	got = kunit_filter_suites(&suite_set, "suite2.test2", NULL, NULL, &err);
	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start);
	KUNIT_ASSERT_EQ(test, err, 0);
	kfree_at_end(test, got.start);
	free_suite_set_at_end(test, &got);

	/* Validate we just have suite2 */
	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]);
@@ -109,7 +109,7 @@ static void filter_suites_to_empty_test(struct kunit *test)

	got = kunit_filter_suites(&suite_set, "not_found", NULL, NULL, &err);
	KUNIT_ASSERT_EQ(test, err, 0);
	kfree_at_end(test, got.start); /* just in case */
	free_suite_set_at_end(test, &got); /* just in case */

	KUNIT_EXPECT_PTR_EQ_MSG(test, got.start, got.end,
				"should be empty to indicate no match");
@@ -172,7 +172,7 @@ static void filter_attr_test(struct kunit *test)
	got = kunit_filter_suites(&suite_set, NULL, filter, NULL, &err);
	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start);
	KUNIT_ASSERT_EQ(test, err, 0);
	kfree_at_end(test, got.start);
	free_suite_set_at_end(test, &got);

	/* Validate we just have normal_suite */
	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]);
@@ -200,7 +200,7 @@ static void filter_attr_empty_test(struct kunit *test)

	got = kunit_filter_suites(&suite_set, NULL, filter, NULL, &err);
	KUNIT_ASSERT_EQ(test, err, 0);
	kfree_at_end(test, got.start); /* just in case */
	free_suite_set_at_end(test, &got); /* just in case */

	KUNIT_EXPECT_PTR_EQ_MSG(test, got.start, got.end,
				"should be empty to indicate no match");
@@ -222,7 +222,7 @@ static void filter_attr_skip_test(struct kunit *test)
	got = kunit_filter_suites(&suite_set, NULL, filter, "skip", &err);
	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start);
	KUNIT_ASSERT_EQ(test, err, 0);
	kfree_at_end(test, got.start);
	free_suite_set_at_end(test, &got);

	/* Validate we have both the slow and normal test */
	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]->test_cases);
@@ -256,18 +256,26 @@ kunit_test_suites(&executor_test_suite);

/* Test helpers */

/* Use the resource API to register a call to kfree(to_free).
static void free_suite_set(void *suite_set)
{
	kunit_free_suite_set(*(struct kunit_suite_set *)suite_set);
	kfree(suite_set);
}

/* Use the resource API to register a call to free_suite_set.
 * Since we never actually use the resource, it's safe to use on const data.
 */
static void kfree_at_end(struct kunit *test, const void *to_free)
static void free_suite_set_at_end(struct kunit *test, const void *to_free)
{
	/* kfree() handles NULL already, but avoid allocating a no-op cleanup. */
	if (IS_ERR_OR_NULL(to_free))
	struct kunit_suite_set *free;

	if (!((struct kunit_suite_set *)to_free)->start)
		return;

	kunit_add_action(test,
			(kunit_action_t *)kfree,
			(void *)to_free);
	free = kzalloc(sizeof(struct kunit_suite_set), GFP_KERNEL);
	*free = *(struct kunit_suite_set *)to_free;

	kunit_add_action(test, free_suite_set, (void *)free);
}

static struct kunit_suite *alloc_fake_suite(struct kunit *test,
Loading