]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
rv: Add rtapp_pagefault monitor
authorNam Cao <namcao@linutronix.de>
Wed, 9 Jul 2025 19:21:20 +0000 (21:21 +0200)
committerSteven Rostedt (Google) <rostedt@goodmis.org>
Wed, 9 Jul 2025 19:27:01 +0000 (15:27 -0400)
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>
kernel/trace/rv/Kconfig
kernel/trace/rv/Makefile
kernel/trace/rv/monitors/pagefault/Kconfig [new file with mode: 0644]
kernel/trace/rv/monitors/pagefault/pagefault.c [new file with mode: 0644]
kernel/trace/rv/monitors/pagefault/pagefault.h [new file with mode: 0644]
kernel/trace/rv/monitors/pagefault/pagefault_trace.h [new file with mode: 0644]
kernel/trace/rv/rv_trace.h
tools/verification/models/rtapp/pagefault.ltl [new file with mode: 0644]

index 5c407d29166146e7a3f89d40ddbbaf7a9ad5aced..6f86d8501e87ec54f1e34390154bb3eaaed0bbb8 100644 (file)
@@ -42,6 +42,7 @@ source "kernel/trace/rv/monitors/scpd/Kconfig"
 source "kernel/trace/rv/monitors/snep/Kconfig"
 source "kernel/trace/rv/monitors/sncid/Kconfig"
 source "kernel/trace/rv/monitors/rtapp/Kconfig"
+source "kernel/trace/rv/monitors/pagefault/Kconfig"
 # Add new monitors here
 
 config RV_REACTORS
index 9b28c241999555ae2a68263a6e3caf456e525534..353ecf939d0e90f6bb7a968ca5d1d48639b9fbe0 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_RV_MON_SCPD) += monitors/scpd/scpd.o
 obj-$(CONFIG_RV_MON_SNEP) += monitors/snep/snep.o
 obj-$(CONFIG_RV_MON_SNCID) += monitors/sncid/sncid.o
 obj-$(CONFIG_RV_MON_RTAPP) += monitors/rtapp/rtapp.o
+obj-$(CONFIG_RV_MON_PAGEFAULT) += monitors/pagefault/pagefault.o
 # Add new monitors here
 obj-$(CONFIG_RV_REACTORS) += rv_reactors.o
 obj-$(CONFIG_RV_REACT_PRINTK) += reactor_printk.o
diff --git a/kernel/trace/rv/monitors/pagefault/Kconfig b/kernel/trace/rv/monitors/pagefault/Kconfig
new file mode 100644 (file)
index 0000000..5e16625
--- /dev/null
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+config RV_MON_PAGEFAULT
+       depends on RV
+       select RV_LTL_MONITOR
+       depends on RV_MON_RTAPP
+       depends on X86 || RISCV
+       default y
+       select LTL_MON_EVENTS_ID
+       bool "pagefault monitor"
+       help
+         Monitor that real-time tasks do not raise page faults, causing
+         undesirable latency.
+
+         If you are developing a real-time system and not entirely sure whether
+         the applications are designed correctly for real-time, you want to say
+         Y here.
+
+         This monitor does not affect execution speed while it is not running,
+         therefore it is safe to enable this in production kernel.
diff --git a/kernel/trace/rv/monitors/pagefault/pagefault.c b/kernel/trace/rv/monitors/pagefault/pagefault.c
new file mode 100644 (file)
index 0000000..9fe6123
--- /dev/null
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/ftrace.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/rv.h>
+#include <linux/sched/deadline.h>
+#include <linux/sched/rt.h>
+#include <linux/tracepoint.h>
+#include <rv/instrumentation.h>
+
+#define MODULE_NAME "pagefault"
+
+#include <rv_trace.h>
+#include <trace/events/exceptions.h>
+#include <monitors/rtapp/rtapp.h>
+
+#include "pagefault.h"
+#include <rv/ltl_monitor.h>
+
+static void ltl_atoms_fetch(struct task_struct *task, struct ltl_monitor *mon)
+{
+       /*
+        * This includes "actual" real-time tasks and also PI-boosted
+        * tasks. A task being PI-boosted means it is blocking an "actual"
+        * real-task, therefore it should also obey the monitor's rule,
+        * otherwise the "actual" real-task may be delayed.
+        */
+       ltl_atom_set(mon, LTL_RT, rt_or_dl_task(task));
+}
+
+static void ltl_atoms_init(struct task_struct *task, struct ltl_monitor *mon, bool task_creation)
+{
+       if (task_creation)
+               ltl_atom_set(mon, LTL_PAGEFAULT, false);
+}
+
+static void handle_page_fault(void *data, unsigned long address, struct pt_regs *regs,
+                             unsigned long error_code)
+{
+       ltl_atom_pulse(current, LTL_PAGEFAULT, true);
+}
+
+static int enable_pagefault(void)
+{
+       int retval;
+
+       retval = ltl_monitor_init();
+       if (retval)
+               return retval;
+
+       rv_attach_trace_probe("rtapp_pagefault", page_fault_kernel, handle_page_fault);
+       rv_attach_trace_probe("rtapp_pagefault", page_fault_user, handle_page_fault);
+
+       return 0;
+}
+
+static void disable_pagefault(void)
+{
+       rv_detach_trace_probe("rtapp_pagefault", page_fault_kernel, handle_page_fault);
+       rv_detach_trace_probe("rtapp_pagefault", page_fault_user, handle_page_fault);
+
+       ltl_monitor_destroy();
+}
+
+static struct rv_monitor rv_pagefault = {
+       .name = "pagefault",
+       .description = "Monitor that RT tasks do not raise page faults",
+       .enable = enable_pagefault,
+       .disable = disable_pagefault,
+};
+
+static int __init register_pagefault(void)
+{
+       return rv_register_monitor(&rv_pagefault, &rv_rtapp);
+}
+
+static void __exit unregister_pagefault(void)
+{
+       rv_unregister_monitor(&rv_pagefault);
+}
+
+module_init(register_pagefault);
+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");
diff --git a/kernel/trace/rv/monitors/pagefault/pagefault.h b/kernel/trace/rv/monitors/pagefault/pagefault.h
new file mode 100644 (file)
index 0000000..c580ec1
--- /dev/null
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * C implementation of Buchi automaton, automatically generated by
+ * tools/verification/rvgen from the linear temporal logic specification.
+ * For further information, see kernel documentation:
+ *   Documentation/trace/rv/linear_temporal_logic.rst
+ */
+
+#include <linux/rv.h>
+
+#define MONITOR_NAME pagefault
+
+enum ltl_atom {
+       LTL_PAGEFAULT,
+       LTL_RT,
+       LTL_NUM_ATOM
+};
+static_assert(LTL_NUM_ATOM <= RV_MAX_LTL_ATOM);
+
+static const char *ltl_atom_str(enum ltl_atom atom)
+{
+       static const char *const names[] = {
+               "pa",
+               "rt",
+       };
+
+       return names[atom];
+}
+
+enum ltl_buchi_state {
+       S0,
+       RV_NUM_BA_STATES
+};
+static_assert(RV_NUM_BA_STATES <= RV_MAX_BA_STATES);
+
+static void ltl_start(struct task_struct *task, struct ltl_monitor *mon)
+{
+       bool pagefault = test_bit(LTL_PAGEFAULT, mon->atoms);
+       bool val3 = !pagefault;
+       bool rt = test_bit(LTL_RT, mon->atoms);
+       bool val1 = !rt;
+       bool val4 = val1 || val3;
+
+       if (val4)
+               __set_bit(S0, mon->states);
+}
+
+static void
+ltl_possible_next_states(struct ltl_monitor *mon, unsigned int state, unsigned long *next)
+{
+       bool pagefault = test_bit(LTL_PAGEFAULT, mon->atoms);
+       bool val3 = !pagefault;
+       bool rt = test_bit(LTL_RT, mon->atoms);
+       bool val1 = !rt;
+       bool val4 = val1 || val3;
+
+       switch (state) {
+       case S0:
+               if (val4)
+                       __set_bit(S0, next);
+               break;
+       }
+}
diff --git a/kernel/trace/rv/monitors/pagefault/pagefault_trace.h b/kernel/trace/rv/monitors/pagefault/pagefault_trace.h
new file mode 100644 (file)
index 0000000..fe1f825
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Snippet to be included in rv_trace.h
+ */
+
+#ifdef CONFIG_RV_MON_PAGEFAULT
+DEFINE_EVENT(event_ltl_monitor_id, event_pagefault,
+            TP_PROTO(struct task_struct *task, char *states, char *atoms, char *next),
+            TP_ARGS(task, states, atoms, next));
+DEFINE_EVENT(error_ltl_monitor_id, error_pagefault,
+            TP_PROTO(struct task_struct *task),
+            TP_ARGS(task));
+#endif /* CONFIG_RV_MON_PAGEFAULT */
index fd3111ad1d512fd269947b9061cc52f9dd061856..98eee8ec96e4fc94cd8a4b400f7895d92374f787 100644 (file)
@@ -172,6 +172,7 @@ DECLARE_EVENT_CLASS(error_ltl_monitor_id,
 
        TP_printk("%s[%d]: violation detected", __get_str(comm), __entry->pid)
 );
+#include <monitors/pagefault/pagefault_trace.h>
 // Add new monitors based on CONFIG_LTL_MON_EVENTS_ID here
 #endif /* CONFIG_LTL_MON_EVENTS_ID */
 #endif /* _TRACE_RV_H */
diff --git a/tools/verification/models/rtapp/pagefault.ltl b/tools/verification/models/rtapp/pagefault.ltl
new file mode 100644 (file)
index 0000000..d7ce621
--- /dev/null
@@ -0,0 +1 @@
+RULE = always (RT imply not PAGEFAULT)