linux_kselftest-kunit-6.10-rc1

This kunit update for Linux 6.10-rc1 consists of:
 
 - fix to race condition in try-catch completion
 - change to __kunit_test_suites_init() to exit early if there is
   nothing to test
 - change to string-stream-test to use KUNIT_DEFINE_ACTION_WRAPPER
 - moving fault tests behind KUNIT_FAULT_TEST Kconfig option
 - kthread test fixes and improvements
 - iov_iter test fixes
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEPZKym/RZuOCGeA/kCwJExA0NQxwFAmZCNsAACgkQCwJExA0N
 Qxx03w/9EmjF3T16LPaeuerdoypWDcroDT6gpoFXGrvf3lDrna8uDNija5Pb1yMn
 l97wla3IJ1EZRMTy1jgWGQiiGIdkV8hcze65HZMi19qx/49TUbhA/pTmpYC56cp9
 sk2fBjOHz8iI4kdL4eCMr9MpSiwOIDcfWOr1Lh/AP2LHOU1pRdFZbwO6iZ3wyGlJ
 JH4D1CwmfgMGEau4qUo0jvuRbFAf33S+yEI9gr8CskPItljFVO4jVz4lprnTbU9i
 qAOivHzwcHyYc0upb6q2vIlp8vhmDygG/m07lnwfF7ZHsYo+3zV4FkxHspN2+jGA
 frH7Y0X9zt6YjRRMb9NcNnI67VTiSNzdCvB7urUhKlbXoZ2gjtgB7zHeQtAhlXRo
 XVa4QgWBI5ExKBuLI+0yKo4wEO8M0quXxhbX+2Q+tsRnoYmhwb0G8AUyl/26bt2g
 RelGrArDS5eMrlxl97rjMGFrB5Uan2MR751tl+aZPgyNRW3tRKJnQLZmM1z8aFQp
 vGReT6POzCnQ1wLUkcj6mnObbv9XuuYY1BQgKCtmJflvRToEuwpLOKK8Uca7ou3p
 TbVarGIn0jdHv4zGkXrAkt/mhcxanBXhVKLfh/MqQ7fCZBULkSrjJFLhCpvvHwIV
 nckaP2sZWls6FTDuawFOUxrr/+LjJchMmHhFy9MiDaVoieiTg6U=
 =3QIa
 -----END PGP SIGNATURE-----

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

Pull kunit updates from Shuah Khan:

 - fix race condition in try-catch completion

 - change __kunit_test_suites_init() to exit early if there is
   nothing to test

 - change string-stream-test to use KUNIT_DEFINE_ACTION_WRAPPER

 - move fault tests behind KUNIT_FAULT_TEST Kconfig option

 - kthread test fixes and improvements

 - iov_iter test fixes

* tag 'linux_kselftest-kunit-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest:
  kunit: bail out early in __kunit_test_suites_init() if there are no suites to test
  kunit: string-stream-test: use KUNIT_DEFINE_ACTION_WRAPPER
  kunit: test: Move fault tests behind KUNIT_FAULT_TEST Kconfig option
  kunit: unregister the device on error
  kunit: Fix race condition in try-catch completion
  kunit: Add tests for fault
  kunit: Print last test location on fault
  kunit: Fix KUNIT_SUCCESS() calls in iov_iter tests
  kunit: Handle test faults
  kunit: Fix timeout message
  kunit: Fix kthread reference
  kunit: Handle thread creation error
This commit is contained in:
Linus Torvalds 2024-05-14 11:32:52 -07:00
commit 896d3fce84
10 changed files with 121 additions and 38 deletions

View File

@ -301,6 +301,8 @@ struct kunit {
struct list_head resources; /* Protected by lock. */
char status_comment[KUNIT_STATUS_COMMENT_SIZE];
/* Saves the last seen test. Useful to help with faults. */
struct kunit_loc last_seen;
};
static inline void kunit_set_failure(struct kunit *test)
@ -567,6 +569,15 @@ void __printf(2, 3) kunit_log_append(struct string_stream *log, const char *fmt,
#define kunit_err(test, fmt, ...) \
kunit_printk(KERN_ERR, test, fmt, ##__VA_ARGS__)
/*
* Must be called at the beginning of each KUNIT_*_ASSERTION().
* Cf. KUNIT_CURRENT_LOC.
*/
#define _KUNIT_SAVE_LOC(test) do { \
WRITE_ONCE(test->last_seen.file, __FILE__); \
WRITE_ONCE(test->last_seen.line, __LINE__); \
} while (0)
/**
* KUNIT_SUCCEED() - A no-op expectation. Only exists for code clarity.
* @test: The test context object.
@ -575,7 +586,7 @@ void __printf(2, 3) kunit_log_append(struct string_stream *log, const char *fmt,
* words, it does nothing and only exists for code clarity. See
* KUNIT_EXPECT_TRUE() for more information.
*/
#define KUNIT_SUCCEED(test) do {} while (0)
#define KUNIT_SUCCEED(test) _KUNIT_SAVE_LOC(test)
void __noreturn __kunit_abort(struct kunit *test);
@ -601,14 +612,16 @@ void __printf(6, 7) __kunit_do_failed_assertion(struct kunit *test,
} while (0)
#define KUNIT_FAIL_ASSERTION(test, assert_type, fmt, ...) \
#define KUNIT_FAIL_ASSERTION(test, assert_type, fmt, ...) do { \
_KUNIT_SAVE_LOC(test); \
_KUNIT_FAILED(test, \
assert_type, \
kunit_fail_assert, \
kunit_fail_assert_format, \
{}, \
fmt, \
##__VA_ARGS__)
##__VA_ARGS__); \
} while (0)
/**
* KUNIT_FAIL() - Always causes a test to fail when evaluated.
@ -637,6 +650,7 @@ void __printf(6, 7) __kunit_do_failed_assertion(struct kunit *test,
fmt, \
...) \
do { \
_KUNIT_SAVE_LOC(test); \
if (likely(!!(condition_) == !!expected_true_)) \
break; \
\
@ -698,6 +712,7 @@ do { \
.right_text = #right, \
}; \
\
_KUNIT_SAVE_LOC(test); \
if (likely(__left op __right)) \
break; \
\
@ -758,6 +773,7 @@ do { \
.right_text = #right, \
}; \
\
_KUNIT_SAVE_LOC(test); \
if (likely((__left) && (__right) && (strcmp(__left, __right) op 0))) \
break; \
\
@ -791,6 +807,7 @@ do { \
.right_text = #right, \
}; \
\
_KUNIT_SAVE_LOC(test); \
if (likely(__left && __right)) \
if (likely(memcmp(__left, __right, __size) op 0)) \
break; \
@ -815,6 +832,7 @@ do { \
do { \
const typeof(ptr) __ptr = (ptr); \
\
_KUNIT_SAVE_LOC(test); \
if (!IS_ERR_OR_NULL(__ptr)) \
break; \
\

View File

@ -14,13 +14,11 @@
typedef void (*kunit_try_catch_func_t)(void *);
struct completion;
struct kunit;
/**
* struct kunit_try_catch - provides a generic way to run code which might fail.
* @test: The test case that is currently being executed.
* @try_completion: Completion that the control thread waits on while test runs.
* @try_result: Contains any errno obtained while running test case.
* @try: The function, the test case, to attempt to run.
* @catch: The function called if @try bails out.
@ -46,7 +44,6 @@ struct kunit;
struct kunit_try_catch {
/* private: internal use only. */
struct kunit *test;
struct completion *try_completion;
int try_result;
kunit_try_catch_func_t try;
kunit_try_catch_func_t catch;

View File

@ -315,6 +315,7 @@ void __noreturn kthread_exit(long result)
kthread->result = result;
do_exit(0);
}
EXPORT_SYMBOL(kthread_exit);
/**
* kthread_complete_and_exit - Exit the current kthread.

View File

@ -24,6 +24,17 @@ config KUNIT_DEBUGFS
test suite, which allow users to see results of the last test suite
run that occurred.
config KUNIT_FAULT_TEST
bool "Enable KUnit tests which print BUG stacktraces"
depends on KUNIT_TEST
depends on !UML
default y
help
Enables fault handling tests for the KUnit framework. These tests may
trigger a kernel BUG(), and the associated stack trace, even when they
pass. If this conflicts with your test infrastrcture (or is confusing
or annoying), they can be disabled by setting this to N.
config KUNIT_TEST
tristate "KUnit test for KUnit" if !KUNIT_ALL_TESTS
default KUNIT_ALL_TESTS

View File

@ -51,7 +51,7 @@ int kunit_bus_init(void)
error = bus_register(&kunit_bus_type);
if (error)
bus_unregister(&kunit_bus_type);
root_device_unregister(kunit_bus_device);
return error;
}

View File

@ -109,6 +109,48 @@ static struct kunit_suite kunit_try_catch_test_suite = {
.test_cases = kunit_try_catch_test_cases,
};
#if IS_ENABLED(CONFIG_KUNIT_FAULT_TEST)
static void kunit_test_null_dereference(void *data)
{
struct kunit *test = data;
int *null = NULL;
*null = 0;
KUNIT_FAIL(test, "This line should never be reached\n");
}
static void kunit_test_fault_null_dereference(struct kunit *test)
{
struct kunit_try_catch_test_context *ctx = test->priv;
struct kunit_try_catch *try_catch = ctx->try_catch;
kunit_try_catch_init(try_catch,
test,
kunit_test_null_dereference,
kunit_test_catch);
kunit_try_catch_run(try_catch, test);
KUNIT_EXPECT_EQ(test, try_catch->try_result, -EINTR);
KUNIT_EXPECT_TRUE(test, ctx->function_called);
}
#endif /* CONFIG_KUNIT_FAULT_TEST */
static struct kunit_case kunit_fault_test_cases[] = {
#if IS_ENABLED(CONFIG_KUNIT_FAULT_TEST)
KUNIT_CASE(kunit_test_fault_null_dereference),
#endif /* CONFIG_KUNIT_FAULT_TEST */
{}
};
static struct kunit_suite kunit_fault_test_suite = {
.name = "kunit_fault",
.init = kunit_try_catch_test_init,
.test_cases = kunit_fault_test_cases,
};
/*
* Context for testing test managed resources
* is_resource_initialized is used to test arbitrary resources
@ -826,6 +868,7 @@ static struct kunit_suite kunit_current_test_suite = {
kunit_test_suites(&kunit_try_catch_test_suite, &kunit_resource_test_suite,
&kunit_log_test_suite, &kunit_status_test_suite,
&kunit_current_test_suite, &kunit_device_test_suite);
&kunit_current_test_suite, &kunit_device_test_suite,
&kunit_fault_test_suite);
MODULE_LICENSE("GPL v2");

View File

@ -22,18 +22,10 @@ struct string_stream_test_priv {
};
/* Avoids a cast warning if kfree() is passed direct to kunit_add_action(). */
static void kfree_wrapper(void *p)
{
kfree(p);
}
KUNIT_DEFINE_ACTION_WRAPPER(kfree_wrapper, kfree, const void *);
/* Avoids a cast warning if string_stream_destroy() is passed direct to kunit_add_action(). */
static void cleanup_raw_stream(void *p)
{
struct string_stream *stream = p;
string_stream_destroy(stream);
}
KUNIT_DEFINE_ACTION_WRAPPER(cleanup_raw_stream, string_stream_destroy, struct string_stream *);
static char *get_concatenated_string(struct kunit *test, struct string_stream *stream)
{

View File

@ -712,6 +712,9 @@ int __kunit_test_suites_init(struct kunit_suite * const * const suites, int num_
{
unsigned int i;
if (num_suites == 0)
return 0;
if (!kunit_enabled() && num_suites > 0) {
pr_info("kunit: disabled\n");
return 0;

View File

@ -11,13 +11,14 @@
#include <linux/completion.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/sched/task.h>
#include "try-catch-impl.h"
void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch)
{
try_catch->try_result = -EFAULT;
kthread_complete_and_exit(try_catch->try_completion, -EFAULT);
kthread_exit(0);
}
EXPORT_SYMBOL_GPL(kunit_try_catch_throw);
@ -25,9 +26,12 @@ static int kunit_generic_run_threadfn_adapter(void *data)
{
struct kunit_try_catch *try_catch = data;
try_catch->try_result = -EINTR;
try_catch->try(try_catch->context);
if (try_catch->try_result == -EINTR)
try_catch->try_result = 0;
kthread_complete_and_exit(try_catch->try_completion, 0);
return 0;
}
static unsigned long kunit_test_timeout(void)
@ -57,30 +61,38 @@ static unsigned long kunit_test_timeout(void)
void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context)
{
DECLARE_COMPLETION_ONSTACK(try_completion);
struct kunit *test = try_catch->test;
struct task_struct *task_struct;
struct completion *task_done;
int exit_code, time_remaining;
try_catch->context = context;
try_catch->try_completion = &try_completion;
try_catch->try_result = 0;
task_struct = kthread_run(kunit_generic_run_threadfn_adapter,
try_catch,
"kunit_try_catch_thread");
task_struct = kthread_create(kunit_generic_run_threadfn_adapter,
try_catch, "kunit_try_catch_thread");
if (IS_ERR(task_struct)) {
try_catch->try_result = PTR_ERR(task_struct);
try_catch->catch(try_catch->context);
return;
}
get_task_struct(task_struct);
/*
* As for a vfork(2), task_struct->vfork_done (pointing to the
* underlying kthread->exited) can be used to wait for the end of a
* kernel thread. It is set to NULL when the thread exits, so we
* keep a copy here.
*/
task_done = task_struct->vfork_done;
wake_up_process(task_struct);
time_remaining = wait_for_completion_timeout(&try_completion,
time_remaining = wait_for_completion_timeout(task_done,
kunit_test_timeout());
if (time_remaining == 0) {
kunit_err(test, "try timed out\n");
try_catch->try_result = -ETIMEDOUT;
kthread_stop(task_struct);
}
put_task_struct(task_struct);
exit_code = try_catch->try_result;
if (!exit_code)
@ -88,8 +100,14 @@ void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context)
if (exit_code == -EFAULT)
try_catch->try_result = 0;
else if (exit_code == -EINTR)
kunit_err(test, "wake_up_process() was never called\n");
else if (exit_code == -EINTR) {
if (test->last_seen.file)
kunit_err(test, "try faulted: last line seen %s:%d\n",
test->last_seen.file, test->last_seen.line);
else
kunit_err(test, "try faulted\n");
} else if (exit_code == -ETIMEDOUT)
kunit_err(test, "try timed out\n");
else if (exit_code)
kunit_err(test, "Unknown error: %d\n", exit_code);

View File

@ -139,7 +139,7 @@ static void __init iov_kunit_copy_to_kvec(struct kunit *test)
return;
}
KUNIT_SUCCEED();
KUNIT_SUCCEED(test);
}
/*
@ -194,7 +194,7 @@ static void __init iov_kunit_copy_from_kvec(struct kunit *test)
return;
}
KUNIT_SUCCEED();
KUNIT_SUCCEED(test);
}
struct bvec_test_range {
@ -302,7 +302,7 @@ static void __init iov_kunit_copy_to_bvec(struct kunit *test)
return;
}
KUNIT_SUCCEED();
KUNIT_SUCCEED(test);
}
/*
@ -359,7 +359,7 @@ static void __init iov_kunit_copy_from_bvec(struct kunit *test)
return;
}
KUNIT_SUCCEED();
KUNIT_SUCCEED(test);
}
static void iov_kunit_destroy_xarray(void *data)
@ -453,7 +453,7 @@ static void __init iov_kunit_copy_to_xarray(struct kunit *test)
return;
}
KUNIT_SUCCEED();
KUNIT_SUCCEED(test);
}
/*
@ -516,7 +516,7 @@ static void __init iov_kunit_copy_from_xarray(struct kunit *test)
return;
}
KUNIT_SUCCEED();
KUNIT_SUCCEED(test);
}
/*
@ -596,7 +596,7 @@ static void __init iov_kunit_extract_pages_kvec(struct kunit *test)
stop:
KUNIT_EXPECT_EQ(test, size, 0);
KUNIT_EXPECT_EQ(test, iter.count, 0);
KUNIT_SUCCEED();
KUNIT_SUCCEED(test);
}
/*
@ -674,7 +674,7 @@ static void __init iov_kunit_extract_pages_bvec(struct kunit *test)
stop:
KUNIT_EXPECT_EQ(test, size, 0);
KUNIT_EXPECT_EQ(test, iter.count, 0);
KUNIT_SUCCEED();
KUNIT_SUCCEED(test);
}
/*
@ -753,7 +753,7 @@ static void __init iov_kunit_extract_pages_xarray(struct kunit *test)
}
stop:
KUNIT_SUCCEED();
KUNIT_SUCCEED(test);
}
static struct kunit_case __refdata iov_kunit_cases[] = {