Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rv: Add rtapp_pagefault monitor

Userspace real-time applications may have design flaws that they raise
page faults in real-time threads, and thus have unexpected latencies.

Add an linear temporal logic monitor to detect this scenario.

Cc: John Ogness <john.ogness@linutronix.de>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Link: https://lore.kernel.org/78fea8a2de6d058241d3c6502c1a92910772b0ed.1752088709.git.namcao@linutronix.de
Reviewed-by: Gabriele Monaco <gmonaco@redhat.com>
Signed-off-by: Nam Cao <namcao@linutronix.de>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>

authored by

Nam Cao and committed by
Steven Rostedt (Google)
9162620e a37c71ca

+190
+1
kernel/trace/rv/Kconfig
··· 42 42 source "kernel/trace/rv/monitors/snep/Kconfig" 43 43 source "kernel/trace/rv/monitors/sncid/Kconfig" 44 44 source "kernel/trace/rv/monitors/rtapp/Kconfig" 45 + source "kernel/trace/rv/monitors/pagefault/Kconfig" 45 46 # Add new monitors here 46 47 47 48 config RV_REACTORS
+1
kernel/trace/rv/Makefile
··· 13 13 obj-$(CONFIG_RV_MON_SNEP) += monitors/snep/snep.o 14 14 obj-$(CONFIG_RV_MON_SNCID) += monitors/sncid/sncid.o 15 15 obj-$(CONFIG_RV_MON_RTAPP) += monitors/rtapp/rtapp.o 16 + obj-$(CONFIG_RV_MON_PAGEFAULT) += monitors/pagefault/pagefault.o 16 17 # Add new monitors here 17 18 obj-$(CONFIG_RV_REACTORS) += rv_reactors.o 18 19 obj-$(CONFIG_RV_REACT_PRINTK) += reactor_printk.o
+20
kernel/trace/rv/monitors/pagefault/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 3 + config RV_MON_PAGEFAULT 4 + depends on RV 5 + select RV_LTL_MONITOR 6 + depends on RV_MON_RTAPP 7 + depends on X86 || RISCV 8 + default y 9 + select LTL_MON_EVENTS_ID 10 + bool "pagefault monitor" 11 + help 12 + Monitor that real-time tasks do not raise page faults, causing 13 + undesirable latency. 14 + 15 + If you are developing a real-time system and not entirely sure whether 16 + the applications are designed correctly for real-time, you want to say 17 + Y here. 18 + 19 + This monitor does not affect execution speed while it is not running, 20 + therefore it is safe to enable this in production kernel.
+88
kernel/trace/rv/monitors/pagefault/pagefault.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <linux/ftrace.h> 3 + #include <linux/init.h> 4 + #include <linux/kernel.h> 5 + #include <linux/module.h> 6 + #include <linux/rv.h> 7 + #include <linux/sched/deadline.h> 8 + #include <linux/sched/rt.h> 9 + #include <linux/tracepoint.h> 10 + #include <rv/instrumentation.h> 11 + 12 + #define MODULE_NAME "pagefault" 13 + 14 + #include <rv_trace.h> 15 + #include <trace/events/exceptions.h> 16 + #include <monitors/rtapp/rtapp.h> 17 + 18 + #include "pagefault.h" 19 + #include <rv/ltl_monitor.h> 20 + 21 + static void ltl_atoms_fetch(struct task_struct *task, struct ltl_monitor *mon) 22 + { 23 + /* 24 + * This includes "actual" real-time tasks and also PI-boosted 25 + * tasks. A task being PI-boosted means it is blocking an "actual" 26 + * real-task, therefore it should also obey the monitor's rule, 27 + * otherwise the "actual" real-task may be delayed. 28 + */ 29 + ltl_atom_set(mon, LTL_RT, rt_or_dl_task(task)); 30 + } 31 + 32 + static void ltl_atoms_init(struct task_struct *task, struct ltl_monitor *mon, bool task_creation) 33 + { 34 + if (task_creation) 35 + ltl_atom_set(mon, LTL_PAGEFAULT, false); 36 + } 37 + 38 + static void handle_page_fault(void *data, unsigned long address, struct pt_regs *regs, 39 + unsigned long error_code) 40 + { 41 + ltl_atom_pulse(current, LTL_PAGEFAULT, true); 42 + } 43 + 44 + static int enable_pagefault(void) 45 + { 46 + int retval; 47 + 48 + retval = ltl_monitor_init(); 49 + if (retval) 50 + return retval; 51 + 52 + rv_attach_trace_probe("rtapp_pagefault", page_fault_kernel, handle_page_fault); 53 + rv_attach_trace_probe("rtapp_pagefault", page_fault_user, handle_page_fault); 54 + 55 + return 0; 56 + } 57 + 58 + static void disable_pagefault(void) 59 + { 60 + rv_detach_trace_probe("rtapp_pagefault", page_fault_kernel, handle_page_fault); 61 + rv_detach_trace_probe("rtapp_pagefault", page_fault_user, handle_page_fault); 62 + 63 + ltl_monitor_destroy(); 64 + } 65 + 66 + static struct rv_monitor rv_pagefault = { 67 + .name = "pagefault", 68 + .description = "Monitor that RT tasks do not raise page faults", 69 + .enable = enable_pagefault, 70 + .disable = disable_pagefault, 71 + }; 72 + 73 + static int __init register_pagefault(void) 74 + { 75 + return rv_register_monitor(&rv_pagefault, &rv_rtapp); 76 + } 77 + 78 + static void __exit unregister_pagefault(void) 79 + { 80 + rv_unregister_monitor(&rv_pagefault); 81 + } 82 + 83 + module_init(register_pagefault); 84 + module_exit(unregister_pagefault); 85 + 86 + MODULE_LICENSE("GPL"); 87 + MODULE_AUTHOR("Nam Cao <namcao@linutronix.de>"); 88 + MODULE_DESCRIPTION("pagefault: Monitor that RT tasks do not raise page faults");
+64
kernel/trace/rv/monitors/pagefault/pagefault.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + /* 4 + * C implementation of Buchi automaton, automatically generated by 5 + * tools/verification/rvgen from the linear temporal logic specification. 6 + * For further information, see kernel documentation: 7 + * Documentation/trace/rv/linear_temporal_logic.rst 8 + */ 9 + 10 + #include <linux/rv.h> 11 + 12 + #define MONITOR_NAME pagefault 13 + 14 + enum ltl_atom { 15 + LTL_PAGEFAULT, 16 + LTL_RT, 17 + LTL_NUM_ATOM 18 + }; 19 + static_assert(LTL_NUM_ATOM <= RV_MAX_LTL_ATOM); 20 + 21 + static const char *ltl_atom_str(enum ltl_atom atom) 22 + { 23 + static const char *const names[] = { 24 + "pa", 25 + "rt", 26 + }; 27 + 28 + return names[atom]; 29 + } 30 + 31 + enum ltl_buchi_state { 32 + S0, 33 + RV_NUM_BA_STATES 34 + }; 35 + static_assert(RV_NUM_BA_STATES <= RV_MAX_BA_STATES); 36 + 37 + static void ltl_start(struct task_struct *task, struct ltl_monitor *mon) 38 + { 39 + bool pagefault = test_bit(LTL_PAGEFAULT, mon->atoms); 40 + bool val3 = !pagefault; 41 + bool rt = test_bit(LTL_RT, mon->atoms); 42 + bool val1 = !rt; 43 + bool val4 = val1 || val3; 44 + 45 + if (val4) 46 + __set_bit(S0, mon->states); 47 + } 48 + 49 + static void 50 + ltl_possible_next_states(struct ltl_monitor *mon, unsigned int state, unsigned long *next) 51 + { 52 + bool pagefault = test_bit(LTL_PAGEFAULT, mon->atoms); 53 + bool val3 = !pagefault; 54 + bool rt = test_bit(LTL_RT, mon->atoms); 55 + bool val1 = !rt; 56 + bool val4 = val1 || val3; 57 + 58 + switch (state) { 59 + case S0: 60 + if (val4) 61 + __set_bit(S0, next); 62 + break; 63 + } 64 + }
+14
kernel/trace/rv/monitors/pagefault/pagefault_trace.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + /* 4 + * Snippet to be included in rv_trace.h 5 + */ 6 + 7 + #ifdef CONFIG_RV_MON_PAGEFAULT 8 + DEFINE_EVENT(event_ltl_monitor_id, event_pagefault, 9 + TP_PROTO(struct task_struct *task, char *states, char *atoms, char *next), 10 + TP_ARGS(task, states, atoms, next)); 11 + DEFINE_EVENT(error_ltl_monitor_id, error_pagefault, 12 + TP_PROTO(struct task_struct *task), 13 + TP_ARGS(task)); 14 + #endif /* CONFIG_RV_MON_PAGEFAULT */
+1
kernel/trace/rv/rv_trace.h
··· 172 172 173 173 TP_printk("%s[%d]: violation detected", __get_str(comm), __entry->pid) 174 174 ); 175 + #include <monitors/pagefault/pagefault_trace.h> 175 176 // Add new monitors based on CONFIG_LTL_MON_EVENTS_ID here 176 177 #endif /* CONFIG_LTL_MON_EVENTS_ID */ 177 178 #endif /* _TRACE_RV_H */
+1
tools/verification/models/rtapp/pagefault.ltl
··· 1 + RULE = always (RT imply not PAGEFAULT)