Commit 896d3fce authored by Linus Torvalds's avatar Linus Torvalds

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

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
parents 4b768bf0 5496b9b7
...@@ -301,6 +301,8 @@ struct kunit { ...@@ -301,6 +301,8 @@ struct kunit {
struct list_head resources; /* Protected by lock. */ struct list_head resources; /* Protected by lock. */
char status_comment[KUNIT_STATUS_COMMENT_SIZE]; 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) 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, ...@@ -567,6 +569,15 @@ void __printf(2, 3) kunit_log_append(struct string_stream *log, const char *fmt,
#define kunit_err(test, fmt, ...) \ #define kunit_err(test, fmt, ...) \
kunit_printk(KERN_ERR, test, fmt, ##__VA_ARGS__) 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. * KUNIT_SUCCEED() - A no-op expectation. Only exists for code clarity.
* @test: The test context object. * @test: The test context object.
...@@ -575,7 +586,7 @@ void __printf(2, 3) kunit_log_append(struct string_stream *log, const char *fmt, ...@@ -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 * words, it does nothing and only exists for code clarity. See
* KUNIT_EXPECT_TRUE() for more information. * 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); void __noreturn __kunit_abort(struct kunit *test);
...@@ -601,14 +612,16 @@ void __printf(6, 7) __kunit_do_failed_assertion(struct kunit *test, ...@@ -601,14 +612,16 @@ void __printf(6, 7) __kunit_do_failed_assertion(struct kunit *test,
} while (0) } 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, \ _KUNIT_FAILED(test, \
assert_type, \ assert_type, \
kunit_fail_assert, \ kunit_fail_assert, \
kunit_fail_assert_format, \ kunit_fail_assert_format, \
{}, \ {}, \
fmt, \ fmt, \
##__VA_ARGS__) ##__VA_ARGS__); \
} while (0)
/** /**
* KUNIT_FAIL() - Always causes a test to fail when evaluated. * 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, ...@@ -637,6 +650,7 @@ void __printf(6, 7) __kunit_do_failed_assertion(struct kunit *test,
fmt, \ fmt, \
...) \ ...) \
do { \ do { \
_KUNIT_SAVE_LOC(test); \
if (likely(!!(condition_) == !!expected_true_)) \ if (likely(!!(condition_) == !!expected_true_)) \
break; \ break; \
\ \
...@@ -698,6 +712,7 @@ do { \ ...@@ -698,6 +712,7 @@ do { \
.right_text = #right, \ .right_text = #right, \
}; \ }; \
\ \
_KUNIT_SAVE_LOC(test); \
if (likely(__left op __right)) \ if (likely(__left op __right)) \
break; \ break; \
\ \
...@@ -758,6 +773,7 @@ do { \ ...@@ -758,6 +773,7 @@ do { \
.right_text = #right, \ .right_text = #right, \
}; \ }; \
\ \
_KUNIT_SAVE_LOC(test); \
if (likely((__left) && (__right) && (strcmp(__left, __right) op 0))) \ if (likely((__left) && (__right) && (strcmp(__left, __right) op 0))) \
break; \ break; \
\ \
...@@ -791,6 +807,7 @@ do { \ ...@@ -791,6 +807,7 @@ do { \
.right_text = #right, \ .right_text = #right, \
}; \ }; \
\ \
_KUNIT_SAVE_LOC(test); \
if (likely(__left && __right)) \ if (likely(__left && __right)) \
if (likely(memcmp(__left, __right, __size) op 0)) \ if (likely(memcmp(__left, __right, __size) op 0)) \
break; \ break; \
...@@ -815,6 +832,7 @@ do { \ ...@@ -815,6 +832,7 @@ do { \
do { \ do { \
const typeof(ptr) __ptr = (ptr); \ const typeof(ptr) __ptr = (ptr); \
\ \
_KUNIT_SAVE_LOC(test); \
if (!IS_ERR_OR_NULL(__ptr)) \ if (!IS_ERR_OR_NULL(__ptr)) \
break; \ break; \
\ \
......
...@@ -14,13 +14,11 @@ ...@@ -14,13 +14,11 @@
typedef void (*kunit_try_catch_func_t)(void *); typedef void (*kunit_try_catch_func_t)(void *);
struct completion;
struct kunit; struct kunit;
/** /**
* struct kunit_try_catch - provides a generic way to run code which might fail. * struct kunit_try_catch - provides a generic way to run code which might fail.
* @test: The test case that is currently being executed. * @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_result: Contains any errno obtained while running test case.
* @try: The function, the test case, to attempt to run. * @try: The function, the test case, to attempt to run.
* @catch: The function called if @try bails out. * @catch: The function called if @try bails out.
...@@ -46,7 +44,6 @@ struct kunit; ...@@ -46,7 +44,6 @@ struct kunit;
struct kunit_try_catch { struct kunit_try_catch {
/* private: internal use only. */ /* private: internal use only. */
struct kunit *test; struct kunit *test;
struct completion *try_completion;
int try_result; int try_result;
kunit_try_catch_func_t try; kunit_try_catch_func_t try;
kunit_try_catch_func_t catch; kunit_try_catch_func_t catch;
......
...@@ -315,6 +315,7 @@ void __noreturn kthread_exit(long result) ...@@ -315,6 +315,7 @@ void __noreturn kthread_exit(long result)
kthread->result = result; kthread->result = result;
do_exit(0); do_exit(0);
} }
EXPORT_SYMBOL(kthread_exit);
/** /**
* kthread_complete_and_exit - Exit the current kthread. * kthread_complete_and_exit - Exit the current kthread.
......
...@@ -24,6 +24,17 @@ config KUNIT_DEBUGFS ...@@ -24,6 +24,17 @@ config KUNIT_DEBUGFS
test suite, which allow users to see results of the last test suite test suite, which allow users to see results of the last test suite
run that occurred. 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 config KUNIT_TEST
tristate "KUnit test for KUnit" if !KUNIT_ALL_TESTS tristate "KUnit test for KUnit" if !KUNIT_ALL_TESTS
default KUNIT_ALL_TESTS default KUNIT_ALL_TESTS
......
...@@ -51,7 +51,7 @@ int kunit_bus_init(void) ...@@ -51,7 +51,7 @@ int kunit_bus_init(void)
error = bus_register(&kunit_bus_type); error = bus_register(&kunit_bus_type);
if (error) if (error)
bus_unregister(&kunit_bus_type); root_device_unregister(kunit_bus_device);
return error; return error;
} }
......
...@@ -109,6 +109,48 @@ static struct kunit_suite kunit_try_catch_test_suite = { ...@@ -109,6 +109,48 @@ static struct kunit_suite kunit_try_catch_test_suite = {
.test_cases = kunit_try_catch_test_cases, .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 * Context for testing test managed resources
* is_resource_initialized is used to test arbitrary resources * is_resource_initialized is used to test arbitrary resources
...@@ -826,6 +868,7 @@ static struct kunit_suite kunit_current_test_suite = { ...@@ -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_test_suites(&kunit_try_catch_test_suite, &kunit_resource_test_suite,
&kunit_log_test_suite, &kunit_status_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"); MODULE_LICENSE("GPL v2");
...@@ -22,18 +22,10 @@ struct string_stream_test_priv { ...@@ -22,18 +22,10 @@ struct string_stream_test_priv {
}; };
/* Avoids a cast warning if kfree() is passed direct to kunit_add_action(). */ /* Avoids a cast warning if kfree() is passed direct to kunit_add_action(). */
static void kfree_wrapper(void *p) KUNIT_DEFINE_ACTION_WRAPPER(kfree_wrapper, kfree, const void *);
{
kfree(p);
}
/* Avoids a cast warning if string_stream_destroy() is passed direct to kunit_add_action(). */ /* Avoids a cast warning if string_stream_destroy() is passed direct to kunit_add_action(). */
static void cleanup_raw_stream(void *p) KUNIT_DEFINE_ACTION_WRAPPER(cleanup_raw_stream, string_stream_destroy, struct string_stream *);
{
struct string_stream *stream = p;
string_stream_destroy(stream);
}
static char *get_concatenated_string(struct kunit *test, struct string_stream *stream) static char *get_concatenated_string(struct kunit *test, struct string_stream *stream)
{ {
......
...@@ -712,6 +712,9 @@ int __kunit_test_suites_init(struct kunit_suite * const * const suites, int num_ ...@@ -712,6 +712,9 @@ int __kunit_test_suites_init(struct kunit_suite * const * const suites, int num_
{ {
unsigned int i; unsigned int i;
if (num_suites == 0)
return 0;
if (!kunit_enabled() && num_suites > 0) { if (!kunit_enabled() && num_suites > 0) {
pr_info("kunit: disabled\n"); pr_info("kunit: disabled\n");
return 0; return 0;
......
...@@ -11,13 +11,14 @@ ...@@ -11,13 +11,14 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/sched/task.h>
#include "try-catch-impl.h" #include "try-catch-impl.h"
void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch) void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch)
{ {
try_catch->try_result = -EFAULT; try_catch->try_result = -EFAULT;
kthread_complete_and_exit(try_catch->try_completion, -EFAULT); kthread_exit(0);
} }
EXPORT_SYMBOL_GPL(kunit_try_catch_throw); EXPORT_SYMBOL_GPL(kunit_try_catch_throw);
...@@ -25,9 +26,12 @@ static int kunit_generic_run_threadfn_adapter(void *data) ...@@ -25,9 +26,12 @@ static int kunit_generic_run_threadfn_adapter(void *data)
{ {
struct kunit_try_catch *try_catch = data; struct kunit_try_catch *try_catch = data;
try_catch->try_result = -EINTR;
try_catch->try(try_catch->context); 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) static unsigned long kunit_test_timeout(void)
...@@ -57,30 +61,38 @@ 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) 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 kunit *test = try_catch->test;
struct task_struct *task_struct; struct task_struct *task_struct;
struct completion *task_done;
int exit_code, time_remaining; int exit_code, time_remaining;
try_catch->context = context; try_catch->context = context;
try_catch->try_completion = &try_completion;
try_catch->try_result = 0; try_catch->try_result = 0;
task_struct = kthread_run(kunit_generic_run_threadfn_adapter, task_struct = kthread_create(kunit_generic_run_threadfn_adapter,
try_catch, try_catch, "kunit_try_catch_thread");
"kunit_try_catch_thread");
if (IS_ERR(task_struct)) { if (IS_ERR(task_struct)) {
try_catch->try_result = PTR_ERR(task_struct);
try_catch->catch(try_catch->context); try_catch->catch(try_catch->context);
return; 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()); kunit_test_timeout());
if (time_remaining == 0) { if (time_remaining == 0) {
kunit_err(test, "try timed out\n");
try_catch->try_result = -ETIMEDOUT; try_catch->try_result = -ETIMEDOUT;
kthread_stop(task_struct); kthread_stop(task_struct);
} }
put_task_struct(task_struct);
exit_code = try_catch->try_result; exit_code = try_catch->try_result;
if (!exit_code) if (!exit_code)
...@@ -88,8 +100,14 @@ void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context) ...@@ -88,8 +100,14 @@ void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context)
if (exit_code == -EFAULT) if (exit_code == -EFAULT)
try_catch->try_result = 0; try_catch->try_result = 0;
else if (exit_code == -EINTR) else if (exit_code == -EINTR) {
kunit_err(test, "wake_up_process() was never called\n"); 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) else if (exit_code)
kunit_err(test, "Unknown error: %d\n", exit_code); kunit_err(test, "Unknown error: %d\n", exit_code);
......
...@@ -139,7 +139,7 @@ static void __init iov_kunit_copy_to_kvec(struct kunit *test) ...@@ -139,7 +139,7 @@ static void __init iov_kunit_copy_to_kvec(struct kunit *test)
return; return;
} }
KUNIT_SUCCEED(); KUNIT_SUCCEED(test);
} }
/* /*
...@@ -194,7 +194,7 @@ static void __init iov_kunit_copy_from_kvec(struct kunit *test) ...@@ -194,7 +194,7 @@ static void __init iov_kunit_copy_from_kvec(struct kunit *test)
return; return;
} }
KUNIT_SUCCEED(); KUNIT_SUCCEED(test);
} }
struct bvec_test_range { struct bvec_test_range {
...@@ -302,7 +302,7 @@ static void __init iov_kunit_copy_to_bvec(struct kunit *test) ...@@ -302,7 +302,7 @@ static void __init iov_kunit_copy_to_bvec(struct kunit *test)
return; return;
} }
KUNIT_SUCCEED(); KUNIT_SUCCEED(test);
} }
/* /*
...@@ -359,7 +359,7 @@ static void __init iov_kunit_copy_from_bvec(struct kunit *test) ...@@ -359,7 +359,7 @@ static void __init iov_kunit_copy_from_bvec(struct kunit *test)
return; return;
} }
KUNIT_SUCCEED(); KUNIT_SUCCEED(test);
} }
static void iov_kunit_destroy_xarray(void *data) static void iov_kunit_destroy_xarray(void *data)
...@@ -453,7 +453,7 @@ static void __init iov_kunit_copy_to_xarray(struct kunit *test) ...@@ -453,7 +453,7 @@ static void __init iov_kunit_copy_to_xarray(struct kunit *test)
return; return;
} }
KUNIT_SUCCEED(); KUNIT_SUCCEED(test);
} }
/* /*
...@@ -516,7 +516,7 @@ static void __init iov_kunit_copy_from_xarray(struct kunit *test) ...@@ -516,7 +516,7 @@ static void __init iov_kunit_copy_from_xarray(struct kunit *test)
return; return;
} }
KUNIT_SUCCEED(); KUNIT_SUCCEED(test);
} }
/* /*
...@@ -596,7 +596,7 @@ static void __init iov_kunit_extract_pages_kvec(struct kunit *test) ...@@ -596,7 +596,7 @@ static void __init iov_kunit_extract_pages_kvec(struct kunit *test)
stop: stop:
KUNIT_EXPECT_EQ(test, size, 0); KUNIT_EXPECT_EQ(test, size, 0);
KUNIT_EXPECT_EQ(test, iter.count, 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) ...@@ -674,7 +674,7 @@ static void __init iov_kunit_extract_pages_bvec(struct kunit *test)
stop: stop:
KUNIT_EXPECT_EQ(test, size, 0); KUNIT_EXPECT_EQ(test, size, 0);
KUNIT_EXPECT_EQ(test, iter.count, 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) ...@@ -753,7 +753,7 @@ static void __init iov_kunit_extract_pages_xarray(struct kunit *test)
} }
stop: stop:
KUNIT_SUCCEED(); KUNIT_SUCCEED(test);
} }
static struct kunit_case __refdata iov_kunit_cases[] = { static struct kunit_case __refdata iov_kunit_cases[] = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment