From 42545589e36390e74a848c517a62eafaa6b8526c Mon Sep 17 00:00:00 2001 From: Nam Cao Date: Fri, 19 Jun 2026 09:21:19 +0200 Subject: [PATCH] rv/rtapp/sleep: Make the error more informative for user The rtapp/sleep monitor detects real-time tasks which go to sleep in an real-time-unsafe manner. If this happen, the monitor triggers a trace event in the sched_wakeup tracepoint's handler. However, the invoking context of that trace event is not the most informative, because of the stack trace of that event is the wakeup's code path which is not very helpful: 74.669317: rv:error_sleep: condvar[254]: violation detected ltl_validate+0x345 ([kernel.kallsyms]) handle_sched_wakeup+0x34 ([kernel.kallsyms]) ttwu_do_activate+0xff ([kernel.kallsyms]) sched_ttwu_pending+0x104 ([kernel.kallsyms]) __flush_smp_call_function_queue+0x15b ([kernel.kallsyms]) __sysvec_call_function_single+0x18 ([kernel.kallsyms]) sysvec_call_function_single+0x66 ([kernel.kallsyms]) asm_sysvec_call_function_single+0x1a ([kernel.kallsyms]) pv_native_safe_halt+0xf ([kernel.kallsyms]) default_idle+0x9 ([kernel.kallsyms]) default_idle_call+0x33 ([kernel.kallsyms]) do_idle+0x234 ([kernel.kallsyms]) cpu_startup_entry+0x24 ([kernel.kallsyms]) start_secondary+0xf8 ([kernel.kallsyms]) common_startup_64+0x13e ([kernel.kallsyms]) What would be much more valuable is the stack trace of the task itself. Instead of using the sched_wakeup tracepoint, use the sched_exit tracepoint. This makes the event happen in the task's context, making the stack trace far more informative for user: rv:error_sleep: condvar[254]: violation detected ltl_validate+0x345 ([kernel.kallsyms]) handle_sched_exit+0x39 ([kernel.kallsyms]) __schedule+0x80f ([kernel.kallsyms]) schedule+0x22 ([kernel.kallsyms]) futex_do_wait+0x33 ([kernel.kallsyms]) __futex_wait+0x8c ([kernel.kallsyms]) futex_wait+0x73 ([kernel.kallsyms]) do_futex+0xc6 ([kernel.kallsyms]) __x64_sys_futex+0x121 ([kernel.kallsyms]) do_syscall_64+0xf3 ([kernel.kallsyms]) entry_SYSCALL_64_after_hwframe+0x77 ([kernel.kallsyms]) __futex_abstimed_wait_common64+0xc6 (inlined) __futex_abstimed_wait_common+0xc6 (/usr/lib/x86_64-linux-gnu/libc.so.6) Signed-off-by: Nam Cao Reviewed-by: Gabriele Monaco Link: https://lore.kernel.org/r/d97b4b5c476e5792b6875ec9bbf8dc214f999516.1781852967.git.namcao@linutronix.de Signed-off-by: Gabriele Monaco --- Documentation/trace/rv/monitor_rtapp.rst | 2 +- kernel/trace/rv/monitors/sleep/sleep.c | 10 +++++----- kernel/trace/rv/monitors/sleep/sleep.h | 14 +++++++------- tools/verification/models/rtapp/sleep.ltl | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Documentation/trace/rv/monitor_rtapp.rst b/Documentation/trace/rv/monitor_rtapp.rst index c8104eda924a..01656bf7080a 100644 --- a/Documentation/trace/rv/monitor_rtapp.rst +++ b/Documentation/trace/rv/monitor_rtapp.rst @@ -95,7 +95,7 @@ The monitor's specification is:: RULE = always ((RT and SLEEP) imply (RT_FRIENDLY_SLEEP or ALLOWLIST)) RT_FRIENDLY_SLEEP = (RT_VALID_SLEEP_REASON or KERNEL_THREAD) - and ((not WAKE) until RT_FRIENDLY_WAKE) + and ((not SCHEDULE_IN) until RT_FRIENDLY_WAKE) RT_VALID_SLEEP_REASON = FUTEX_WAIT or RT_FRIENDLY_NANOSLEEP diff --git a/kernel/trace/rv/monitors/sleep/sleep.c b/kernel/trace/rv/monitors/sleep/sleep.c index 8dfe5ec13e19..d6b677fab8f8 100644 --- a/kernel/trace/rv/monitors/sleep/sleep.c +++ b/kernel/trace/rv/monitors/sleep/sleep.c @@ -36,7 +36,7 @@ static void ltl_atoms_fetch(struct task_struct *task, struct ltl_monitor *mon) static void ltl_atoms_init(struct task_struct *task, struct ltl_monitor *mon, bool task_creation) { ltl_atom_set(mon, LTL_SLEEP, false); - ltl_atom_set(mon, LTL_WAKE, false); + ltl_atom_set(mon, LTL_SCHEDULE_IN, false); ltl_atom_set(mon, LTL_ABORT_SLEEP, false); ltl_atom_set(mon, LTL_WOKEN_BY_HARDIRQ, false); ltl_atom_set(mon, LTL_WOKEN_BY_NMI, false); @@ -92,9 +92,9 @@ static void handle_sched_set_state(void *data, struct task_struct *task, int sta ltl_atom_pulse(task, LTL_ABORT_SLEEP, true); } -static void handle_sched_wakeup(void *data, struct task_struct *task) +static void handle_sched_exit(void *data, bool is_switch) { - ltl_atom_pulse(task, LTL_WAKE, true); + ltl_atom_pulse(current, LTL_SCHEDULE_IN, true); } static void handle_sched_waking(void *data, struct task_struct *task) @@ -200,7 +200,7 @@ static int enable_sleep(void) return retval; rv_attach_trace_probe("rtapp_sleep", sched_waking, handle_sched_waking); - rv_attach_trace_probe("rtapp_sleep", sched_wakeup, handle_sched_wakeup); + rv_attach_trace_probe("rtapp_sleep", sched_exit_tp, handle_sched_exit); rv_attach_trace_probe("rtapp_sleep", sched_set_state_tp, handle_sched_set_state); rv_attach_trace_probe("rtapp_sleep", contention_begin, handle_contention_begin); rv_attach_trace_probe("rtapp_sleep", contention_end, handle_contention_end); @@ -213,7 +213,7 @@ static int enable_sleep(void) static void disable_sleep(void) { rv_detach_trace_probe("rtapp_sleep", sched_waking, handle_sched_waking); - rv_detach_trace_probe("rtapp_sleep", sched_wakeup, handle_sched_wakeup); + rv_detach_trace_probe("rtapp_sleep", sched_exit_tp, handle_sched_exit); rv_detach_trace_probe("rtapp_sleep", sched_set_state_tp, handle_sched_set_state); rv_detach_trace_probe("rtapp_sleep", contention_begin, handle_contention_begin); rv_detach_trace_probe("rtapp_sleep", contention_end, handle_contention_end); diff --git a/kernel/trace/rv/monitors/sleep/sleep.h b/kernel/trace/rv/monitors/sleep/sleep.h index 95dc2727c059..403dc2852c52 100644 --- a/kernel/trace/rv/monitors/sleep/sleep.h +++ b/kernel/trace/rv/monitors/sleep/sleep.h @@ -24,10 +24,10 @@ enum ltl_atom { LTL_NANOSLEEP_CLOCK_TAI, LTL_NANOSLEEP_TIMER_ABSTIME, LTL_RT, + LTL_SCHEDULE_IN, LTL_SLEEP, LTL_TASK_IS_MIGRATION, LTL_TASK_IS_RCU, - LTL_WAKE, LTL_WOKEN_BY_EQUAL_OR_HIGHER_PRIO, LTL_WOKEN_BY_HARDIRQ, LTL_WOKEN_BY_NMI, @@ -50,10 +50,10 @@ static const char *ltl_atom_str(enum ltl_atom atom) "na_cl_ta", "na_ti_ab", "rt", - "sl", + "sch_in", + "sle", "ta_mi", "ta_rc", - "wak", "wo_eq_hi_pr", "wo_ha", "wo_nm", @@ -81,10 +81,10 @@ static void ltl_start(struct task_struct *task, struct ltl_monitor *mon) bool woken_by_hardirq = test_bit(LTL_WOKEN_BY_HARDIRQ, mon->atoms); bool woken_by_equal_or_higher_prio = test_bit(LTL_WOKEN_BY_EQUAL_OR_HIGHER_PRIO, mon->atoms); - bool wake = test_bit(LTL_WAKE, mon->atoms); bool task_is_rcu = test_bit(LTL_TASK_IS_RCU, mon->atoms); bool task_is_migration = test_bit(LTL_TASK_IS_MIGRATION, mon->atoms); bool sleep = test_bit(LTL_SLEEP, mon->atoms); + bool schedule_in = test_bit(LTL_SCHEDULE_IN, mon->atoms); bool rt = test_bit(LTL_RT, mon->atoms); bool nanosleep_timer_abstime = test_bit(LTL_NANOSLEEP_TIMER_ABSTIME, mon->atoms); bool nanosleep_clock_tai = test_bit(LTL_NANOSLEEP_CLOCK_TAI, mon->atoms); @@ -104,7 +104,7 @@ static void ltl_start(struct task_struct *task, struct ltl_monitor *mon) bool val35 = woken_by_nmi || val34; bool val36 = woken_by_hardirq || val35; bool val14 = woken_by_equal_or_higher_prio || val36; - bool val13 = !wake; + bool val13 = !schedule_in; bool val26 = nanosleep_clock_monotonic || nanosleep_clock_tai; bool val27 = nanosleep_timer_abstime && val26; bool val18 = clock_nanosleep && val27; @@ -132,10 +132,10 @@ ltl_possible_next_states(struct ltl_monitor *mon, unsigned int state, unsigned l bool woken_by_hardirq = test_bit(LTL_WOKEN_BY_HARDIRQ, mon->atoms); bool woken_by_equal_or_higher_prio = test_bit(LTL_WOKEN_BY_EQUAL_OR_HIGHER_PRIO, mon->atoms); - bool wake = test_bit(LTL_WAKE, mon->atoms); bool task_is_rcu = test_bit(LTL_TASK_IS_RCU, mon->atoms); bool task_is_migration = test_bit(LTL_TASK_IS_MIGRATION, mon->atoms); bool sleep = test_bit(LTL_SLEEP, mon->atoms); + bool schedule_in = test_bit(LTL_SCHEDULE_IN, mon->atoms); bool rt = test_bit(LTL_RT, mon->atoms); bool nanosleep_timer_abstime = test_bit(LTL_NANOSLEEP_TIMER_ABSTIME, mon->atoms); bool nanosleep_clock_tai = test_bit(LTL_NANOSLEEP_CLOCK_TAI, mon->atoms); @@ -155,7 +155,7 @@ ltl_possible_next_states(struct ltl_monitor *mon, unsigned int state, unsigned l bool val35 = woken_by_nmi || val34; bool val36 = woken_by_hardirq || val35; bool val14 = woken_by_equal_or_higher_prio || val36; - bool val13 = !wake; + bool val13 = !schedule_in; bool val26 = nanosleep_clock_monotonic || nanosleep_clock_tai; bool val27 = nanosleep_timer_abstime && val26; bool val18 = clock_nanosleep && val27; diff --git a/tools/verification/models/rtapp/sleep.ltl b/tools/verification/models/rtapp/sleep.ltl index 6f26c4810f78..464c84b9df87 100644 --- a/tools/verification/models/rtapp/sleep.ltl +++ b/tools/verification/models/rtapp/sleep.ltl @@ -1,7 +1,7 @@ RULE = always ((RT and SLEEP) imply (RT_FRIENDLY_SLEEP or ALLOWLIST)) RT_FRIENDLY_SLEEP = (RT_VALID_SLEEP_REASON or KERNEL_THREAD) - and ((not WAKE) until RT_FRIENDLY_WAKE) + and ((not SCHEDULE_IN) until RT_FRIENDLY_WAKE) RT_VALID_SLEEP_REASON = FUTEX_WAIT or RT_FRIENDLY_NANOSLEEP