1*f74f8bb2SNam Cao // SPDX-License-Identifier: GPL-2.0 2*f74f8bb2SNam Cao #include <linux/ftrace.h> 3*f74f8bb2SNam Cao #include <linux/tracepoint.h> 4*f74f8bb2SNam Cao #include <linux/init.h> 5*f74f8bb2SNam Cao #include <linux/irqflags.h> 6*f74f8bb2SNam Cao #include <linux/kernel.h> 7*f74f8bb2SNam Cao #include <linux/module.h> 8*f74f8bb2SNam Cao #include <linux/rv.h> 9*f74f8bb2SNam Cao #include <linux/sched/deadline.h> 10*f74f8bb2SNam Cao #include <linux/sched/rt.h> 11*f74f8bb2SNam Cao #include <rv/instrumentation.h> 12*f74f8bb2SNam Cao 13*f74f8bb2SNam Cao #define MODULE_NAME "sleep" 14*f74f8bb2SNam Cao 15*f74f8bb2SNam Cao #include <trace/events/syscalls.h> 16*f74f8bb2SNam Cao #include <trace/events/sched.h> 17*f74f8bb2SNam Cao #include <trace/events/lock.h> 18*f74f8bb2SNam Cao #include <uapi/linux/futex.h> 19*f74f8bb2SNam Cao #include <rv_trace.h> 20*f74f8bb2SNam Cao #include <monitors/rtapp/rtapp.h> 21*f74f8bb2SNam Cao 22*f74f8bb2SNam Cao #include "sleep.h" 23*f74f8bb2SNam Cao #include <rv/ltl_monitor.h> 24*f74f8bb2SNam Cao 25*f74f8bb2SNam Cao static void ltl_atoms_fetch(struct task_struct *task, struct ltl_monitor *mon) 26*f74f8bb2SNam Cao { 27*f74f8bb2SNam Cao /* 28*f74f8bb2SNam Cao * This includes "actual" real-time tasks and also PI-boosted 29*f74f8bb2SNam Cao * tasks. A task being PI-boosted means it is blocking an "actual" 30*f74f8bb2SNam Cao * real-task, therefore it should also obey the monitor's rule, 31*f74f8bb2SNam Cao * otherwise the "actual" real-task may be delayed. 32*f74f8bb2SNam Cao */ 33*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_RT, rt_or_dl_task(task)); 34*f74f8bb2SNam Cao } 35*f74f8bb2SNam Cao 36*f74f8bb2SNam Cao static void ltl_atoms_init(struct task_struct *task, struct ltl_monitor *mon, bool task_creation) 37*f74f8bb2SNam Cao { 38*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_SLEEP, false); 39*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_WAKE, false); 40*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_ABORT_SLEEP, false); 41*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_WOKEN_BY_HARDIRQ, false); 42*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_WOKEN_BY_NMI, false); 43*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_WOKEN_BY_EQUAL_OR_HIGHER_PRIO, false); 44*f74f8bb2SNam Cao 45*f74f8bb2SNam Cao if (task_creation) { 46*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_KTHREAD_SHOULD_STOP, false); 47*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_MONOTONIC, false); 48*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_TAI, false); 49*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_NANOSLEEP_TIMER_ABSTIME, false); 50*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_CLOCK_NANOSLEEP, false); 51*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_FUTEX_WAIT, false); 52*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_FUTEX_LOCK_PI, false); 53*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_BLOCK_ON_RT_MUTEX, false); 54*f74f8bb2SNam Cao } 55*f74f8bb2SNam Cao 56*f74f8bb2SNam Cao if (task->flags & PF_KTHREAD) { 57*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_KERNEL_THREAD, true); 58*f74f8bb2SNam Cao 59*f74f8bb2SNam Cao /* kernel tasks do not do syscall */ 60*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_FUTEX_WAIT, false); 61*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_FUTEX_LOCK_PI, false); 62*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_MONOTONIC, false); 63*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_TAI, false); 64*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_NANOSLEEP_TIMER_ABSTIME, false); 65*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_CLOCK_NANOSLEEP, false); 66*f74f8bb2SNam Cao 67*f74f8bb2SNam Cao if (strstarts(task->comm, "migration/")) 68*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_TASK_IS_MIGRATION, true); 69*f74f8bb2SNam Cao else 70*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_TASK_IS_MIGRATION, false); 71*f74f8bb2SNam Cao 72*f74f8bb2SNam Cao if (strstarts(task->comm, "rcu")) 73*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_TASK_IS_RCU, true); 74*f74f8bb2SNam Cao else 75*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_TASK_IS_RCU, false); 76*f74f8bb2SNam Cao } else { 77*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_KTHREAD_SHOULD_STOP, false); 78*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_KERNEL_THREAD, false); 79*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_TASK_IS_RCU, false); 80*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_TASK_IS_MIGRATION, false); 81*f74f8bb2SNam Cao } 82*f74f8bb2SNam Cao 83*f74f8bb2SNam Cao } 84*f74f8bb2SNam Cao 85*f74f8bb2SNam Cao static void handle_sched_set_state(void *data, struct task_struct *task, int state) 86*f74f8bb2SNam Cao { 87*f74f8bb2SNam Cao if (state & TASK_INTERRUPTIBLE) 88*f74f8bb2SNam Cao ltl_atom_pulse(task, LTL_SLEEP, true); 89*f74f8bb2SNam Cao else if (state == TASK_RUNNING) 90*f74f8bb2SNam Cao ltl_atom_pulse(task, LTL_ABORT_SLEEP, true); 91*f74f8bb2SNam Cao } 92*f74f8bb2SNam Cao 93*f74f8bb2SNam Cao static void handle_sched_wakeup(void *data, struct task_struct *task) 94*f74f8bb2SNam Cao { 95*f74f8bb2SNam Cao ltl_atom_pulse(task, LTL_WAKE, true); 96*f74f8bb2SNam Cao } 97*f74f8bb2SNam Cao 98*f74f8bb2SNam Cao static void handle_sched_waking(void *data, struct task_struct *task) 99*f74f8bb2SNam Cao { 100*f74f8bb2SNam Cao if (this_cpu_read(hardirq_context)) { 101*f74f8bb2SNam Cao ltl_atom_pulse(task, LTL_WOKEN_BY_HARDIRQ, true); 102*f74f8bb2SNam Cao } else if (in_task()) { 103*f74f8bb2SNam Cao if (current->prio <= task->prio) 104*f74f8bb2SNam Cao ltl_atom_pulse(task, LTL_WOKEN_BY_EQUAL_OR_HIGHER_PRIO, true); 105*f74f8bb2SNam Cao } else if (in_nmi()) { 106*f74f8bb2SNam Cao ltl_atom_pulse(task, LTL_WOKEN_BY_NMI, true); 107*f74f8bb2SNam Cao } 108*f74f8bb2SNam Cao } 109*f74f8bb2SNam Cao 110*f74f8bb2SNam Cao static void handle_contention_begin(void *data, void *lock, unsigned int flags) 111*f74f8bb2SNam Cao { 112*f74f8bb2SNam Cao if (flags & LCB_F_RT) 113*f74f8bb2SNam Cao ltl_atom_update(current, LTL_BLOCK_ON_RT_MUTEX, true); 114*f74f8bb2SNam Cao } 115*f74f8bb2SNam Cao 116*f74f8bb2SNam Cao static void handle_contention_end(void *data, void *lock, int ret) 117*f74f8bb2SNam Cao { 118*f74f8bb2SNam Cao ltl_atom_update(current, LTL_BLOCK_ON_RT_MUTEX, false); 119*f74f8bb2SNam Cao } 120*f74f8bb2SNam Cao 121*f74f8bb2SNam Cao static void handle_sys_enter(void *data, struct pt_regs *regs, long id) 122*f74f8bb2SNam Cao { 123*f74f8bb2SNam Cao struct ltl_monitor *mon; 124*f74f8bb2SNam Cao unsigned long args[6]; 125*f74f8bb2SNam Cao int op, cmd; 126*f74f8bb2SNam Cao 127*f74f8bb2SNam Cao mon = ltl_get_monitor(current); 128*f74f8bb2SNam Cao 129*f74f8bb2SNam Cao switch (id) { 130*f74f8bb2SNam Cao case __NR_clock_nanosleep: 131*f74f8bb2SNam Cao #ifdef __NR_clock_nanosleep_time64 132*f74f8bb2SNam Cao case __NR_clock_nanosleep_time64: 133*f74f8bb2SNam Cao #endif 134*f74f8bb2SNam Cao syscall_get_arguments(current, regs, args); 135*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_MONOTONIC, args[0] == CLOCK_MONOTONIC); 136*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_TAI, args[0] == CLOCK_TAI); 137*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_NANOSLEEP_TIMER_ABSTIME, args[1] == TIMER_ABSTIME); 138*f74f8bb2SNam Cao ltl_atom_update(current, LTL_CLOCK_NANOSLEEP, true); 139*f74f8bb2SNam Cao break; 140*f74f8bb2SNam Cao 141*f74f8bb2SNam Cao case __NR_futex: 142*f74f8bb2SNam Cao #ifdef __NR_futex_time64 143*f74f8bb2SNam Cao case __NR_futex_time64: 144*f74f8bb2SNam Cao #endif 145*f74f8bb2SNam Cao syscall_get_arguments(current, regs, args); 146*f74f8bb2SNam Cao op = args[1]; 147*f74f8bb2SNam Cao cmd = op & FUTEX_CMD_MASK; 148*f74f8bb2SNam Cao 149*f74f8bb2SNam Cao switch (cmd) { 150*f74f8bb2SNam Cao case FUTEX_LOCK_PI: 151*f74f8bb2SNam Cao case FUTEX_LOCK_PI2: 152*f74f8bb2SNam Cao ltl_atom_update(current, LTL_FUTEX_LOCK_PI, true); 153*f74f8bb2SNam Cao break; 154*f74f8bb2SNam Cao case FUTEX_WAIT: 155*f74f8bb2SNam Cao case FUTEX_WAIT_BITSET: 156*f74f8bb2SNam Cao case FUTEX_WAIT_REQUEUE_PI: 157*f74f8bb2SNam Cao ltl_atom_update(current, LTL_FUTEX_WAIT, true); 158*f74f8bb2SNam Cao break; 159*f74f8bb2SNam Cao } 160*f74f8bb2SNam Cao break; 161*f74f8bb2SNam Cao } 162*f74f8bb2SNam Cao } 163*f74f8bb2SNam Cao 164*f74f8bb2SNam Cao static void handle_sys_exit(void *data, struct pt_regs *regs, long ret) 165*f74f8bb2SNam Cao { 166*f74f8bb2SNam Cao struct ltl_monitor *mon = ltl_get_monitor(current); 167*f74f8bb2SNam Cao 168*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_FUTEX_LOCK_PI, false); 169*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_FUTEX_WAIT, false); 170*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_MONOTONIC, false); 171*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_NANOSLEEP_CLOCK_TAI, false); 172*f74f8bb2SNam Cao ltl_atom_set(mon, LTL_NANOSLEEP_TIMER_ABSTIME, false); 173*f74f8bb2SNam Cao ltl_atom_update(current, LTL_CLOCK_NANOSLEEP, false); 174*f74f8bb2SNam Cao } 175*f74f8bb2SNam Cao 176*f74f8bb2SNam Cao static void handle_kthread_stop(void *data, struct task_struct *task) 177*f74f8bb2SNam Cao { 178*f74f8bb2SNam Cao /* FIXME: this could race with other tracepoint handlers */ 179*f74f8bb2SNam Cao ltl_atom_update(task, LTL_KTHREAD_SHOULD_STOP, true); 180*f74f8bb2SNam Cao } 181*f74f8bb2SNam Cao 182*f74f8bb2SNam Cao static int enable_sleep(void) 183*f74f8bb2SNam Cao { 184*f74f8bb2SNam Cao int retval; 185*f74f8bb2SNam Cao 186*f74f8bb2SNam Cao retval = ltl_monitor_init(); 187*f74f8bb2SNam Cao if (retval) 188*f74f8bb2SNam Cao return retval; 189*f74f8bb2SNam Cao 190*f74f8bb2SNam Cao rv_attach_trace_probe("rtapp_sleep", sched_waking, handle_sched_waking); 191*f74f8bb2SNam Cao rv_attach_trace_probe("rtapp_sleep", sched_wakeup, handle_sched_wakeup); 192*f74f8bb2SNam Cao rv_attach_trace_probe("rtapp_sleep", sched_set_state_tp, handle_sched_set_state); 193*f74f8bb2SNam Cao rv_attach_trace_probe("rtapp_sleep", contention_begin, handle_contention_begin); 194*f74f8bb2SNam Cao rv_attach_trace_probe("rtapp_sleep", contention_end, handle_contention_end); 195*f74f8bb2SNam Cao rv_attach_trace_probe("rtapp_sleep", sched_kthread_stop, handle_kthread_stop); 196*f74f8bb2SNam Cao rv_attach_trace_probe("rtapp_sleep", sys_enter, handle_sys_enter); 197*f74f8bb2SNam Cao rv_attach_trace_probe("rtapp_sleep", sys_exit, handle_sys_exit); 198*f74f8bb2SNam Cao return 0; 199*f74f8bb2SNam Cao } 200*f74f8bb2SNam Cao 201*f74f8bb2SNam Cao static void disable_sleep(void) 202*f74f8bb2SNam Cao { 203*f74f8bb2SNam Cao rv_detach_trace_probe("rtapp_sleep", sched_waking, handle_sched_waking); 204*f74f8bb2SNam Cao rv_detach_trace_probe("rtapp_sleep", sched_wakeup, handle_sched_wakeup); 205*f74f8bb2SNam Cao rv_detach_trace_probe("rtapp_sleep", sched_set_state_tp, handle_sched_set_state); 206*f74f8bb2SNam Cao rv_detach_trace_probe("rtapp_sleep", contention_begin, handle_contention_begin); 207*f74f8bb2SNam Cao rv_detach_trace_probe("rtapp_sleep", contention_end, handle_contention_end); 208*f74f8bb2SNam Cao rv_detach_trace_probe("rtapp_sleep", sched_kthread_stop, handle_kthread_stop); 209*f74f8bb2SNam Cao rv_detach_trace_probe("rtapp_sleep", sys_enter, handle_sys_enter); 210*f74f8bb2SNam Cao rv_detach_trace_probe("rtapp_sleep", sys_exit, handle_sys_exit); 211*f74f8bb2SNam Cao 212*f74f8bb2SNam Cao ltl_monitor_destroy(); 213*f74f8bb2SNam Cao } 214*f74f8bb2SNam Cao 215*f74f8bb2SNam Cao static struct rv_monitor rv_sleep = { 216*f74f8bb2SNam Cao .name = "sleep", 217*f74f8bb2SNam Cao .description = "Monitor that RT tasks do not undesirably sleep", 218*f74f8bb2SNam Cao .enable = enable_sleep, 219*f74f8bb2SNam Cao .disable = disable_sleep, 220*f74f8bb2SNam Cao }; 221*f74f8bb2SNam Cao 222*f74f8bb2SNam Cao static int __init register_sleep(void) 223*f74f8bb2SNam Cao { 224*f74f8bb2SNam Cao return rv_register_monitor(&rv_sleep, &rv_rtapp); 225*f74f8bb2SNam Cao } 226*f74f8bb2SNam Cao 227*f74f8bb2SNam Cao static void __exit unregister_sleep(void) 228*f74f8bb2SNam Cao { 229*f74f8bb2SNam Cao rv_unregister_monitor(&rv_sleep); 230*f74f8bb2SNam Cao } 231*f74f8bb2SNam Cao 232*f74f8bb2SNam Cao module_init(register_sleep); 233*f74f8bb2SNam Cao module_exit(unregister_sleep); 234*f74f8bb2SNam Cao 235*f74f8bb2SNam Cao MODULE_LICENSE("GPL"); 236*f74f8bb2SNam Cao MODULE_AUTHOR("Nam Cao <namcao@linutronix.de>"); 237*f74f8bb2SNam Cao MODULE_DESCRIPTION("sleep: Monitor that RT tasks do not undesirably sleep"); 238