diff options
| author | Gabriele Monaco <gmonaco@redhat.com> | 2026-07-23 09:45:31 +0200 |
|---|---|---|
| committer | Gabriele Monaco <gmonaco@redhat.com> | 2026-07-31 16:27:46 +0200 |
| commit | 51f3fe704a880c7061057d9b22ada8964bc4c9de (patch) | |
| tree | 58885868c5fddfa53f9b4f10aaa1831469bee4fb /kernel | |
| parent | cf8f191c06546dff223df12010d4a21f7b631ae3 (diff) | |
rv: Add KUnit tests for some LTL monitors
Validate the functionality of LTL monitors by injecting events in a
controlled environment (KUnit) and expecting reactions, just like it is
done in DA monitors.
Reviewed-by: Nam Cao <namcao@linutronix.de>
Link: https://lore.kernel.org/r/20260723074534.43521-15-gmonaco@redhat.com
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/trace/rv/monitors/pagefault/pagefault.c | 12 | ||||
| -rw-r--r-- | kernel/trace/rv/monitors/pagefault/pagefault_kunit.c | 34 | ||||
| -rw-r--r-- | kernel/trace/rv/monitors/pagefault/pagefault_kunit.h | 24 | ||||
| -rw-r--r-- | kernel/trace/rv/monitors/sleep/sleep.c | 18 | ||||
| -rw-r--r-- | kernel/trace/rv/monitors/sleep/sleep_kunit.c | 59 | ||||
| -rw-r--r-- | kernel/trace/rv/monitors/sleep/sleep_kunit.h | 29 | ||||
| -rw-r--r-- | kernel/trace/rv/rv_monitors_test.c | 4 |
7 files changed, 180 insertions, 0 deletions
diff --git a/kernel/trace/rv/monitors/pagefault/pagefault.c b/kernel/trace/rv/monitors/pagefault/pagefault.c index e52500fd2de0..c599fc19fc88 100644 --- a/kernel/trace/rv/monitors/pagefault/pagefault.c +++ b/kernel/trace/rv/monitors/pagefault/pagefault.c @@ -86,3 +86,15 @@ module_exit(unregister_pagefault); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Nam Cao <namcao@linutronix.de>"); MODULE_DESCRIPTION("pagefault: Monitor that RT tasks do not raise page faults"); + +#if IS_ENABLED(CONFIG_RV_MONITORS_KUNIT_TEST) +#include <kunit/visibility.h> +#include "pagefault_kunit.h" + +const struct rv_pagefault_ops rv_pagefault_ops = { + .mon = RV_MON_OPS_INIT(), + .handle_page_fault = handle_page_fault, + .handle_task_newtask = handle_task_newtask, +}; +EXPORT_SYMBOL_IF_KUNIT(rv_pagefault_ops); +#endif diff --git a/kernel/trace/rv/monitors/pagefault/pagefault_kunit.c b/kernel/trace/rv/monitors/pagefault/pagefault_kunit.c new file mode 100644 index 000000000000..06369960b008 --- /dev/null +++ b/kernel/trace/rv/monitors/pagefault/pagefault_kunit.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/kernel.h> +#include <linux/rv.h> +#include <rv/kunit.h> +#include <linux/sched/deadline.h> +#include <linux/sched/rt.h> +#include "pagefault_kunit.h" + +#if IS_REACHABLE(CONFIG_RV_MON_PAGEFAULT) + +static void rv_test_pagefault(struct kunit *test) +{ + struct task_struct *target = rv_kunit_alloc_mock_task(test); + struct rv_kunit_ctx *ctx = test->priv; + + prepare_test(test, &rv_pagefault_ops.mon); + + /* Initial pagefault when non-RT to start the model without failure */ + target->policy = SCHED_NORMAL; + target->prio = MAX_RT_PRIO + 20; + rv_pagefault_ops.handle_task_newtask(NULL, target, 0); + rv_mock_current(target); + rv_pagefault_ops.handle_page_fault(NULL, 0, NULL, 0); + + /* RT task has a page fault */ + target->policy = SCHED_FIFO; + target->prio = MAX_RT_PRIO - 1; + RV_KUNIT_EXPECT_REACTION_HERE(test, ctx) + rv_pagefault_ops.handle_page_fault(NULL, 0, NULL, 0); +} + +#else +#define rv_test_pagefault rv_test_stub +#endif diff --git a/kernel/trace/rv/monitors/pagefault/pagefault_kunit.h b/kernel/trace/rv/monitors/pagefault/pagefault_kunit.h new file mode 100644 index 000000000000..2f9652f08b3f --- /dev/null +++ b/kernel/trace/rv/monitors/pagefault/pagefault_kunit.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Automatically generated by rvgen kunit. + * May need manual intervention for function prototypes that couldn't be + * found (e.g. are in another file) or variables to be exported. + */ + +#ifndef __PAGEFAULT_KUNIT_H +#define __PAGEFAULT_KUNIT_H + +#if IS_ENABLED(CONFIG_RV_MONITORS_KUNIT_TEST) + +#include <linux/rv.h> +#include <rv/kunit.h> + +extern const struct rv_pagefault_ops { + struct rv_kunit_mon mon; + void (*handle_page_fault)(void *data, unsigned long address, struct pt_regs *regs, + unsigned long error_code); + void (*handle_task_newtask)(void *data, struct task_struct *task, u64 flags); +} rv_pagefault_ops; +#endif + +#endif /* __PAGEFAULT_KUNIT_H */ diff --git a/kernel/trace/rv/monitors/sleep/sleep.c b/kernel/trace/rv/monitors/sleep/sleep.c index a1b569a4b183..b82537251e09 100644 --- a/kernel/trace/rv/monitors/sleep/sleep.c +++ b/kernel/trace/rv/monitors/sleep/sleep.c @@ -208,3 +208,21 @@ module_exit(unregister_sleep); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Nam Cao <namcao@linutronix.de>"); MODULE_DESCRIPTION("sleep: Monitor that RT tasks do not undesirably sleep"); + +#if IS_ENABLED(CONFIG_RV_MONITORS_KUNIT_TEST) +#include <kunit/visibility.h> +#include "sleep_kunit.h" + +const struct rv_sleep_ops rv_sleep_ops = { + .mon = RV_MON_OPS_INIT(), + .handle_sched_waking = handle_sched_waking, + .handle_sched_exit = handle_sched_exit, + .handle_sched_set_state = handle_sched_set_state, + .handle_contention_begin = handle_contention_begin, + .handle_contention_end = handle_contention_end, + .handle_sys_enter = handle_sys_enter, + .handle_sys_exit = handle_sys_exit, + .handle_task_newtask = handle_task_newtask, +}; +EXPORT_SYMBOL_IF_KUNIT(rv_sleep_ops); +#endif diff --git a/kernel/trace/rv/monitors/sleep/sleep_kunit.c b/kernel/trace/rv/monitors/sleep/sleep_kunit.c new file mode 100644 index 000000000000..17df5baf1ec2 --- /dev/null +++ b/kernel/trace/rv/monitors/sleep/sleep_kunit.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/kernel.h> +#include <linux/rv.h> +#include <rv/kunit.h> +#include <trace/events/syscalls.h> +#include <trace/events/sched.h> +#include <uapi/linux/futex.h> +#include "sleep_kunit.h" + +#if IS_REACHABLE(CONFIG_RV_MON_SLEEP) + +static void rv_test_sleep(struct kunit *test) +{ + struct task_struct *target = rv_kunit_alloc_mock_task(test); + struct task_struct *other = rv_kunit_alloc_mock_task(test); + struct rv_kunit_ctx *ctx = test->priv; + unsigned long args[6] = {0}; + struct pt_regs regs = {0}; + + prepare_test(test, &rv_sleep_ops.mon); + target->policy = SCHED_FIFO; + target->prio = MAX_RT_PRIO - 2; + other->policy = SCHED_FIFO; + other->prio = MAX_RT_PRIO - 1; + rv_sleep_ops.handle_task_newtask(NULL, target, 0); + + /* RT task sleeps on a non RT-friendly nanosleep */ + rv_mock_current(target); + args[0] = CLOCK_REALTIME; + syscall_set_arguments(target, ®s, args); +#ifdef __NR_clock_nanosleep + rv_sleep_ops.handle_sys_enter(NULL, ®s, __NR_clock_nanosleep); +#elif defined(__NR_clock_nanosleep_time64) + rv_sleep_ops.handle_sys_enter(NULL, ®s, __NR_clock_nanosleep_time64); +#endif + RV_KUNIT_EXPECT_REACTION_HERE(test, ctx) + rv_sleep_ops.handle_sched_set_state(NULL, target, TASK_INTERRUPTIBLE); + rv_sleep_ops.handle_sys_exit(NULL, NULL, 0); + + /* RT task woken up by lower priority task */ + args[1] = FUTEX_WAIT; + syscall_set_arguments(target, ®s, args); + rv_mock_current(target); +#ifdef __NR_futex + rv_sleep_ops.handle_sys_enter(NULL, ®s, __NR_futex); +#elif defined(__NR_futex_time64) + rv_sleep_ops.handle_sys_enter(NULL, ®s, __NR_futex_time64); +#endif + rv_sleep_ops.handle_sched_set_state(NULL, target, TASK_INTERRUPTIBLE); + rv_mock_current(other); + rv_sleep_ops.handle_sched_waking(NULL, target); + rv_mock_current(target); + RV_KUNIT_EXPECT_REACTION_HERE(test, ctx) + rv_sleep_ops.handle_sched_exit(NULL, true); +} + +#else +#define rv_test_sleep rv_test_stub +#endif diff --git a/kernel/trace/rv/monitors/sleep/sleep_kunit.h b/kernel/trace/rv/monitors/sleep/sleep_kunit.h new file mode 100644 index 000000000000..3ebf8d2699f2 --- /dev/null +++ b/kernel/trace/rv/monitors/sleep/sleep_kunit.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Automatically generated by rvgen kunit. + * May need manual intervention for function prototypes that couldn't be + * found (e.g. are in another file) or variables to be exported. + */ + +#ifndef __SLEEP_KUNIT_H +#define __SLEEP_KUNIT_H + +#if IS_ENABLED(CONFIG_RV_MONITORS_KUNIT_TEST) + +#include <linux/rv.h> +#include <rv/kunit.h> + +extern const struct rv_sleep_ops { + struct rv_kunit_mon mon; + void (*handle_sched_waking)(void *data, struct task_struct *task); + void (*handle_sched_exit)(void *data, bool is_switch); + void (*handle_sched_set_state)(void *data, struct task_struct *task, int state); + void (*handle_contention_begin)(void *data, void *lock, unsigned int flags); + void (*handle_contention_end)(void *data, void *lock, int ret); + void (*handle_sys_enter)(void *data, struct pt_regs *regs, long id); + void (*handle_sys_exit)(void *data, struct pt_regs *regs, long ret); + void (*handle_task_newtask)(void *data, struct task_struct *task, u64 flags); +} rv_sleep_ops; +#endif + +#endif /* __SLEEP_KUNIT_H */ diff --git a/kernel/trace/rv/rv_monitors_test.c b/kernel/trace/rv/rv_monitors_test.c index e58bd677ae0b..3ad11195e664 100644 --- a/kernel/trace/rv/rv_monitors_test.c +++ b/kernel/trace/rv/rv_monitors_test.c @@ -151,6 +151,8 @@ static void rv_test_dummy(struct kunit *test) #include "monitors/sts/sts_kunit.c" #include "monitors/opid/opid_kunit.c" #include "monitors/nomiss/nomiss_kunit.c" +#include "monitors/pagefault/pagefault_kunit.c" +#include "monitors/sleep/sleep_kunit.c" static struct kunit_case rv_mon_test_cases[] = { KUNIT_CASE(rv_test_dummy), @@ -159,6 +161,8 @@ static struct kunit_case rv_mon_test_cases[] = { KUNIT_CASE(rv_test_sts), KUNIT_CASE(rv_test_opid), KUNIT_CASE(rv_test_nomiss), + KUNIT_CASE(rv_test_pagefault), + KUNIT_CASE(rv_test_sleep), {} }; |
