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

rv/monitor: Add the wip monitor

The wakeup in preemptive (wip) monitor verifies if the
wakeup events always take place with preemption disabled:

|
|
v
#==================#
H preemptive H <+
#==================# |
| |
| preempt_disable | preempt_enable
v |
sched_waking +------------------+ |
+--------------- | | |
| | non_preemptive | |
+--------------> | | -+
+------------------+

The wakeup event always takes place with preemption disabled because
of the scheduler synchronization. However, because the preempt_count
and its trace event are not atomic with regard to interrupts, some
inconsistencies might happen.

The documentation illustrates one of these cases.

Link: https://lkml.kernel.org/r/c98ca678df81115fddc04921b3c79720c836b18f.1659052063.git.bristot@kernel.org

Cc: Wim Van Sebroeck <wim@linux-watchdog.org>
Cc: Guenter Roeck <linux@roeck-us.net>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Marco Elver <elver@google.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: "Paul E. McKenney" <paulmck@kernel.org>
Cc: Shuah Khan <skhan@linuxfoundation.org>
Cc: Gabriele Paoloni <gpaoloni@redhat.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Clark Williams <williams@redhat.com>
Cc: Tao Zhou <tao.zhou@linux.dev>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: linux-doc@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-trace-devel@vger.kernel.org
Signed-off-by: Daniel Bristot de Oliveira <bristot@kernel.org>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>

authored by

Daniel Bristot de Oliveira and committed by
Steven Rostedt (Google)
10bde81c 8812d212

+111 -36
+1
Documentation/trace/rv/index.rst
··· 10 10 deterministic_automata.rst 11 11 da_monitor_synthesis.rst 12 12 da_monitor_instrumentation.rst 13 + monitor_wip.rst
+55
Documentation/trace/rv/monitor_wip.rst
··· 1 + Monitor wip 2 + =========== 3 + 4 + - Name: wip - wakeup in preemptive 5 + - Type: per-cpu deterministic automaton 6 + - Author: Daniel Bristot de Oliveira <bristot@kernel.org> 7 + 8 + Description 9 + ----------- 10 + 11 + The wakeup in preemptive (wip) monitor is a sample per-cpu monitor 12 + that verifies if the wakeup events always take place with 13 + preemption disabled:: 14 + 15 + | 16 + | 17 + v 18 + #==================# 19 + H preemptive H <+ 20 + #==================# | 21 + | | 22 + | preempt_disable | preempt_enable 23 + v | 24 + sched_waking +------------------+ | 25 + +--------------- | | | 26 + | | non_preemptive | | 27 + +--------------> | | -+ 28 + +------------------+ 29 + 30 + The wakeup event always takes place with preemption disabled because 31 + of the scheduler synchronization. However, because the preempt_count 32 + and its trace event are not atomic with regard to interrupts, some 33 + inconsistencies might happen. For example:: 34 + 35 + preempt_disable() { 36 + __preempt_count_add(1) 37 + -------> smp_apic_timer_interrupt() { 38 + preempt_disable() 39 + do not trace (preempt count >= 1) 40 + 41 + wake up a thread 42 + 43 + preempt_enable() 44 + do not trace (preempt count >= 1) 45 + } 46 + <------ 47 + trace_preempt_disable(); 48 + } 49 + 50 + This problem was reported and discussed here: 51 + https://lore.kernel.org/r/cover.1559051152.git.bristot@redhat.com/ 52 + 53 + Specification 54 + ------------- 55 + Grapviz Dot file in tools/verification/models/wip.dot
+10
include/trace/events/rv.h
··· 56 56 __entry->event, 57 57 __entry->state) 58 58 ); 59 + 60 + #ifdef CONFIG_RV_MON_WIP 61 + DEFINE_EVENT(event_da_monitor, event_wip, 62 + TP_PROTO(char *state, char *event, char *next_state, bool final_state), 63 + TP_ARGS(state, event, next_state, final_state)); 64 + 65 + DEFINE_EVENT(error_da_monitor, error_wip, 66 + TP_PROTO(char *state, char *event), 67 + TP_ARGS(state, event)); 68 + #endif /* CONFIG_RV_MON_WIP */ 59 69 #endif /* CONFIG_DA_MON_EVENTS_IMPLICIT */ 60 70 61 71 #ifdef CONFIG_DA_MON_EVENTS_ID
+13
kernel/trace/rv/Kconfig
··· 25 25 For further information, see: 26 26 Documentation/trace/rv/runtime-verification.rst 27 27 28 + config RV_MON_WIP 29 + depends on RV 30 + depends on PREEMPT_TRACER 31 + select DA_MON_EVENTS_IMPLICIT 32 + bool "wip monitor" 33 + help 34 + Enable wip (wakeup in preemptive) sample monitor that illustrates 35 + the usage of per-cpu monitors, and one limitation of the 36 + preempt_disable/enable events. 37 + 38 + For further information, see: 39 + Documentation/trace/rv/monitor_wip.rst 40 + 28 41 config RV_REACTORS 29 42 bool "Runtime verification reactors" 30 43 default y
+1
kernel/trace/rv/Makefile
··· 2 2 3 3 obj-$(CONFIG_RV) += rv.o 4 4 obj-$(CONFIG_RV_REACTORS) += rv_reactors.o 5 + obj-$(CONFIG_RV_MON_WIP) += monitors/wip/wip.o
+15 -36
kernel/trace/rv/monitors/wip/wip.c
··· 10 10 11 11 #define MODULE_NAME "wip" 12 12 13 - /* 14 - * XXX: include required tracepoint headers, e.g., 15 - * #include <linux/trace/events/sched.h> 16 - */ 17 13 #include <trace/events/rv.h> 14 + #include <trace/events/sched.h> 15 + #include <trace/events/preemptirq.h> 18 16 19 - /* 20 - * This is the self-generated part of the monitor. Generally, there is no need 21 - * to touch this section. 22 - */ 23 17 #include "wip.h" 24 18 25 - /* 26 - * Declare the deterministic automata monitor. 27 - * 28 - * The rv monitor reference is needed for the monitor declaration. 29 - */ 30 19 struct rv_monitor rv_wip; 31 20 DECLARE_DA_MON_PER_CPU(wip, unsigned char); 32 21 33 - /* 34 - * This is the instrumentation part of the monitor. 35 - * 36 - * This is the section where manual work is required. Here the kernel events 37 - * are translated into model's event. 38 - * 39 - */ 40 - static void handle_preempt_disable(void *data, /* XXX: fill header */) 22 + static void handle_preempt_disable(void *data, unsigned long ip, unsigned long parent_ip) 41 23 { 42 24 da_handle_event_wip(preempt_disable_wip); 43 25 } 44 26 45 - static void handle_preempt_enable(void *data, /* XXX: fill header */) 27 + static void handle_preempt_enable(void *data, unsigned long ip, unsigned long parent_ip) 46 28 { 47 - da_handle_event_wip(preempt_enable_wip); 29 + da_handle_start_event_wip(preempt_enable_wip); 48 30 } 49 31 50 - static void handle_sched_waking(void *data, /* XXX: fill header */) 32 + static void handle_sched_waking(void *data, struct task_struct *task) 51 33 { 52 34 da_handle_event_wip(sched_waking_wip); 53 35 } ··· 42 60 if (retval) 43 61 return retval; 44 62 45 - rv_attach_trace_probe("wip", /* XXX: tracepoint */, handle_preempt_disable); 46 - rv_attach_trace_probe("wip", /* XXX: tracepoint */, handle_preempt_enable); 47 - rv_attach_trace_probe("wip", /* XXX: tracepoint */, handle_sched_waking); 63 + rv_attach_trace_probe("wip", preempt_enable, handle_preempt_enable); 64 + rv_attach_trace_probe("wip", sched_waking, handle_sched_waking); 65 + rv_attach_trace_probe("wip", preempt_disable, handle_preempt_disable); 48 66 49 67 return 0; 50 68 } ··· 53 71 { 54 72 rv_wip.enabled = 0; 55 73 56 - rv_detach_trace_probe("wip", /* XXX: tracepoint */, handle_preempt_disable); 57 - rv_detach_trace_probe("wip", /* XXX: tracepoint */, handle_preempt_enable); 58 - rv_detach_trace_probe("wip", /* XXX: tracepoint */, handle_sched_waking); 74 + rv_detach_trace_probe("wip", preempt_disable, handle_preempt_disable); 75 + rv_detach_trace_probe("wip", preempt_enable, handle_preempt_enable); 76 + rv_detach_trace_probe("wip", sched_waking, handle_sched_waking); 59 77 60 78 da_monitor_destroy_wip(); 61 79 } 62 80 63 - /* 64 - * This is the monitor register section. 65 - */ 66 81 struct rv_monitor rv_wip = { 67 82 .name = "wip", 68 - .description = "auto-generated wip", 83 + .description = "wakeup in preemptive per-cpu testing monitor.", 69 84 .enable = enable_wip, 70 85 .disable = disable_wip, 71 86 .reset = da_monitor_reset_all_wip, ··· 84 105 module_exit(unregister_wip); 85 106 86 107 MODULE_LICENSE("GPL"); 87 - MODULE_AUTHOR("dot2k: auto-generated"); 88 - MODULE_DESCRIPTION("wip"); 108 + MODULE_AUTHOR("Daniel Bristot de Oliveira <bristot@kernel.org>"); 109 + MODULE_DESCRIPTION("wip: wakeup in preemptive - per-cpu sample monitor.");
+16
tools/verification/models/wip.dot
··· 1 + digraph state_automaton { 2 + {node [shape = circle] "non_preemptive"}; 3 + {node [shape = plaintext, style=invis, label=""] "__init_preemptive"}; 4 + {node [shape = doublecircle] "preemptive"}; 5 + {node [shape = circle] "preemptive"}; 6 + "__init_preemptive" -> "preemptive"; 7 + "non_preemptive" [label = "non_preemptive"]; 8 + "non_preemptive" -> "non_preemptive" [ label = "sched_waking" ]; 9 + "non_preemptive" -> "preemptive" [ label = "preempt_enable" ]; 10 + "preemptive" [label = "preemptive"]; 11 + "preemptive" -> "non_preemptive" [ label = "preempt_disable" ]; 12 + { rank = min ; 13 + "__init_preemptive"; 14 + "preemptive"; 15 + } 16 + }