summaryrefslogtreecommitdiff
path: root/tools/verification
diff options
context:
space:
mode:
Diffstat (limited to 'tools/verification')
-rw-r--r--tools/verification/dot2/automata.py36
-rw-r--r--tools/verification/dot2/dot2c.py4
-rw-r--r--tools/verification/dot2/dot2k42
-rw-r--r--tools/verification/dot2/dot2k.py290
-rw-r--r--tools/verification/dot2/dot2k_templates/Kconfig9
-rw-r--r--tools/verification/dot2/dot2k_templates/main.c91
-rw-r--r--tools/verification/dot2/dot2k_templates/main_container.c38
-rw-r--r--tools/verification/dot2/dot2k_templates/main_container.h3
-rw-r--r--tools/verification/dot2/dot2k_templates/main_global.c91
-rw-r--r--tools/verification/dot2/dot2k_templates/main_per_cpu.c91
-rw-r--r--tools/verification/dot2/dot2k_templates/main_per_task.c91
-rw-r--r--tools/verification/dot2/dot2k_templates/trace.h13
-rw-r--r--tools/verification/models/sched/sco.dot18
-rw-r--r--tools/verification/models/sched/scpd.dot18
-rw-r--r--tools/verification/models/sched/sncid.dot18
-rw-r--r--tools/verification/models/sched/snep.dot18
-rw-r--r--tools/verification/models/sched/snroc.dot18
-rw-r--r--tools/verification/models/sched/tss.dot18
-rw-r--r--tools/verification/rv/Makefile6
-rw-r--r--tools/verification/rv/Makefile.rv2
-rw-r--r--tools/verification/rv/include/in_kernel.h2
-rw-r--r--tools/verification/rv/include/rv.h3
-rw-r--r--tools/verification/rv/src/in_kernel.c256
-rw-r--r--tools/verification/rv/src/rv.c38
24 files changed, 805 insertions, 409 deletions
diff --git a/tools/verification/dot2/automata.py b/tools/verification/dot2/automata.py
index bdeb98baa8b0..d9a3fe2b74bf 100644
--- a/tools/verification/dot2/automata.py
+++ b/tools/verification/dot2/automata.py
@@ -19,13 +19,14 @@ class Automata:
invalid_state_str = "INVALID_STATE"
- def __init__(self, file_path):
+ def __init__(self, file_path, model_name=None):
self.__dot_path = file_path
- self.name = self.__get_model_name()
+ self.name = model_name or self.__get_model_name()
self.__dot_lines = self.__open_dot()
self.states, self.initial_state, self.final_states = self.__get_state_variables()
self.events = self.__get_event_variables()
self.function = self.__create_matrix()
+ self.events_start, self.events_start_run = self.__store_init_events()
def __get_model_name(self):
basename = ntpath.basename(self.__dot_path)
@@ -172,3 +173,34 @@ class Automata:
cursor += 1
return matrix
+
+ def __store_init_events(self):
+ events_start = [False] * len(self.events)
+ events_start_run = [False] * len(self.events)
+ for i, _ in enumerate(self.events):
+ curr_event_will_init = 0
+ curr_event_from_init = False
+ curr_event_used = 0
+ for j, _ in enumerate(self.states):
+ if self.function[j][i] != self.invalid_state_str:
+ curr_event_used += 1
+ if self.function[j][i] == self.initial_state:
+ curr_event_will_init += 1
+ if self.function[0][i] != self.invalid_state_str:
+ curr_event_from_init = True
+ # this event always leads to init
+ if curr_event_will_init and curr_event_used == curr_event_will_init:
+ events_start[i] = True
+ # this event is only called from init
+ if curr_event_from_init and curr_event_used == 1:
+ events_start_run[i] = True
+ return events_start, events_start_run
+
+ def is_start_event(self, event):
+ return self.events_start[self.events.index(event)]
+
+ def is_start_run_event(self, event):
+ # prefer handle_start_event if there
+ if any(self.events_start):
+ return False
+ return self.events_start_run[self.events.index(event)]
diff --git a/tools/verification/dot2/dot2c.py b/tools/verification/dot2/dot2c.py
index 87d8a1e1470c..fa2816ac7b61 100644
--- a/tools/verification/dot2/dot2c.py
+++ b/tools/verification/dot2/dot2c.py
@@ -22,8 +22,8 @@ class Dot2c(Automata):
struct_automaton_def = "automaton"
var_automaton_def = "aut"
- def __init__(self, file_path):
- super().__init__(file_path)
+ def __init__(self, file_path, model_name=None):
+ super().__init__(file_path, model_name)
self.line_length = 100
def __buff_to_string(self, buff):
diff --git a/tools/verification/dot2/dot2k b/tools/verification/dot2/dot2k
index d4d7e52d549e..767064f415e7 100644
--- a/tools/verification/dot2/dot2k
+++ b/tools/verification/dot2/dot2k
@@ -11,35 +11,43 @@
if __name__ == '__main__':
from dot2.dot2k import dot2k
import argparse
- import ntpath
- import os
- import platform
import sys
+ def is_container():
+ """Should work even before parsing the arguments"""
+ return "-c" in sys.argv or "--container" in sys.argv
+
parser = argparse.ArgumentParser(description='transform .dot file into kernel rv monitor')
- parser.add_argument('-d', "--dot", dest="dot_file", required=True)
- parser.add_argument('-t', "--monitor_type", dest="monitor_type", required=True)
- parser.add_argument('-n', "--model_name", dest="model_name", required=False)
+ parser.add_argument('-d', "--dot", dest="dot_file", required=not is_container())
+ parser.add_argument('-t', "--monitor_type", dest="monitor_type", required=not is_container(),
+ help=f"Available options: {', '.join(dot2k.monitor_types.keys())}")
+ parser.add_argument('-n', "--model_name", dest="model_name", required=is_container())
parser.add_argument("-D", "--description", dest="description", required=False)
+ parser.add_argument("-a", "--auto_patch", dest="auto_patch",
+ action="store_true", required=False,
+ help="Patch the kernel in place")
+ parser.add_argument("-p", "--parent", dest="parent",
+ required=False, help="Create a monitor nested to parent")
+ parser.add_argument("-c", "--container", dest="container",
+ action="store_true", required=False,
+ help="Create an empty monitor to be used as a container")
params = parser.parse_args()
- print("Opening and parsing the dot file %s" % params.dot_file)
+ if not is_container():
+ print("Opening and parsing the dot file %s" % params.dot_file)
try:
- monitor=dot2k(params.dot_file, params.monitor_type)
+ monitor=dot2k(params.dot_file, params.monitor_type, vars(params))
except Exception as e:
print('Error: '+ str(e))
print("Sorry : :-(")
sys.exit(1)
- # easier than using argparse action.
- if params.model_name != None:
- print(params.model_name)
-
print("Writing the monitor into the directory %s" % monitor.name)
monitor.print_files()
print("Almost done, checklist")
- print(" - Edit the %s/%s.c to add the instrumentation" % (monitor.name, monitor.name))
- print(" - Edit include/trace/events/rv.h to add the tracepoint entry")
- print(" - Move it to the kernel's monitor directory")
- print(" - Edit kernel/trace/rv/Makefile")
- print(" - Edit kernel/trace/rv/Kconfig")
+ if not is_container():
+ print(" - Edit the %s/%s.c to add the instrumentation" % (monitor.name, monitor.name))
+ print(monitor.fill_tracepoint_tooltip())
+ print(monitor.fill_makefile_tooltip())
+ print(monitor.fill_kconfig_tooltip())
+ print(monitor.fill_monitor_tooltip())
diff --git a/tools/verification/dot2/dot2k.py b/tools/verification/dot2/dot2k.py
index 016550fccf1f..745d35a4a379 100644
--- a/tools/verification/dot2/dot2k.py
+++ b/tools/verification/dot2/dot2k.py
@@ -14,50 +14,98 @@ import os
class dot2k(Dot2c):
monitor_types = { "global" : 1, "per_cpu" : 2, "per_task" : 3 }
- monitor_templates_dir = "dot2k/rv_templates/"
+ monitor_templates_dir = "dot2/dot2k_templates/"
+ rv_dir = "kernel/trace/rv"
monitor_type = "per_cpu"
- def __init__(self, file_path, MonitorType):
- super().__init__(file_path)
-
- self.monitor_type = self.monitor_types.get(MonitorType)
- if self.monitor_type == None:
- raise Exception("Unknown monitor type: %s" % MonitorType)
-
- self.monitor_type = MonitorType
+ def __init__(self, file_path, MonitorType, extra_params={}):
+ self.container = extra_params.get("container")
+ self.parent = extra_params.get("parent")
self.__fill_rv_templates_dir()
- self.main_c = self.__open_file(self.monitor_templates_dir + "main_" + MonitorType + ".c")
+
+ if self.container:
+ if file_path:
+ raise ValueError("A container does not require a dot file")
+ if MonitorType:
+ raise ValueError("A container does not require a monitor type")
+ if self.parent:
+ raise ValueError("A container cannot have a parent")
+ self.name = extra_params.get("model_name")
+ self.events = []
+ self.states = []
+ self.main_c = self.__read_file(self.monitor_templates_dir + "main_container.c")
+ self.main_h = self.__read_file(self.monitor_templates_dir + "main_container.h")
+ else:
+ super().__init__(file_path, extra_params.get("model_name"))
+
+ self.monitor_type = self.monitor_types.get(MonitorType)
+ if self.monitor_type is None:
+ raise ValueError("Unknown monitor type: %s" % MonitorType)
+ self.monitor_type = MonitorType
+ self.main_c = self.__read_file(self.monitor_templates_dir + "main.c")
+ self.trace_h = self.__read_file(self.monitor_templates_dir + "trace.h")
+ self.kconfig = self.__read_file(self.monitor_templates_dir + "Kconfig")
self.enum_suffix = "_%s" % self.name
+ self.description = extra_params.get("description", self.name) or "auto-generated"
+ self.auto_patch = extra_params.get("auto_patch")
+ if self.auto_patch:
+ self.__fill_rv_kernel_dir()
def __fill_rv_templates_dir(self):
- if os.path.exists(self.monitor_templates_dir) == True:
+ if os.path.exists(self.monitor_templates_dir):
return
if platform.system() != "Linux":
- raise Exception("I can only run on Linux.")
+ raise OSError("I can only run on Linux.")
kernel_path = "/lib/modules/%s/build/tools/verification/dot2/dot2k_templates/" % (platform.release())
- if os.path.exists(kernel_path) == True:
+ if os.path.exists(kernel_path):
self.monitor_templates_dir = kernel_path
return
- if os.path.exists("/usr/share/dot2/dot2k_templates/") == True:
+ if os.path.exists("/usr/share/dot2/dot2k_templates/"):
self.monitor_templates_dir = "/usr/share/dot2/dot2k_templates/"
return
- raise Exception("Could not find the template directory, do you have the kernel source installed?")
+ raise FileNotFoundError("Could not find the template directory, do you have the kernel source installed?")
+ def __fill_rv_kernel_dir(self):
+
+ # first try if we are running in the kernel tree root
+ if os.path.exists(self.rv_dir):
+ return
- def __open_file(self, path):
+ # offset if we are running inside the kernel tree from verification/dot2
+ kernel_path = os.path.join("../..", self.rv_dir)
+
+ if os.path.exists(kernel_path):
+ self.rv_dir = kernel_path
+ return
+
+ if platform.system() != "Linux":
+ raise OSError("I can only run on Linux.")
+
+ kernel_path = os.path.join("/lib/modules/%s/build" % platform.release(), self.rv_dir)
+
+ # if the current kernel is from a distro this may not be a full kernel tree
+ # verify that one of the files we are going to modify is available
+ if os.path.exists(os.path.join(kernel_path, "rv_trace.h")):
+ self.rv_dir = kernel_path
+ return
+
+ raise FileNotFoundError("Could not find the rv directory, do you have the kernel source installed?")
+
+ def __read_file(self, path):
try:
- fd = open(path)
+ fd = open(path, 'r')
except OSError:
raise Exception("Cannot open the file: %s" % path)
content = fd.read()
+ fd.close()
return content
def __buff_to_string(self, buff):
@@ -69,16 +117,34 @@ class dot2k(Dot2c):
# cut off the last \n
return string[:-1]
+ def fill_monitor_type(self):
+ return self.monitor_type.upper()
+
+ def fill_parent(self):
+ return "&rv_%s" % self.parent if self.parent else "NULL"
+
+ def fill_include_parent(self):
+ if self.parent:
+ return "#include <monitors/%s/%s.h>\n" % (self.parent, self.parent)
+ return ""
+
def fill_tracepoint_handlers_skel(self):
buff = []
for event in self.events:
buff.append("static void handle_%s(void *data, /* XXX: fill header */)" % event)
buff.append("{")
+ handle = "handle_event"
+ if self.is_start_event(event):
+ buff.append("\t/* XXX: validate that this event always leads to the initial state */")
+ handle = "handle_start_event"
+ elif self.is_start_run_event(event):
+ buff.append("\t/* XXX: validate that this event is only valid in the initial state */")
+ handle = "handle_start_run_event"
if self.monitor_type == "per_task":
buff.append("\tstruct task_struct *p = /* XXX: how do I get p? */;");
- buff.append("\tda_handle_event_%s(p, %s%s);" % (self.name, event, self.enum_suffix));
+ buff.append("\tda_%s_%s(p, %s%s);" % (handle, self.name, event, self.enum_suffix));
else:
- buff.append("\tda_handle_event_%s(%s%s);" % (self.name, event, self.enum_suffix));
+ buff.append("\tda_%s_%s(%s%s);" % (handle, self.name, event, self.enum_suffix));
buff.append("}")
buff.append("")
return self.__buff_to_string(buff)
@@ -97,23 +163,31 @@ class dot2k(Dot2c):
def fill_main_c(self):
main_c = self.main_c
+ monitor_type = self.fill_monitor_type()
min_type = self.get_minimun_type()
- nr_events = self.events.__len__()
+ nr_events = len(self.events)
tracepoint_handlers = self.fill_tracepoint_handlers_skel()
tracepoint_attach = self.fill_tracepoint_attach_probe()
tracepoint_detach = self.fill_tracepoint_detach_helper()
-
- main_c = main_c.replace("MIN_TYPE", min_type)
- main_c = main_c.replace("MODEL_NAME", self.name)
- main_c = main_c.replace("NR_EVENTS", str(nr_events))
- main_c = main_c.replace("TRACEPOINT_HANDLERS_SKEL", tracepoint_handlers)
- main_c = main_c.replace("TRACEPOINT_ATTACH", tracepoint_attach)
- main_c = main_c.replace("TRACEPOINT_DETACH", tracepoint_detach)
+ parent = self.fill_parent()
+ parent_include = self.fill_include_parent()
+
+ main_c = main_c.replace("%%MONITOR_TYPE%%", monitor_type)
+ main_c = main_c.replace("%%MIN_TYPE%%", min_type)
+ main_c = main_c.replace("%%MODEL_NAME%%", self.name)
+ main_c = main_c.replace("%%NR_EVENTS%%", str(nr_events))
+ main_c = main_c.replace("%%TRACEPOINT_HANDLERS_SKEL%%", tracepoint_handlers)
+ main_c = main_c.replace("%%TRACEPOINT_ATTACH%%", tracepoint_attach)
+ main_c = main_c.replace("%%TRACEPOINT_DETACH%%", tracepoint_detach)
+ main_c = main_c.replace("%%DESCRIPTION%%", self.description)
+ main_c = main_c.replace("%%PARENT%%", parent)
+ main_c = main_c.replace("%%INCLUDE_PARENT%%", parent_include)
return main_c
def fill_model_h_header(self):
buff = []
+ buff.append("/* SPDX-License-Identifier: GPL-2.0 */")
buff.append("/*")
buff.append(" * Automatically generated C representation of %s automaton" % (self.name))
buff.append(" * For further information about this format, see kernel documentation:")
@@ -137,41 +211,179 @@ class dot2k(Dot2c):
return self.__buff_to_string(buff)
+ def fill_monitor_class_type(self):
+ if self.monitor_type == "per_task":
+ return "DA_MON_EVENTS_ID"
+ return "DA_MON_EVENTS_IMPLICIT"
+
+ def fill_monitor_class(self):
+ if self.monitor_type == "per_task":
+ return "da_monitor_id"
+ return "da_monitor"
+
+ def fill_tracepoint_args_skel(self, tp_type):
+ buff = []
+ tp_args_event = [
+ ("char *", "state"),
+ ("char *", "event"),
+ ("char *", "next_state"),
+ ("bool ", "final_state"),
+ ]
+ tp_args_error = [
+ ("char *", "state"),
+ ("char *", "event"),
+ ]
+ tp_args_id = ("int ", "id")
+ tp_args = tp_args_event if tp_type == "event" else tp_args_error
+ if self.monitor_type == "per_task":
+ tp_args.insert(0, tp_args_id)
+ tp_proto_c = ", ".join([a+b for a,b in tp_args])
+ tp_args_c = ", ".join([b for a,b in tp_args])
+ buff.append(" TP_PROTO(%s)," % tp_proto_c)
+ buff.append(" TP_ARGS(%s)" % tp_args_c)
+ return self.__buff_to_string(buff)
+
+ def fill_monitor_deps(self):
+ buff = []
+ buff.append(" # XXX: add dependencies if there")
+ if self.parent:
+ buff.append(" depends on RV_MON_%s" % self.parent.upper())
+ buff.append(" default y")
+ return self.__buff_to_string(buff)
+
+ def fill_trace_h(self):
+ trace_h = self.trace_h
+ monitor_class = self.fill_monitor_class()
+ monitor_class_type = self.fill_monitor_class_type()
+ tracepoint_args_skel_event = self.fill_tracepoint_args_skel("event")
+ tracepoint_args_skel_error = self.fill_tracepoint_args_skel("error")
+ trace_h = trace_h.replace("%%MODEL_NAME%%", self.name)
+ trace_h = trace_h.replace("%%MODEL_NAME_UP%%", self.name.upper())
+ trace_h = trace_h.replace("%%MONITOR_CLASS%%", monitor_class)
+ trace_h = trace_h.replace("%%MONITOR_CLASS_TYPE%%", monitor_class_type)
+ trace_h = trace_h.replace("%%TRACEPOINT_ARGS_SKEL_EVENT%%", tracepoint_args_skel_event)
+ trace_h = trace_h.replace("%%TRACEPOINT_ARGS_SKEL_ERROR%%", tracepoint_args_skel_error)
+ return trace_h
+
+ def fill_kconfig(self):
+ kconfig = self.kconfig
+ monitor_class_type = self.fill_monitor_class_type()
+ monitor_deps = self.fill_monitor_deps()
+ kconfig = kconfig.replace("%%MODEL_NAME%%", self.name)
+ kconfig = kconfig.replace("%%MODEL_NAME_UP%%", self.name.upper())
+ kconfig = kconfig.replace("%%MONITOR_CLASS_TYPE%%", monitor_class_type)
+ kconfig = kconfig.replace("%%DESCRIPTION%%", self.description)
+ kconfig = kconfig.replace("%%MONITOR_DEPS%%", monitor_deps)
+ return kconfig
+
+ def fill_main_container_h(self):
+ main_h = self.main_h
+ main_h = main_h.replace("%%MODEL_NAME%%", self.name)
+ return main_h
+
+ def __patch_file(self, file, marker, line):
+ file_to_patch = os.path.join(self.rv_dir, file)
+ content = self.__read_file(file_to_patch)
+ content = content.replace(marker, line + "\n" + marker)
+ self.__write_file(file_to_patch, content)
+
+ def fill_tracepoint_tooltip(self):
+ monitor_class_type = self.fill_monitor_class_type()
+ if self.auto_patch:
+ self.__patch_file("rv_trace.h",
+ "// Add new monitors based on CONFIG_%s here" % monitor_class_type,
+ "#include <monitors/%s/%s_trace.h>" % (self.name, self.name))
+ return " - Patching %s/rv_trace.h, double check the result" % self.rv_dir
+
+ return """ - Edit %s/rv_trace.h:
+Add this line where other tracepoints are included and %s is defined:
+#include <monitors/%s/%s_trace.h>
+""" % (self.rv_dir, monitor_class_type, self.name, self.name)
+
+ def fill_kconfig_tooltip(self):
+ if self.auto_patch:
+ self.__patch_file("Kconfig",
+ "# Add new monitors here",
+ "source \"kernel/trace/rv/monitors/%s/Kconfig\"" % (self.name))
+ return " - Patching %s/Kconfig, double check the result" % self.rv_dir
+
+ return """ - Edit %s/Kconfig:
+Add this line where other monitors are included:
+source \"kernel/trace/rv/monitors/%s/Kconfig\"
+""" % (self.rv_dir, self.name)
+
+ def fill_makefile_tooltip(self):
+ name = self.name
+ name_up = name.upper()
+ if self.auto_patch:
+ self.__patch_file("Makefile",
+ "# Add new monitors here",
+ "obj-$(CONFIG_RV_MON_%s) += monitors/%s/%s.o" % (name_up, name, name))
+ return " - Patching %s/Makefile, double check the result" % self.rv_dir
+
+ return """ - Edit %s/Makefile:
+Add this line where other monitors are included:
+obj-$(CONFIG_RV_MON_%s) += monitors/%s/%s.o
+""" % (self.rv_dir, name_up, name, name)
+
+ def fill_monitor_tooltip(self):
+ if self.auto_patch:
+ return " - Monitor created in %s/monitors/%s" % (self.rv_dir, self. name)
+ return " - Move %s/ to the kernel's monitor directory (%s/monitors)" % (self.name, self.rv_dir)
+
def __create_directory(self):
+ path = self.name
+ if self.auto_patch:
+ path = os.path.join(self.rv_dir, "monitors", path)
try:
- os.mkdir(self.name)
+ os.mkdir(path)
except FileExistsError:
return
except:
print("Fail creating the output dir: %s" % self.name)
- def __create_file(self, file_name, content):
- path = "%s/%s" % (self.name, file_name)
+ def __write_file(self, file_name, content):
try:
- file = open(path, 'w')
- except FileExistsError:
- return
+ file = open(file_name, 'w')
except:
- print("Fail creating file: %s" % path)
+ print("Fail writing to file: %s" % file_name)
file.write(content)
file.close()
+ def __create_file(self, file_name, content):
+ path = "%s/%s" % (self.name, file_name)
+ if self.auto_patch:
+ path = os.path.join(self.rv_dir, "monitors", path)
+ self.__write_file(path, content)
+
def __get_main_name(self):
path = "%s/%s" % (self.name, "main.c")
- if os.path.exists(path) == False:
- return "main.c"
+ if not os.path.exists(path):
+ return "main.c"
return "__main.c"
def print_files(self):
main_c = self.fill_main_c()
- model_h = self.fill_model_h()
self.__create_directory()
path = "%s.c" % self.name
self.__create_file(path, main_c)
- path = "%s.h" % self.name
- self.__create_file(path, model_h)
+ if self.container:
+ main_h = self.fill_main_container_h()
+ path = "%s.h" % self.name
+ self.__create_file(path, main_h)
+ else:
+ model_h = self.fill_model_h()
+ path = "%s.h" % self.name
+ self.__create_file(path, model_h)
+
+ trace_h = self.fill_trace_h()
+ path = "%s_trace.h" % self.name
+ self.__create_file(path, trace_h)
+
+ kconfig = self.fill_kconfig()
+ self.__create_file("Kconfig", kconfig)
diff --git a/tools/verification/dot2/dot2k_templates/Kconfig b/tools/verification/dot2/dot2k_templates/Kconfig
new file mode 100644
index 000000000000..291b29ea28db
--- /dev/null
+++ b/tools/verification/dot2/dot2k_templates/Kconfig
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+config RV_MON_%%MODEL_NAME_UP%%
+ depends on RV
+%%MONITOR_DEPS%%
+ select %%MONITOR_CLASS_TYPE%%
+ bool "%%MODEL_NAME%% monitor"
+ help
+ %%DESCRIPTION%%
diff --git a/tools/verification/dot2/dot2k_templates/main.c b/tools/verification/dot2/dot2k_templates/main.c
new file mode 100644
index 000000000000..83044a20c89a
--- /dev/null
+++ b/tools/verification/dot2/dot2k_templates/main.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/ftrace.h>
+#include <linux/tracepoint.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/rv.h>
+#include <rv/instrumentation.h>
+#include <rv/da_monitor.h>
+
+#define MODULE_NAME "%%MODEL_NAME%%"
+
+/*
+ * XXX: include required tracepoint headers, e.g.,
+ * #include <trace/events/sched.h>
+ */
+#include <rv_trace.h>
+%%INCLUDE_PARENT%%
+/*
+ * This is the self-generated part of the monitor. Generally, there is no need
+ * to touch this section.
+ */
+#include "%%MODEL_NAME%%.h"
+
+/*
+ * Declare the deterministic automata monitor.
+ *
+ * The rv monitor reference is needed for the monitor declaration.
+ */
+static struct rv_monitor rv_%%MODEL_NAME%%;
+DECLARE_DA_MON_%%MONITOR_TYPE%%(%%MODEL_NAME%%, %%MIN_TYPE%%);
+
+/*
+ * This is the instrumentation part of the monitor.
+ *
+ * This is the section where manual work is required. Here the kernel events
+ * are translated into model's event.
+ *
+ */
+%%TRACEPOINT_HANDLERS_SKEL%%
+static int enable_%%MODEL_NAME%%(void)
+{
+ int retval;
+
+ retval = da_monitor_init_%%MODEL_NAME%%();
+ if (retval)
+ return retval;
+
+%%TRACEPOINT_ATTACH%%
+
+ return 0;
+}
+
+static void disable_%%MODEL_NAME%%(void)
+{
+ rv_%%MODEL_NAME%%.enabled = 0;
+
+%%TRACEPOINT_DETACH%%
+
+ da_monitor_destroy_%%MODEL_NAME%%();
+}
+
+/*
+ * This is the monitor register section.
+ */
+static struct rv_monitor rv_%%MODEL_NAME%% = {
+ .name = "%%MODEL_NAME%%",
+ .description = "%%DESCRIPTION%%",
+ .enable = enable_%%MODEL_NAME%%,
+ .disable = disable_%%MODEL_NAME%%,
+ .reset = da_monitor_reset_all_%%MODEL_NAME%%,
+ .enabled = 0,
+};
+
+static int __init register_%%MODEL_NAME%%(void)
+{
+ rv_register_monitor(&rv_%%MODEL_NAME%%, %%PARENT%%);
+ return 0;
+}
+
+static void __exit unregister_%%MODEL_NAME%%(void)
+{
+ rv_unregister_monitor(&rv_%%MODEL_NAME%%);
+}
+
+module_init(register_%%MODEL_NAME%%);
+module_exit(unregister_%%MODEL_NAME%%);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("dot2k: auto-generated");
+MODULE_DESCRIPTION("%%MODEL_NAME%%: %%DESCRIPTION%%");
diff --git a/tools/verification/dot2/dot2k_templates/main_container.c b/tools/verification/dot2/dot2k_templates/main_container.c
new file mode 100644
index 000000000000..89fc17cf8958
--- /dev/null
+++ b/tools/verification/dot2/dot2k_templates/main_container.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/rv.h>
+
+#define MODULE_NAME "%%MODEL_NAME%%"
+
+#include "%%MODEL_NAME%%.h"
+
+struct rv_monitor rv_%%MODEL_NAME%%;
+
+struct rv_monitor rv_%%MODEL_NAME%% = {
+ .name = "%%MODEL_NAME%%",
+ .description = "%%DESCRIPTION%%",
+ .enable = NULL,
+ .disable = NULL,
+ .reset = NULL,
+ .enabled = 0,
+};
+
+static int __init register_%%MODEL_NAME%%(void)
+{
+ rv_register_monitor(&rv_%%MODEL_NAME%%, NULL);
+ return 0;
+}
+
+static void __exit unregister_%%MODEL_NAME%%(void)
+{
+ rv_unregister_monitor(&rv_%%MODEL_NAME%%);
+}
+
+module_init(register_%%MODEL_NAME%%);
+module_exit(unregister_%%MODEL_NAME%%);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("dot2k: auto-generated");
+MODULE_DESCRIPTION("%%MODEL_NAME%%: %%DESCRIPTION%%");
diff --git a/tools/verification/dot2/dot2k_templates/main_container.h b/tools/verification/dot2/dot2k_templates/main_container.h
new file mode 100644
index 000000000000..0f6883ab4bcc
--- /dev/null
+++ b/tools/verification/dot2/dot2k_templates/main_container.h
@@ -0,0 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+extern struct rv_monitor rv_%%MODEL_NAME%%;
diff --git a/tools/verification/dot2/dot2k_templates/main_global.c b/tools/verification/dot2/dot2k_templates/main_global.c
deleted file mode 100644
index a5658bfb9044..000000000000
--- a/tools/verification/dot2/dot2k_templates/main_global.c
+++ /dev/null
@@ -1,91 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/ftrace.h>
-#include <linux/tracepoint.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/rv.h>
-#include <rv/instrumentation.h>
-#include <rv/da_monitor.h>
-
-#define MODULE_NAME "MODEL_NAME"
-
-/*
- * XXX: include required tracepoint headers, e.g.,
- * #include <trace/events/sched.h>
- */
-#include <trace/events/rv.h>
-
-/*
- * This is the self-generated part of the monitor. Generally, there is no need
- * to touch this section.
- */
-#include "MODEL_NAME.h"
-
-/*
- * Declare the deterministic automata monitor.
- *
- * The rv monitor reference is needed for the monitor declaration.
- */
-static struct rv_monitor rv_MODEL_NAME;
-DECLARE_DA_MON_GLOBAL(MODEL_NAME, MIN_TYPE);
-
-/*
- * This is the instrumentation part of the monitor.
- *
- * This is the section where manual work is required. Here the kernel events
- * are translated into model's event.
- *
- */
-TRACEPOINT_HANDLERS_SKEL
-static int enable_MODEL_NAME(void)
-{
- int retval;
-
- retval = da_monitor_init_MODEL_NAME();
- if (retval)
- return retval;
-
-TRACEPOINT_ATTACH
-
- return 0;
-}
-
-static void disable_MODEL_NAME(void)
-{
- rv_MODEL_NAME.enabled = 0;
-
-TRACEPOINT_DETACH
-
- da_monitor_destroy_MODEL_NAME();
-}
-
-/*
- * This is the monitor register section.
- */
-static struct rv_monitor rv_MODEL_NAME = {
- .name = "MODEL_NAME",
- .description = "auto-generated MODEL_NAME",
- .enable = enable_MODEL_NAME,
- .disable = disable_MODEL_NAME,
- .reset = da_monitor_reset_all_MODEL_NAME,
- .enabled = 0,
-};
-
-static int __init register_MODEL_NAME(void)
-{
- rv_register_monitor(&rv_MODEL_NAME);
- return 0;
-}
-
-static void __exit unregister_MODEL_NAME(void)
-{
- rv_unregister_monitor(&rv_MODEL_NAME);
-}
-
-module_init(register_MODEL_NAME);
-module_exit(unregister_MODEL_NAME);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("dot2k: auto-generated");
-MODULE_DESCRIPTION("MODEL_NAME");
diff --git a/tools/verification/dot2/dot2k_templates/main_per_cpu.c b/tools/verification/dot2/dot2k_templates/main_per_cpu.c
deleted file mode 100644
index 03539a97633f..000000000000
--- a/tools/verification/dot2/dot2k_templates/main_per_cpu.c
+++ /dev/null
@@ -1,91 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/ftrace.h>
-#include <linux/tracepoint.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/rv.h>
-#include <rv/instrumentation.h>
-#include <rv/da_monitor.h>
-
-#define MODULE_NAME "MODEL_NAME"
-
-/*
- * XXX: include required tracepoint headers, e.g.,
- * #include <linux/trace/events/sched.h>
- */
-#include <trace/events/rv.h>
-
-/*
- * This is the self-generated part of the monitor. Generally, there is no need
- * to touch this section.
- */
-#include "MODEL_NAME.h"
-
-/*
- * Declare the deterministic automata monitor.
- *
- * The rv monitor reference is needed for the monitor declaration.
- */
-static struct rv_monitor rv_MODEL_NAME;
-DECLARE_DA_MON_PER_CPU(MODEL_NAME, MIN_TYPE);
-
-/*
- * This is the instrumentation part of the monitor.
- *
- * This is the section where manual work is required. Here the kernel events
- * are translated into model's event.
- *
- */
-TRACEPOINT_HANDLERS_SKEL
-static int enable_MODEL_NAME(void)
-{
- int retval;
-
- retval = da_monitor_init_MODEL_NAME();
- if (retval)
- return retval;
-
-TRACEPOINT_ATTACH
-
- return 0;
-}
-
-static void disable_MODEL_NAME(void)
-{
- rv_MODEL_NAME.enabled = 0;
-
-TRACEPOINT_DETACH
-
- da_monitor_destroy_MODEL_NAME();
-}
-
-/*
- * This is the monitor register section.
- */
-static struct rv_monitor rv_MODEL_NAME = {
- .name = "MODEL_NAME",
- .description = "auto-generated MODEL_NAME",
- .enable = enable_MODEL_NAME,
- .disable = disable_MODEL_NAME,
- .reset = da_monitor_reset_all_MODEL_NAME,
- .enabled = 0,
-};
-
-static int __init register_MODEL_NAME(void)
-{
- rv_register_monitor(&rv_MODEL_NAME);
- return 0;
-}
-
-static void __exit unregister_MODEL_NAME(void)
-{
- rv_unregister_monitor(&rv_MODEL_NAME);
-}
-
-module_init(register_MODEL_NAME);
-module_exit(unregister_MODEL_NAME);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("dot2k: auto-generated");
-MODULE_DESCRIPTION("MODEL_NAME");
diff --git a/tools/verification/dot2/dot2k_templates/main_per_task.c b/tools/verification/dot2/dot2k_templates/main_per_task.c
deleted file mode 100644
index ffd92af87a86..000000000000
--- a/tools/verification/dot2/dot2k_templates/main_per_task.c
+++ /dev/null
@@ -1,91 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/ftrace.h>
-#include <linux/tracepoint.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/rv.h>
-#include <rv/instrumentation.h>
-#include <rv/da_monitor.h>
-
-#define MODULE_NAME "MODEL_NAME"
-
-/*
- * XXX: include required tracepoint headers, e.g.,
- * #include <linux/trace/events/sched.h>
- */
-#include <trace/events/rv.h>
-
-/*
- * This is the self-generated part of the monitor. Generally, there is no need
- * to touch this section.
- */
-#include "MODEL_NAME.h"
-
-/*
- * Declare the deterministic automata monitor.
- *
- * The rv monitor reference is needed for the monitor declaration.
- */
-static struct rv_monitor rv_MODEL_NAME;
-DECLARE_DA_MON_PER_TASK(MODEL_NAME, MIN_TYPE);
-
-/*
- * This is the instrumentation part of the monitor.
- *
- * This is the section where manual work is required. Here the kernel events
- * are translated into model's event.
- *
- */
-TRACEPOINT_HANDLERS_SKEL
-static int enable_MODEL_NAME(void)
-{
- int retval;
-
- retval = da_monitor_init_MODEL_NAME();
- if (retval)
- return retval;
-
-TRACEPOINT_ATTACH
-
- return 0;
-}
-
-static void disable_MODEL_NAME(void)
-{
- rv_MODEL_NAME.enabled = 0;
-
-TRACEPOINT_DETACH
-
- da_monitor_destroy_MODEL_NAME();
-}
-
-/*
- * This is the monitor register section.
- */
-static struct rv_monitor rv_MODEL_NAME = {
- .name = "MODEL_NAME",
- .description = "auto-generated MODEL_NAME",
- .enable = enable_MODEL_NAME,
- .disable = disable_MODEL_NAME,
- .reset = da_monitor_reset_all_MODEL_NAME,
- .enabled = 0,
-};
-
-static int __init register_MODEL_NAME(void)
-{
- rv_register_monitor(&rv_MODEL_NAME);
- return 0;
-}
-
-static void __exit unregister_MODEL_NAME(void)
-{
- rv_unregister_monitor(&rv_MODEL_NAME);
-}
-
-module_init(register_MODEL_NAME);
-module_exit(unregister_MODEL_NAME);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("dot2k: auto-generated");
-MODULE_DESCRIPTION("MODEL_NAME");
diff --git a/tools/verification/dot2/dot2k_templates/trace.h b/tools/verification/dot2/dot2k_templates/trace.h
new file mode 100644
index 000000000000..87d3a1308926
--- /dev/null
+++ b/tools/verification/dot2/dot2k_templates/trace.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Snippet to be included in rv_trace.h
+ */
+
+#ifdef CONFIG_RV_MON_%%MODEL_NAME_UP%%
+DEFINE_EVENT(event_%%MONITOR_CLASS%%, event_%%MODEL_NAME%%,
+%%TRACEPOINT_ARGS_SKEL_EVENT%%);
+
+DEFINE_EVENT(error_%%MONITOR_CLASS%%, error_%%MODEL_NAME%%,
+%%TRACEPOINT_ARGS_SKEL_ERROR%%);
+#endif /* CONFIG_RV_MON_%%MODEL_NAME_UP%% */
diff --git a/tools/verification/models/sched/sco.dot b/tools/verification/models/sched/sco.dot
new file mode 100644
index 000000000000..20b0e3b449a6
--- /dev/null
+++ b/tools/verification/models/sched/sco.dot
@@ -0,0 +1,18 @@
+digraph state_automaton {
+ center = true;
+ size = "7,11";
+ {node [shape = plaintext] "scheduling_context"};
+ {node [shape = plaintext, style=invis, label=""] "__init_thread_context"};
+ {node [shape = ellipse] "thread_context"};
+ {node [shape = plaintext] "thread_context"};
+ "__init_thread_context" -> "thread_context";
+ "scheduling_context" [label = "scheduling_context"];
+ "scheduling_context" -> "thread_context" [ label = "schedule_exit" ];
+ "thread_context" [label = "thread_context", color = green3];
+ "thread_context" -> "scheduling_context" [ label = "schedule_entry" ];
+ "thread_context" -> "thread_context" [ label = "sched_set_state" ];
+ { rank = min ;
+ "__init_thread_context";
+ "thread_context";
+ }
+}
diff --git a/tools/verification/models/sched/scpd.dot b/tools/verification/models/sched/scpd.dot
new file mode 100644
index 000000000000..340413896765
--- /dev/null
+++ b/tools/verification/models/sched/scpd.dot
@@ -0,0 +1,18 @@
+digraph state_automaton {
+ center = true;
+ size = "7,11";
+ {node [shape = plaintext] "can_sched"};
+ {node [shape = plaintext, style=invis, label=""] "__init_cant_sched"};
+ {node [shape = ellipse] "cant_sched"};
+ {node [shape = plaintext] "cant_sched"};
+ "__init_cant_sched" -> "cant_sched";
+ "can_sched" [label = "can_sched"];
+ "can_sched" -> "can_sched" [ label = "schedule_entry\nschedule_exit" ];
+ "can_sched" -> "cant_sched" [ label = "preempt_enable" ];
+ "cant_sched" [label = "cant_sched", color = green3];
+ "cant_sched" -> "can_sched" [ label = "preempt_disable" ];
+ { rank = min ;
+ "__init_cant_sched";
+ "cant_sched";
+ }
+}
diff --git a/tools/verification/models/sched/sncid.dot b/tools/verification/models/sched/sncid.dot
new file mode 100644
index 000000000000..072851721b50
--- /dev/null
+++ b/tools/verification/models/sched/sncid.dot
@@ -0,0 +1,18 @@
+digraph state_automaton {
+ center = true;
+ size = "7,11";
+ {node [shape = plaintext, style=invis, label=""] "__init_can_sched"};
+ {node [shape = ellipse] "can_sched"};
+ {node [shape = plaintext] "can_sched"};
+ {node [shape = plaintext] "cant_sched"};
+ "__init_can_sched" -> "can_sched";
+ "can_sched" [label = "can_sched", color = green3];
+ "can_sched" -> "can_sched" [ label = "schedule_entry\nschedule_exit" ];
+ "can_sched" -> "cant_sched" [ label = "irq_disable" ];
+ "cant_sched" [label = "cant_sched"];
+ "cant_sched" -> "can_sched" [ label = "irq_enable" ];
+ { rank = min ;
+ "__init_can_sched";
+ "can_sched";
+ }
+}
diff --git a/tools/verification/models/sched/snep.dot b/tools/verification/models/sched/snep.dot
new file mode 100644
index 000000000000..fe1300e93f21
--- /dev/null
+++ b/tools/verification/models/sched/snep.dot
@@ -0,0 +1,18 @@
+digraph state_automaton {
+ center = true;
+ size = "7,11";
+ {node [shape = plaintext, style=invis, label=""] "__init_non_scheduling_context"};
+ {node [shape = ellipse] "non_scheduling_context"};
+ {node [shape = plaintext] "non_scheduling_context"};
+ {node [shape = plaintext] "scheduling_contex"};
+ "__init_non_scheduling_context" -> "non_scheduling_context";
+ "non_scheduling_context" [label = "non_scheduling_context", color = green3];
+ "non_scheduling_context" -> "non_scheduling_context" [ label = "preempt_disable\npreempt_enable" ];
+ "non_scheduling_context" -> "scheduling_contex" [ label = "schedule_entry" ];
+ "scheduling_contex" [label = "scheduling_contex"];
+ "scheduling_contex" -> "non_scheduling_context" [ label = "schedule_exit" ];
+ { rank = min ;
+ "__init_non_scheduling_context";
+ "non_scheduling_context";
+ }
+}
diff --git a/tools/verification/models/sched/snroc.dot b/tools/verification/models/sched/snroc.dot
new file mode 100644
index 000000000000..8b71c32d4dca
--- /dev/null
+++ b/tools/verification/models/sched/snroc.dot
@@ -0,0 +1,18 @@
+digraph state_automaton {
+ center = true;
+ size = "7,11";
+ {node [shape = plaintext, style=invis, label=""] "__init_other_context"};
+ {node [shape = ellipse] "other_context"};
+ {node [shape = plaintext] "other_context"};
+ {node [shape = plaintext] "own_context"};
+ "__init_other_context" -> "other_context";
+ "other_context" [label = "other_context", color = green3];
+ "other_context" -> "own_context" [ label = "sched_switch_in" ];
+ "own_context" [label = "own_context"];
+ "own_context" -> "other_context" [ label = "sched_switch_out" ];
+ "own_context" -> "own_context" [ label = "sched_set_state" ];
+ { rank = min ;
+ "__init_other_context";
+ "other_context";
+ }
+}
diff --git a/tools/verification/models/sched/tss.dot b/tools/verification/models/sched/tss.dot
new file mode 100644
index 000000000000..7dfa1d9121bb
--- /dev/null
+++ b/tools/verification/models/sched/tss.dot
@@ -0,0 +1,18 @@
+digraph state_automaton {
+ center = true;
+ size = "7,11";
+ {node [shape = plaintext] "sched"};
+ {node [shape = plaintext, style=invis, label=""] "__init_thread"};
+ {node [shape = ellipse] "thread"};
+ {node [shape = plaintext] "thread"};
+ "__init_thread" -> "thread";
+ "sched" [label = "sched"];
+ "sched" -> "sched" [ label = "sched_switch" ];
+ "sched" -> "thread" [ label = "schedule_exit" ];
+ "thread" [label = "thread", color = green3];
+ "thread" -> "sched" [ label = "schedule_entry" ];
+ { rank = min ;
+ "__init_thread";
+ "thread";
+ }
+}
diff --git a/tools/verification/rv/Makefile b/tools/verification/rv/Makefile
index 411d62b3d8eb..5b898360ba48 100644
--- a/tools/verification/rv/Makefile
+++ b/tools/verification/rv/Makefile
@@ -35,12 +35,6 @@ FEATURE_TESTS += libtracefs
FEATURE_DISPLAY := libtraceevent
FEATURE_DISPLAY += libtracefs
-ifeq ($(V),1)
- Q =
-else
- Q = @
-endif
-
all: $(RV)
include $(srctree)/tools/build/Makefile.include
diff --git a/tools/verification/rv/Makefile.rv b/tools/verification/rv/Makefile.rv
index 161baa29eb86..2497fb96c83d 100644
--- a/tools/verification/rv/Makefile.rv
+++ b/tools/verification/rv/Makefile.rv
@@ -27,7 +27,7 @@ endif
INCLUDE := -Iinclude/
CFLAGS := -g -DVERSION=\"$(VERSION)\" $(FOPTS) $(WOPTS) $(EXTRA_CFLAGS) $(INCLUDE)
-LDFLAGS := -ggdb $(EXTRA_LDFLAGS)
+LDFLAGS := -ggdb $(LDFLAGS) $(EXTRA_LDFLAGS)
INSTALL := install
MKDIR := mkdir
diff --git a/tools/verification/rv/include/in_kernel.h b/tools/verification/rv/include/in_kernel.h
index 3090638c8d71..f3bfd3b9895f 100644
--- a/tools/verification/rv/include/in_kernel.h
+++ b/tools/verification/rv/include/in_kernel.h
@@ -1,3 +1,3 @@
// SPDX-License-Identifier: GPL-2.0
-int ikm_list_monitors(void);
+int ikm_list_monitors(char *container);
int ikm_run_monitor(char *monitor, int argc, char **argv);
diff --git a/tools/verification/rv/include/rv.h b/tools/verification/rv/include/rv.h
index 770fd6da3610..6f668eb266cb 100644
--- a/tools/verification/rv/include/rv.h
+++ b/tools/verification/rv/include/rv.h
@@ -1,12 +1,13 @@
// SPDX-License-Identifier: GPL-2.0
#define MAX_DESCRIPTION 1024
-#define MAX_DA_NAME_LEN 24
+#define MAX_DA_NAME_LEN 32
struct monitor {
char name[MAX_DA_NAME_LEN];
char desc[MAX_DESCRIPTION];
int enabled;
+ int nested;
};
int should_stop(void);
diff --git a/tools/verification/rv/src/in_kernel.c b/tools/verification/rv/src/in_kernel.c
index f2bbc75a76f4..c0dcee795c0d 100644
--- a/tools/verification/rv/src/in_kernel.c
+++ b/tools/verification/rv/src/in_kernel.c
@@ -6,15 +6,18 @@
*/
#include <getopt.h>
#include <stdlib.h>
+#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
+#include <dirent.h>
#include <trace.h>
#include <utils.h>
#include <rv.h>
static int config_has_id;
+static int config_is_container;
static int config_my_pid;
static int config_trace;
@@ -45,6 +48,51 @@ static int __ikm_read_enable(char *monitor_name)
}
/*
+ * __ikm_find_monitor - find the full name of a possibly nested module
+ *
+ * __does not log errors.
+ *
+ * Returns 1 if we found the monitor, -1 on error and 0 if it does not exist.
+ * The string out_name is populated with the full name, which can be
+ * equal to monitor_name or container/monitor_name if nested
+ */
+static int __ikm_find_monitor_name(char *monitor_name, char *out_name)
+{
+ char *available_monitors, container[MAX_DA_NAME_LEN+1], *cursor, *end;
+ int retval = 1;
+
+ available_monitors = tracefs_instance_file_read(NULL, "rv/available_monitors", NULL);
+ if (!available_monitors)
+ return -1;
+
+ cursor = strstr(available_monitors, monitor_name);
+ if (!cursor) {
+ retval = 0;
+ goto out_free;
+ }
+
+ for (; cursor > available_monitors; cursor--)
+ if (*(cursor-1) == '\n')
+ break;
+ end = strstr(cursor, "\n");
+ memcpy(out_name, cursor, end-cursor);
+ out_name[end-cursor] = '\0';
+
+ cursor = strstr(out_name, ":");
+ if (cursor)
+ *cursor = '/';
+ else {
+ sprintf(container, "%s:", monitor_name);
+ if (strstr(available_monitors, container))
+ config_is_container = 1;
+ }
+
+out_free:
+ free(available_monitors);
+ return retval;
+}
+
+/*
* ikm_read_enable - reads monitor's enable status
*
* Returns the current status, or -1 on error.
@@ -132,12 +180,28 @@ static char *ikm_read_desc(char *monitor_name)
/*
* ikm_fill_monitor_definition - fill monitor's definition
*
- * Returns -1 on error, 0 otherwise.
+ * Returns -1 on error, 1 if the monitor does not belong in the container, 0 otherwise.
+ * container can be NULL
*/
-static int ikm_fill_monitor_definition(char *name, struct monitor *ikm)
+static int ikm_fill_monitor_definition(char *name, struct monitor *ikm, char *container)
{
int enabled;
- char *desc;
+ char *desc, *nested_name;
+
+ nested_name = strstr(name, ":");
+ if (nested_name) {
+ /* it belongs in container if it starts with "container:" */
+ if (container && strstr(name, container) != name)
+ return 1;
+ *nested_name = '/';
+ ++nested_name;
+ ikm->nested = 1;
+ } else {
+ if (container)
+ return 1;
+ nested_name = name;
+ ikm->nested = 0;
+ }
enabled = ikm_read_enable(name);
if (enabled < 0) {
@@ -151,7 +215,7 @@ static int ikm_fill_monitor_definition(char *name, struct monitor *ikm)
return -1;
}
- strncpy(ikm->name, name, MAX_DA_NAME_LEN);
+ strncpy(ikm->name, nested_name, MAX_DA_NAME_LEN);
ikm->enabled = enabled;
strncpy(ikm->desc, desc, MAX_DESCRIPTION);
@@ -270,12 +334,12 @@ static int ikm_has_id(char *monitor_name)
*
* Returns 0 on success, -1 otherwise.
*/
-int ikm_list_monitors(void)
+int ikm_list_monitors(char *container)
{
char *available_monitors;
- struct monitor ikm;
+ struct monitor ikm = {0};
char *curr, *next;
- int retval;
+ int retval, list_monitor = 0;
available_monitors = tracefs_instance_file_read(NULL, "rv/available_monitors", NULL);
@@ -289,15 +353,29 @@ int ikm_list_monitors(void)
next = strstr(curr, "\n");
*next = '\0';
- retval = ikm_fill_monitor_definition(curr, &ikm);
- if (retval)
+ retval = ikm_fill_monitor_definition(curr, &ikm, container);
+ if (retval < 0)
err_msg("ikm: error reading %d in kernel monitor, skipping\n", curr);
- printf("%-24s %s %s\n", ikm.name, ikm.desc, ikm.enabled ? "[ON]" : "[OFF]");
+ if (!retval) {
+ int indent = ikm.nested && !container;
+
+ list_monitor = 1;
+ printf("%s%-*s %s %s\n", indent ? " - " : "",
+ indent ? MAX_DA_NAME_LEN - 3 : MAX_DA_NAME_LEN,
+ ikm.name, ikm.desc, ikm.enabled ? "[ON]" : "[OFF]");
+ }
curr = ++next;
} while (strlen(curr));
+ if (!list_monitor) {
+ if (container)
+ printf("-- No monitor found in container %s --\n", container);
+ else
+ printf("-- No monitor found --\n");
+ }
+
free(available_monitors);
return 0;
@@ -343,11 +421,11 @@ ikm_event_handler(struct trace_seq *s, struct tep_record *record,
unsigned long long final_state;
unsigned long long pid;
unsigned long long id;
- int cpu = record->cpu;
int val;
+ bool missing_id;
if (config_has_id)
- tep_get_field_val(s, trace_event, "id", record, &id, 1);
+ missing_id = tep_get_field_val(s, trace_event, "id", record, &id, 1);
tep_get_common_field_val(s, trace_event, "common_pid", record, &pid, 1);
@@ -356,12 +434,21 @@ ikm_event_handler(struct trace_seq *s, struct tep_record *record,
else if (config_my_pid && (config_my_pid == pid))
return 0;
- tep_print_event(trace_event->tep, s, record, "%16s-%-8d ", TEP_PRINT_COMM, TEP_PRINT_PID);
+ tep_print_event(trace_event->tep, s, record, "%16s-%-8d [%.3d] ",
+ TEP_PRINT_COMM, TEP_PRINT_PID, TEP_PRINT_CPU);
- trace_seq_printf(s, "[%.3d] event ", cpu);
+ if (config_is_container)
+ tep_print_event(trace_event->tep, s, record, "%s ", TEP_PRINT_NAME);
+ else
+ trace_seq_printf(s, "event ");
- if (config_has_id)
- trace_seq_printf(s, "%8llu ", id);
+ if (config_has_id) {
+ if (missing_id)
+ /* placeholder if we are dealing with a mixed-type container*/
+ trace_seq_printf(s, " ");
+ else
+ trace_seq_printf(s, "%8llu ", id);
+ }
state = tep_get_field_raw(s, trace_event, "state", record, &val, 0);
event = tep_get_field_raw(s, trace_event, "event", record, &val, 0);
@@ -394,9 +481,10 @@ ikm_error_handler(struct trace_seq *s, struct tep_record *record,
int cpu = record->cpu;
char *state, *event;
int val;
+ bool missing_id;
if (config_has_id)
- tep_get_field_val(s, trace_event, "id", record, &id, 1);
+ missing_id = tep_get_field_val(s, trace_event, "id", record, &id, 1);
tep_get_common_field_val(s, trace_event, "common_pid", record, &pid, 1);
@@ -405,10 +493,20 @@ ikm_error_handler(struct trace_seq *s, struct tep_record *record,
else if (config_my_pid == pid)
return 0;
- trace_seq_printf(s, "%8lld [%03d] error ", pid, cpu);
+ trace_seq_printf(s, "%8lld [%03d] ", pid, cpu);
- if (config_has_id)
- trace_seq_printf(s, "%8llu ", id);
+ if (config_is_container)
+ tep_print_event(trace_event->tep, s, record, "%s ", TEP_PRINT_NAME);
+ else
+ trace_seq_printf(s, "error ");
+
+ if (config_has_id) {
+ if (missing_id)
+ /* placeholder if we are dealing with a mixed-type container*/
+ trace_seq_printf(s, " ");
+ else
+ trace_seq_printf(s, "%8llu ", id);
+ }
state = tep_get_field_raw(s, trace_event, "state", record, &val, 0);
event = tep_get_field_raw(s, trace_event, "event", record, &val, 0);
@@ -421,6 +519,64 @@ ikm_error_handler(struct trace_seq *s, struct tep_record *record,
return 0;
}
+static int ikm_enable_trace_events(char *monitor_name, struct trace_instance *inst)
+{
+ char event[MAX_DA_NAME_LEN + 7]; /* max(error_,event_) + '0' = 7 */
+ int retval;
+
+ snprintf(event, sizeof(event), "event_%s", monitor_name);
+ retval = tracefs_event_enable(inst->inst, "rv", event);
+ if (retval)
+ return -1;
+
+ tep_register_event_handler(inst->tep, -1, "rv", event,
+ ikm_event_handler, NULL);
+
+ snprintf(event, sizeof(event), "error_%s", monitor_name);
+ retval = tracefs_event_enable(inst->inst, "rv", event);
+ if (retval)
+ return -1;
+
+ tep_register_event_handler(inst->tep, -1, "rv", event,
+ ikm_error_handler, NULL);
+
+ /* set if at least 1 monitor has id in case of a container */
+ config_has_id = ikm_has_id(monitor_name);
+ if (config_has_id < 0)
+ return -1;
+
+
+ return 0;
+}
+
+static int ikm_enable_trace_container(char *monitor_name,
+ struct trace_instance *inst)
+{
+ DIR *dp;
+ char *abs_path, rv_path[MAX_PATH];
+ struct dirent *ep;
+ int retval = 0;
+
+ snprintf(rv_path, MAX_PATH, "rv/monitors/%s", monitor_name);
+ abs_path = tracefs_instance_get_file(NULL, rv_path);
+ if (!abs_path)
+ return -1;
+ dp = opendir(abs_path);
+ if (!dp)
+ goto out_free;
+
+ while (!retval && (ep = readdir(dp))) {
+ if (ep->d_type != DT_DIR || ep->d_name[0] == '.')
+ continue;
+ retval = ikm_enable_trace_events(ep->d_name, inst);
+ }
+
+ closedir(dp);
+out_free:
+ free(abs_path);
+ return retval;
+}
+
/*
* ikm_setup_trace_instance - set up a tracing instance to collect data
*
@@ -430,19 +586,12 @@ ikm_error_handler(struct trace_seq *s, struct tep_record *record,
*/
static struct trace_instance *ikm_setup_trace_instance(char *monitor_name)
{
- char event[MAX_DA_NAME_LEN + 7]; /* max(error_,event_) + '0' = 7 */
struct trace_instance *inst;
int retval;
if (!config_trace)
return NULL;
- config_has_id = ikm_has_id(monitor_name);
- if (config_has_id < 0) {
- err_msg("ikm: failed to read monitor %s event format\n", monitor_name);
- goto out_err;
- }
-
/* alloc data */
inst = calloc(1, sizeof(*inst));
if (!inst) {
@@ -454,23 +603,13 @@ static struct trace_instance *ikm_setup_trace_instance(char *monitor_name)
if (retval)
goto out_free;
- /* enable events */
- snprintf(event, sizeof(event), "event_%s", monitor_name);
- retval = tracefs_event_enable(inst->inst, "rv", event);
+ if (config_is_container)
+ retval = ikm_enable_trace_container(monitor_name, inst);
+ else
+ retval = ikm_enable_trace_events(monitor_name, inst);
if (retval)
goto out_inst;
- tep_register_event_handler(inst->tep, -1, "rv", event,
- ikm_event_handler, NULL);
-
- snprintf(event, sizeof(event), "error_%s", monitor_name);
- retval = tracefs_event_enable(inst->inst, "rv", event);
- if (retval)
- goto out_inst;
-
- tep_register_event_handler(inst->tep, -1, "rv", event,
- ikm_error_handler, NULL);
-
/* ready to enable */
tracefs_trace_on(inst->inst);
@@ -633,32 +772,41 @@ static int parse_arguments(char *monitor_name, int argc, char **argv)
int ikm_run_monitor(char *monitor_name, int argc, char **argv)
{
struct trace_instance *inst = NULL;
+ char *nested_name, full_name[2*MAX_DA_NAME_LEN];
int retval;
- /*
- * Check if monitor exists by seeing it is enabled.
- */
- retval = __ikm_read_enable(monitor_name);
- if (retval < 0)
+ nested_name = strstr(monitor_name, ":");
+ if (nested_name)
+ ++nested_name;
+ else
+ nested_name = monitor_name;
+
+ retval = __ikm_find_monitor_name(monitor_name, full_name);
+ if (!retval)
return 0;
+ if (retval < 0) {
+ err_msg("ikm: error finding monitor %s\n", nested_name);
+ return -1;
+ }
+ retval = __ikm_read_enable(full_name);
if (retval) {
- err_msg("ikm: monitor %s (in-kernel) is already enabled\n", monitor_name);
+ err_msg("ikm: monitor %s (in-kernel) is already enabled\n", nested_name);
return -1;
}
/* we should be good to go */
- retval = parse_arguments(monitor_name, argc, argv);
+ retval = parse_arguments(full_name, argc, argv);
if (retval)
- ikm_usage(1, monitor_name, "ikm: failed parsing arguments");
+ ikm_usage(1, nested_name, "ikm: failed parsing arguments");
if (config_trace) {
- inst = ikm_setup_trace_instance(monitor_name);
+ inst = ikm_setup_trace_instance(nested_name);
if (!inst)
return -1;
}
- retval = ikm_enable(monitor_name);
+ retval = ikm_enable(full_name);
if (retval < 0)
goto out_free_instance;
@@ -682,17 +830,17 @@ int ikm_run_monitor(char *monitor_name, int argc, char **argv)
sleep(1);
}
- ikm_disable(monitor_name);
+ ikm_disable(full_name);
ikm_destroy_trace_instance(inst);
if (config_reactor && config_initial_reactor)
- ikm_write_reactor(monitor_name, config_initial_reactor);
+ ikm_write_reactor(full_name, config_initial_reactor);
return 1;
out_free_instance:
ikm_destroy_trace_instance(inst);
if (config_reactor && config_initial_reactor)
- ikm_write_reactor(monitor_name, config_initial_reactor);
+ ikm_write_reactor(full_name, config_initial_reactor);
return -1;
}
diff --git a/tools/verification/rv/src/rv.c b/tools/verification/rv/src/rv.c
index 1ddb85532816..239de054d1e0 100644
--- a/tools/verification/rv/src/rv.c
+++ b/tools/verification/rv/src/rv.c
@@ -41,30 +41,42 @@ static void rv_list(int argc, char **argv)
{
static const char *const usage[] = {
"",
- " usage: rv list [-h]",
+ " usage: rv list [-h] [container]",
"",
" list all available monitors",
"",
" -h/--help: print this menu",
+ "",
+ " [container]: list only monitors in this container",
NULL,
};
- int i;
-
- if (argc > 1) {
+ int i, print_help = 0, retval = 0;
+ char *container = NULL;
+
+ if (argc == 2) {
+ if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
+ print_help = 1;
+ retval = 0;
+ } else if (argv[1][0] == '-') {
+ /* assume invalid option */
+ print_help = 1;
+ retval = 1;
+ } else
+ container = argv[1];
+ } else if (argc > 2) {
+ /* more than 2 is always usage */
+ print_help = 1;
+ retval = 1;
+ }
+ if (print_help) {
fprintf(stderr, "rv version %s\n", VERSION);
-
- /* more than 1 is always usage */
for (i = 0; usage[i]; i++)
fprintf(stderr, "%s\n", usage[i]);
-
- /* but only -h is valid */
- if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
- exit(0);
- else
- exit(1);
+ exit(retval);
}
- ikm_list_monitors();
+ ikm_list_monitors(container);
+
exit(0);
}