* [PATCH 07/26] rv/rvgen: replace __contains__() with in operator
From: Wander Lairson Costa @ 2026-01-19 20:45 UTC (permalink / raw)
To: Steven Rostedt, Gabriele Monaco, Nam Cao, Wander Lairson Costa,
open list, open list:RUNTIME VERIFICATION (RV)
In-Reply-To: <20260119205601.105821-1-wander@redhat.com>
Replace the direct call to the __contains__() dunder method with the
idiomatic in operator in the dot2c module. The previous implementation
explicitly called the __contains__() method to check for membership in
the final_states collection, which is not the recommended Python
style.
Python provides the in operator as the proper way to test membership,
which internally calls the __contains__() method. Directly calling
dunder methods bypasses Python's abstraction layer and reduces code
readability. Using the in operator makes the code more natural and
familiar to Python developers while maintaining identical functionality.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/verification/rvgen/rvgen/dot2c.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/verification/rvgen/rvgen/dot2c.py b/tools/verification/rvgen/rvgen/dot2c.py
index b9a2c009a9246..c97bb9466af6d 100644
--- a/tools/verification/rvgen/rvgen/dot2c.py
+++ b/tools/verification/rvgen/rvgen/dot2c.py
@@ -207,7 +207,7 @@ class Dot2c(Automata):
else:
first = False
- if self.final_states.__contains__(state):
+ if state in self.final_states:
line = line + '1'
else:
line = line + '0'
--
2.52.0
^ permalink raw reply related
* [PATCH 06/26] rv/rvgen: use context managers for file operations
From: Wander Lairson Costa @ 2026-01-19 20:45 UTC (permalink / raw)
To: Steven Rostedt, Gabriele Monaco, Nam Cao, Wander Lairson Costa,
open list, open list:RUNTIME VERIFICATION (RV)
In-Reply-To: <20260119205601.105821-1-wander@redhat.com>
Replace manual file open and close operations with context managers
throughout the rvgen codebase. The previous implementation used
explicit open() and close() calls, which could lead to resource leaks
if exceptions occurred between opening and closing the file handles.
This change affects three file operations: reading DOT specification
files in the automata parser, reading template files in the generator
base class, and writing generated monitor files. All now use the with
statement to ensure proper resource cleanup even in error conditions.
Context managers provide automatic cleanup through the with statement,
which guarantees that file handles are closed when the with block
exits regardless of whether an exception occurred. This follows PEP
343 recommendations and is the standard Python idiom for resource
management. The change also reduces code verbosity while improving
safety and maintainability.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/verification/rvgen/rvgen/automata.py | 6 ++----
tools/verification/rvgen/rvgen/generator.py | 12 ++++--------
2 files changed, 6 insertions(+), 12 deletions(-)
diff --git a/tools/verification/rvgen/rvgen/automata.py b/tools/verification/rvgen/rvgen/automata.py
index ed02d0c69b410..70ff98abea751 100644
--- a/tools/verification/rvgen/rvgen/automata.py
+++ b/tools/verification/rvgen/rvgen/automata.py
@@ -51,13 +51,11 @@ class Automata:
cursor = 0
dot_lines = []
try:
- dot_file = open(self.__dot_path)
+ with open(self.__dot_path) as dot_file:
+ dot_lines = dot_file.read().splitlines()
except OSError as exc:
raise AutomataError(f"Cannot open the file: {self.__dot_path}") from exc
- dot_lines = dot_file.read().splitlines()
- dot_file.close()
-
# checking the first line:
line = dot_lines[cursor].split()
diff --git a/tools/verification/rvgen/rvgen/generator.py b/tools/verification/rvgen/rvgen/generator.py
index 6d16fb68798a7..ee75e111feef1 100644
--- a/tools/verification/rvgen/rvgen/generator.py
+++ b/tools/verification/rvgen/rvgen/generator.py
@@ -51,11 +51,8 @@ class RVGenerator:
raise FileNotFoundError("Could not find the rv directory, do you have the kernel source installed?")
def _read_file(self, path):
- fd = open(path, 'r')
-
- content = fd.read()
-
- fd.close()
+ with open(path, 'r') as fd:
+ content = fd.read()
return content
def _read_template_file(self, file):
@@ -199,9 +196,8 @@ obj-$(CONFIG_RV_MON_{name_up}) += monitors/{name}/{name}.o
return
def __write_file(self, file_name, content):
- file = open(file_name, 'w')
- file.write(content)
- file.close()
+ with open(file_name, 'w') as file:
+ file.write(content)
def _create_file(self, file_name, content):
path = f"{self.name}/{file_name}"
--
2.52.0
^ permalink raw reply related
* [PATCH 05/26] rv/rvgen: remove unnecessary semicolons
From: Wander Lairson Costa @ 2026-01-19 20:45 UTC (permalink / raw)
To: Steven Rostedt, Gabriele Monaco, Nam Cao, Wander Lairson Costa,
open list, open list:RUNTIME VERIFICATION (RV)
In-Reply-To: <20260119205601.105821-1-wander@redhat.com>
Remove unnecessary semicolons from Python code in the rvgen tool.
Python does not require semicolons to terminate statements, and
their presence goes against PEP 8 style guidelines. These semicolons
were likely added out of habit from C-style languages.
The changes affect four instances across two files. In dot2c.py, one
semicolon is removed from a boolean assignment. In dot2k.py, three
semicolons are removed from string append operations that build
generated C code. Note that the semicolons inside the string literals
themselves are correctly preserved as they are part of the C code
being generated, not Python syntax.
This cleanup improves consistency with Python coding standards and
aligns with the recent improvements to remove other Python
anti-patterns from the codebase.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/verification/rvgen/rvgen/dot2c.py | 2 +-
tools/verification/rvgen/rvgen/dot2k.py | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/tools/verification/rvgen/rvgen/dot2c.py b/tools/verification/rvgen/rvgen/dot2c.py
index 0fb3617ad8ce9..b9a2c009a9246 100644
--- a/tools/verification/rvgen/rvgen/dot2c.py
+++ b/tools/verification/rvgen/rvgen/dot2c.py
@@ -120,7 +120,7 @@ class Dot2c(Automata):
for entry in buff:
if first:
string = string + "\t\t\"" + entry
- first = False;
+ first = False
else:
string = string + "\",\n\t\t\"" + entry
string = string + "\""
diff --git a/tools/verification/rvgen/rvgen/dot2k.py b/tools/verification/rvgen/rvgen/dot2k.py
index 1c0d0235bdf62..291385adb2c20 100644
--- a/tools/verification/rvgen/rvgen/dot2k.py
+++ b/tools/verification/rvgen/rvgen/dot2k.py
@@ -37,10 +37,10 @@ class dot2k(Monitor, Dot2c):
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(f"\tda_{handle}_{self.name}(p, {event}{self.enum_suffix});");
+ buff.append("\tstruct task_struct *p = /* XXX: how do I get p? */;")
+ buff.append(f"\tda_{handle}_{self.name}(p, {event}{self.enum_suffix});")
else:
- buff.append(f"\tda_{handle}_{self.name}({event}{self.enum_suffix});");
+ buff.append(f"\tda_{handle}_{self.name}({event}{self.enum_suffix});")
buff.append("}")
buff.append("")
return '\n'.join(buff)
--
2.52.0
^ permalink raw reply related
* [PATCH 04/26] rv/rvgen: replace __len__() calls with len()
From: Wander Lairson Costa @ 2026-01-19 20:45 UTC (permalink / raw)
To: Steven Rostedt, Gabriele Monaco, Nam Cao, Wander Lairson Costa,
open list, open list:RUNTIME VERIFICATION (RV)
In-Reply-To: <20260119205601.105821-1-wander@redhat.com>
Replace all direct calls to the __len__() dunder method with the
idiomatic len() built-in function across the rvgen codebase. This
change eliminates a Python anti-pattern where dunder methods are
called directly instead of using their corresponding built-in
functions.
The changes affect nine instances across two files. In automata.py,
the empty string check is further improved by using truthiness
testing instead of explicit length comparison. In dot2c.py, all
length checks in the get_minimun_type, __get_max_strlen_of_states,
and get_aut_init_function methods now use the standard len()
function. Additionally, spacing around keyword arguments has been
corrected to follow PEP 8 guidelines.
Direct calls to dunder methods like __len__() are discouraged in
Python because they bypass the language's abstraction layer and
reduce code readability. Using len() provides the same functionality
while adhering to Python community standards and making the code more
familiar to Python developers.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/verification/rvgen/rvgen/automata.py | 2 +-
tools/verification/rvgen/rvgen/dot2c.py | 16 ++++++++--------
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/tools/verification/rvgen/rvgen/automata.py b/tools/verification/rvgen/rvgen/automata.py
index 3e24313a2eaec..ed02d0c69b410 100644
--- a/tools/verification/rvgen/rvgen/automata.py
+++ b/tools/verification/rvgen/rvgen/automata.py
@@ -42,7 +42,7 @@ class Automata:
raise AutomataError(f"not a dot file: {self.__dot_path}")
model_name = ntpath.splitext(basename)[0]
- if model_name.__len__() == 0:
+ if not model_name:
raise AutomataError(f"not a dot file: {self.__dot_path}")
return model_name
diff --git a/tools/verification/rvgen/rvgen/dot2c.py b/tools/verification/rvgen/rvgen/dot2c.py
index 78959d345c26e..0fb3617ad8ce9 100644
--- a/tools/verification/rvgen/rvgen/dot2c.py
+++ b/tools/verification/rvgen/rvgen/dot2c.py
@@ -86,14 +86,14 @@ class Dot2c(Automata):
def get_minimun_type(self):
min_type = "unsigned char"
- if self.states.__len__() > 255:
+ if len(self.states) > 255:
min_type = "unsigned short"
- if self.states.__len__() > 65535:
+ if len(self.states) > 65535:
min_type = "unsigned int"
- if self.states.__len__() > 1000000:
- raise AutomataError(f"Too many states: {self.states.__len__()}")
+ if len(self.states) > 1000000:
+ raise AutomataError(f"Too many states: {len(self.states)}")
return min_type
@@ -149,12 +149,12 @@ class Dot2c(Automata):
return buff
def __get_max_strlen_of_states(self):
- max_state_name = max(self.states, key = len).__len__()
- return max(max_state_name, self.invalid_state_str.__len__())
+ max_state_name = len(max(self.states, key=len))
+ return max(max_state_name, len(self.invalid_state_str))
def get_aut_init_function(self):
- nr_states = self.states.__len__()
- nr_events = self.events.__len__()
+ nr_states = len(self.states)
+ nr_events = len(self.events)
buff = []
maxlen = self.__get_max_strlen_of_states() + len(self.enum_suffix)
--
2.52.0
^ permalink raw reply related
* [PATCH 03/26] rv/rvgen: replace % string formatting with f-strings
From: Wander Lairson Costa @ 2026-01-19 20:45 UTC (permalink / raw)
To: Steven Rostedt, Gabriele Monaco, Nam Cao, Wander Lairson Costa,
open list, open list:RUNTIME VERIFICATION (RV)
In-Reply-To: <20260119205601.105821-1-wander@redhat.com>
Replace all instances of percent-style string formatting with
f-strings across the rvgen codebase. This modernizes the string
formatting to use Python 3.6+ features, providing clearer and more
maintainable code while improving runtime performance.
The conversion handles all formatting cases including simple variable
substitution, multi-variable formatting, and complex format specifiers.
Dynamic width formatting is converted from "%*s" to "{var:>{width}}"
using proper alignment syntax. Template strings for generated C code
properly escape braces using double-brace syntax to produce literal
braces in the output.
F-strings provide approximately 2x performance improvement over percent
formatting and are the recommended approach in modern Python.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/verification/rvgen/__main__.py | 6 +--
tools/verification/rvgen/rvgen/automata.py | 6 +--
tools/verification/rvgen/rvgen/dot2c.py | 40 +++++++-------
tools/verification/rvgen/rvgen/dot2k.py | 26 ++++-----
tools/verification/rvgen/rvgen/generator.py | 59 ++++++++++-----------
tools/verification/rvgen/rvgen/ltl2k.py | 30 +++++------
6 files changed, 82 insertions(+), 85 deletions(-)
diff --git a/tools/verification/rvgen/__main__.py b/tools/verification/rvgen/__main__.py
index 768b11a1e978b..eeeccf81d4b90 100644
--- a/tools/verification/rvgen/__main__.py
+++ b/tools/verification/rvgen/__main__.py
@@ -40,7 +40,7 @@ if __name__ == '__main__':
params = parser.parse_args()
if params.subcmd == "monitor":
- print("Opening and parsing the specification file %s" % params.spec)
+ print(f"Opening and parsing the specification file {params.spec}")
if params.monitor_class == "da":
monitor = dot2k(params.spec, params.monitor_type, vars(params))
elif params.monitor_class == "ltl":
@@ -51,11 +51,11 @@ if __name__ == '__main__':
else:
monitor = Container(vars(params))
- print("Writing the monitor into the directory %s" % monitor.name)
+ print(f"Writing the monitor into the directory {monitor.name}")
monitor.print_files()
print("Almost done, checklist")
if params.subcmd == "monitor":
- print(" - Edit the %s/%s.c to add the instrumentation" % (monitor.name, monitor.name))
+ print(f" - Edit the {monitor.name}/{monitor.name}.c to add the instrumentation")
print(monitor.fill_tracepoint_tooltip())
print(monitor.fill_makefile_tooltip())
print(monitor.fill_kconfig_tooltip())
diff --git a/tools/verification/rvgen/rvgen/automata.py b/tools/verification/rvgen/rvgen/automata.py
index 8d88c3b65d00d..3e24313a2eaec 100644
--- a/tools/verification/rvgen/rvgen/automata.py
+++ b/tools/verification/rvgen/rvgen/automata.py
@@ -39,11 +39,11 @@ class Automata:
basename = ntpath.basename(self.__dot_path)
if not basename.endswith(".dot") and not basename.endswith(".gv"):
print("not a dot file")
- raise AutomataError("not a dot file: %s" % self.__dot_path)
+ raise AutomataError(f"not a dot file: {self.__dot_path}")
model_name = ntpath.splitext(basename)[0]
if model_name.__len__() == 0:
- raise AutomataError("not a dot file: %s" % self.__dot_path)
+ raise AutomataError(f"not a dot file: {self.__dot_path}")
return model_name
@@ -62,7 +62,7 @@ class Automata:
line = dot_lines[cursor].split()
if (line[0] != "digraph") and (line[1] != "state_automaton"):
- raise AutomataError("Not a valid .dot format: %s" % self.__dot_path)
+ raise AutomataError(f"Not a valid .dot format: {self.__dot_path}")
else:
cursor += 1
return dot_lines
diff --git a/tools/verification/rvgen/rvgen/dot2c.py b/tools/verification/rvgen/rvgen/dot2c.py
index 1a1770e7f20c0..78959d345c26e 100644
--- a/tools/verification/rvgen/rvgen/dot2c.py
+++ b/tools/verification/rvgen/rvgen/dot2c.py
@@ -37,11 +37,11 @@ class Dot2c(Automata):
def __get_enum_states_content(self):
buff = []
- buff.append("\t%s%s = 0," % (self.initial_state, self.enum_suffix))
+ buff.append(f"\t{self.initial_state}{self.enum_suffix} = 0,")
for state in self.states:
if state != self.initial_state:
- buff.append("\t%s%s," % (state, self.enum_suffix))
- buff.append("\tstate_max%s" % (self.enum_suffix))
+ buff.append(f"\t{state}{self.enum_suffix},")
+ buff.append(f"\tstate_max{self.enum_suffix}")
return buff
@@ -51,7 +51,7 @@ class Dot2c(Automata):
def format_states_enum(self):
buff = []
- buff.append("enum %s {" % self.enum_states_def)
+ buff.append(f"enum {self.enum_states_def} {{")
buff.append(self.get_enum_states_string())
buff.append("};\n")
@@ -62,12 +62,12 @@ class Dot2c(Automata):
first = True
for event in self.events:
if first:
- buff.append("\t%s%s = 0," % (event, self.enum_suffix))
+ buff.append(f"\t{event}{self.enum_suffix} = 0,")
first = False
else:
- buff.append("\t%s%s," % (event, self.enum_suffix))
+ buff.append(f"\t{event}{self.enum_suffix},")
- buff.append("\tevent_max%s" % self.enum_suffix)
+ buff.append(f"\tevent_max{self.enum_suffix}")
return buff
@@ -77,7 +77,7 @@ class Dot2c(Automata):
def format_events_enum(self):
buff = []
- buff.append("enum %s {" % self.enum_events_def)
+ buff.append(f"enum {self.enum_events_def} {{")
buff.append(self.get_enum_events_string())
buff.append("};\n")
@@ -93,25 +93,25 @@ class Dot2c(Automata):
min_type = "unsigned int"
if self.states.__len__() > 1000000:
- raise AutomataError("Too many states: %d" % self.states.__len__())
+ raise AutomataError(f"Too many states: {self.states.__len__()}")
return min_type
def format_automaton_definition(self):
min_type = self.get_minimun_type()
buff = []
- buff.append("struct %s {" % self.struct_automaton_def)
- buff.append("\tchar *state_names[state_max%s];" % (self.enum_suffix))
- buff.append("\tchar *event_names[event_max%s];" % (self.enum_suffix))
- buff.append("\t%s function[state_max%s][event_max%s];" % (min_type, self.enum_suffix, self.enum_suffix))
- buff.append("\t%s initial_state;" % min_type)
- buff.append("\tbool final_states[state_max%s];" % (self.enum_suffix))
+ buff.append(f"struct {self.struct_automaton_def} {{")
+ buff.append(f"\tchar *state_names[state_max{self.enum_suffix}];")
+ buff.append(f"\tchar *event_names[event_max{self.enum_suffix}];")
+ buff.append(f"\t{min_type} function[state_max{self.enum_suffix}][event_max{self.enum_suffix}];")
+ buff.append(f"\t{min_type} initial_state;")
+ buff.append(f"\tbool final_states[state_max{self.enum_suffix}];")
buff.append("};\n")
return buff
def format_aut_init_header(self):
buff = []
- buff.append("static const struct %s %s = {" % (self.struct_automaton_def, self.var_automaton_def))
+ buff.append(f"static const struct {self.struct_automaton_def} {self.var_automaton_def} = {{")
return buff
def __get_string_vector_per_line_content(self, buff):
@@ -169,9 +169,9 @@ class Dot2c(Automata):
next_state = self.function[x][y] + self.enum_suffix
if linetoolong:
- line += "\t\t\t%s" % next_state
+ line += f"\t\t\t{next_state}"
else:
- line += "%*s" % (maxlen, next_state)
+ line += f"{next_state:>{maxlen}}"
if y != nr_events-1:
line += ",\n" if linetoolong else ", "
else:
@@ -215,7 +215,7 @@ class Dot2c(Automata):
def format_aut_init_final_states(self):
buff = []
- buff.append("\t.final_states = { %s }," % self.get_aut_init_final_states())
+ buff.append(f"\t.final_states = {{ {self.get_aut_init_final_states()} }},")
return buff
@@ -231,7 +231,7 @@ class Dot2c(Automata):
def format_invalid_state(self):
buff = []
- buff.append("#define %s state_max%s\n" % (self.invalid_state_str, self.enum_suffix))
+ buff.append(f"#define {self.invalid_state_str} state_max{self.enum_suffix}\n")
return buff
diff --git a/tools/verification/rvgen/rvgen/dot2k.py b/tools/verification/rvgen/rvgen/dot2k.py
index ed0a3c9011069..1c0d0235bdf62 100644
--- a/tools/verification/rvgen/rvgen/dot2k.py
+++ b/tools/verification/rvgen/rvgen/dot2k.py
@@ -19,7 +19,7 @@ class dot2k(Monitor, Dot2c):
self.monitor_type = MonitorType
Monitor.__init__(self, extra_params)
Dot2c.__init__(self, file_path, extra_params.get("model_name"))
- self.enum_suffix = "_%s" % self.name
+ self.enum_suffix = f"_{self.name}"
def fill_monitor_type(self):
return self.monitor_type.upper()
@@ -27,7 +27,7 @@ class dot2k(Monitor, Dot2c):
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(f"static void handle_{event}(void *data, /* XXX: fill header */)")
buff.append("{")
handle = "handle_event"
if self.is_start_event(event):
@@ -38,9 +38,9 @@ class dot2k(Monitor, Dot2c):
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_%s_%s(p, %s%s);" % (handle, self.name, event, self.enum_suffix));
+ buff.append(f"\tda_{handle}_{self.name}(p, {event}{self.enum_suffix});");
else:
- buff.append("\tda_%s_%s(%s%s);" % (handle, self.name, event, self.enum_suffix));
+ buff.append(f"\tda_{handle}_{self.name}({event}{self.enum_suffix});");
buff.append("}")
buff.append("")
return '\n'.join(buff)
@@ -48,20 +48,20 @@ class dot2k(Monitor, Dot2c):
def fill_tracepoint_attach_probe(self):
buff = []
for event in self.events:
- buff.append("\trv_attach_trace_probe(\"%s\", /* XXX: tracepoint */, handle_%s);" % (self.name, event))
+ buff.append(f"\trv_attach_trace_probe(\"{self.name}\", /* XXX: tracepoint */, handle_{event});")
return '\n'.join(buff)
def fill_tracepoint_detach_helper(self):
buff = []
for event in self.events:
- buff.append("\trv_detach_trace_probe(\"%s\", /* XXX: tracepoint */, handle_%s);" % (self.name, event))
+ buff.append(f"\trv_detach_trace_probe(\"{self.name}\", /* XXX: tracepoint */, handle_{event});")
return '\n'.join(buff)
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(f" * Automatically generated C representation of {self.name} automaton")
buff.append(" * For further information about this format, see kernel documentation:")
buff.append(" * Documentation/trace/rv/deterministic_automata.rst")
buff.append(" */")
@@ -73,10 +73,10 @@ class dot2k(Monitor, Dot2c):
#
# Adjust the definition names
#
- self.enum_states_def = "states_%s" % self.name
- self.enum_events_def = "events_%s" % self.name
- self.struct_automaton_def = "automaton_%s" % self.name
- self.var_automaton_def = "automaton_%s" % self.name
+ self.enum_states_def = f"states_{self.name}"
+ self.enum_events_def = f"events_{self.name}"
+ self.struct_automaton_def = f"automaton_{self.name}"
+ self.var_automaton_def = f"automaton_{self.name}"
buff = self.fill_model_h_header()
buff += self.format_model()
@@ -111,8 +111,8 @@ class dot2k(Monitor, Dot2c):
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)
+ buff.append(f" TP_PROTO({tp_proto_c}),")
+ buff.append(f" TP_ARGS({tp_args_c})")
return '\n'.join(buff)
def fill_main_c(self):
diff --git a/tools/verification/rvgen/rvgen/generator.py b/tools/verification/rvgen/rvgen/generator.py
index af1662e2c20a7..6d16fb68798a7 100644
--- a/tools/verification/rvgen/rvgen/generator.py
+++ b/tools/verification/rvgen/rvgen/generator.py
@@ -40,7 +40,7 @@ class RVGenerator:
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)
+ kernel_path = os.path.join(f"/lib/modules/{platform.release()}/build", 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
@@ -69,11 +69,11 @@ class RVGenerator:
return self._read_file(path)
def fill_parent(self):
- return "&rv_%s" % self.parent if self.parent else "NULL"
+ return f"&rv_{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 f"#include <monitors/{self.parent}/{self.parent}.h>\n"
return ""
def fill_tracepoint_handlers_skel(self):
@@ -119,7 +119,7 @@ class RVGenerator:
buff = []
buff.append(" # XXX: add dependencies if there")
if self.parent:
- buff.append(" depends on RV_MON_%s" % self.parent.upper())
+ buff.append(f" depends on RV_MON_{self.parent.upper()}")
buff.append(" default y")
return '\n'.join(buff)
@@ -145,31 +145,30 @@ class RVGenerator:
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
+ f"// Add new monitors based on CONFIG_{monitor_class_type} here",
+ f"#include <monitors/{self.name}/{self.name}_trace.h>")
+ return f" - Patching {self.rv_dir}/rv_trace.h, double check the result"
- 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)
+ return f""" - Edit {self.rv_dir}/rv_trace.h:
+Add this line where other tracepoints are included and {monitor_class_type} is defined:
+#include <monitors/{self.name}/{self.name}_trace.h>
+"""
def _kconfig_marker(self, container=None) -> str:
- return "# Add new %smonitors here" % (container + " "
- if container else "")
+ return f"# Add new {container + ' ' if container else ''}monitors here"
def fill_kconfig_tooltip(self):
if self.auto_patch:
# monitors with a container should stay together in the Kconfig
self._patch_file("Kconfig",
self._kconfig_marker(self.parent),
- "source \"kernel/trace/rv/monitors/%s/Kconfig\"" % (self.name))
- return " - Patching %s/Kconfig, double check the result" % self.rv_dir
+ f"source \"kernel/trace/rv/monitors/{self.name}/Kconfig\"")
+ return f" - Patching {self.rv_dir}/Kconfig, double check the result"
- return """ - Edit %s/Kconfig:
+ return f""" - Edit {self.rv_dir}/Kconfig:
Add this line where other monitors are included:
-source \"kernel/trace/rv/monitors/%s/Kconfig\"
-""" % (self.rv_dir, self.name)
+source \"kernel/trace/rv/monitors/{self.name}/Kconfig\"
+"""
def fill_makefile_tooltip(self):
name = self.name
@@ -177,18 +176,18 @@ source \"kernel/trace/rv/monitors/%s/Kconfig\"
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
+ f"obj-$(CONFIG_RV_MON_{name_up}) += monitors/{name}/{name}.o")
+ return f" - Patching {self.rv_dir}/Makefile, double check the result"
- return """ - Edit %s/Makefile:
+ return f""" - Edit {self.rv_dir}/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)
+obj-$(CONFIG_RV_MON_{name_up}) += monitors/{name}/{name}.o
+"""
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)
+ return f" - Monitor created in {self.rv_dir}/monitors/{self.name}"
+ return f" - Move {self.name}/ to the kernel's monitor directory ({self.rv_dir}/monitors)"
def __create_directory(self):
path = self.name
@@ -205,13 +204,13 @@ obj-$(CONFIG_RV_MON_%s) += monitors/%s/%s.o
file.close()
def _create_file(self, file_name, content):
- path = "%s/%s" % (self.name, file_name)
+ path = f"{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")
+ path = f"{self.name}/main.c"
if not os.path.exists(path):
return "main.c"
return "__main.c"
@@ -221,11 +220,11 @@ obj-$(CONFIG_RV_MON_%s) += monitors/%s/%s.o
self.__create_directory()
- path = "%s.c" % self.name
+ path = f"{self.name}.c"
self._create_file(path, main_c)
model_h = self.fill_model_h()
- path = "%s.h" % self.name
+ path = f"{self.name}.h"
self._create_file(path, model_h)
kconfig = self.fill_kconfig()
@@ -256,5 +255,5 @@ class Monitor(RVGenerator):
def print_files(self):
super().print_files()
trace_h = self.fill_trace_h()
- path = "%s_trace.h" % self.name
+ path = f"{self.name}_trace.h"
self._create_file(path, trace_h)
diff --git a/tools/verification/rvgen/rvgen/ltl2k.py b/tools/verification/rvgen/rvgen/ltl2k.py
index b075f98d50c47..fa9ea6d597095 100644
--- a/tools/verification/rvgen/rvgen/ltl2k.py
+++ b/tools/verification/rvgen/rvgen/ltl2k.py
@@ -73,7 +73,7 @@ class ltl2k(generator.Monitor):
]
for node in self.ba:
- buf.append("\tS%i," % node.id)
+ buf.append(f"\tS{node.id},")
buf.append("\tRV_NUM_BA_STATES")
buf.append("};")
buf.append("static_assert(RV_NUM_BA_STATES <= RV_MAX_BA_STATES);")
@@ -82,7 +82,7 @@ class ltl2k(generator.Monitor):
def _fill_atoms(self):
buf = ["enum ltl_atom {"]
for a in sorted(self.atoms):
- buf.append("\tLTL_%s," % a)
+ buf.append(f"\tLTL_{a},")
buf.append("\tLTL_NUM_ATOM")
buf.append("};")
buf.append("static_assert(LTL_NUM_ATOM <= RV_MAX_LTL_ATOM);")
@@ -96,7 +96,7 @@ class ltl2k(generator.Monitor):
]
for name in self.atoms_abbr:
- buf.append("\t\t\"%s\"," % name)
+ buf.append(f"\t\t\"{name}\",")
buf.extend([
"\t};",
@@ -113,19 +113,19 @@ class ltl2k(generator.Monitor):
continue
if isinstance(node.op, ltl2ba.AndOp):
- buf.append("\tbool %s = %s && %s;" % (node, node.op.left, node.op.right))
+ buf.append(f"\tbool {node} = {node.op.left} && {node.op.right};")
required_values |= {str(node.op.left), str(node.op.right)}
elif isinstance(node.op, ltl2ba.OrOp):
- buf.append("\tbool %s = %s || %s;" % (node, node.op.left, node.op.right))
+ buf.append(f"\tbool {node} = {node.op.left} || {node.op.right};")
required_values |= {str(node.op.left), str(node.op.right)}
elif isinstance(node.op, ltl2ba.NotOp):
- buf.append("\tbool %s = !%s;" % (node, node.op.child))
+ buf.append(f"\tbool {node} = !{node.op.child};")
required_values.add(str(node.op.child))
for atom in self.atoms:
if atom.lower() not in required_values:
continue
- buf.append("\tbool %s = test_bit(LTL_%s, mon->atoms);" % (atom.lower(), atom))
+ buf.append(f"\tbool {atom.lower()} = test_bit(LTL_{atom}, mon->atoms);")
buf.reverse()
@@ -153,7 +153,7 @@ class ltl2k(generator.Monitor):
])
for node in self.ba:
- buf.append("\tcase S%i:" % node.id)
+ buf.append(f"\tcase S{node.id}:")
for o in sorted(node.outgoing):
line = "\t\tif "
@@ -163,7 +163,7 @@ class ltl2k(generator.Monitor):
lines = break_long_line(line, indent)
buf.extend(lines)
- buf.append("\t\t\t__set_bit(S%i, next);" % o.id)
+ buf.append(f"\t\t\t__set_bit(S{o.id}, next);")
buf.append("\t\tbreak;")
buf.extend([
"\t}",
@@ -197,7 +197,7 @@ class ltl2k(generator.Monitor):
lines = break_long_line(line, indent)
buf.extend(lines)
- buf.append("\t\t__set_bit(S%i, mon->states);" % node.id)
+ buf.append(f"\t\t__set_bit(S{node.id}, mon->states);")
buf.append("}")
return buf
@@ -205,23 +205,21 @@ class ltl2k(generator.Monitor):
buff = []
buff.append("static void handle_example_event(void *data, /* XXX: fill header */)")
buff.append("{")
- buff.append("\tltl_atom_update(task, LTL_%s, true/false);" % self.atoms[0])
+ buff.append(f"\tltl_atom_update(task, LTL_{self.atoms[0]}, true/false);")
buff.append("}")
buff.append("")
return '\n'.join(buff)
def fill_tracepoint_attach_probe(self):
- return "\trv_attach_trace_probe(\"%s\", /* XXX: tracepoint */, handle_example_event);" \
- % self.name
+ return f"\trv_attach_trace_probe(\"{self.name}\", /* XXX: tracepoint */, handle_example_event);"
def fill_tracepoint_detach_helper(self):
- return "\trv_detach_trace_probe(\"%s\", /* XXX: tracepoint */, handle_sample_event);" \
- % self.name
+ return f"\trv_detach_trace_probe(\"{self.name}\", /* XXX: tracepoint */, handle_sample_event);"
def fill_atoms_init(self):
buff = []
for a in self.atoms:
- buff.append("\tltl_atom_set(mon, LTL_%s, true/false);" % a)
+ buff.append(f"\tltl_atom_set(mon, LTL_{a}, true/false);")
return '\n'.join(buff)
def fill_model_h(self):
--
2.52.0
^ permalink raw reply related
* [PATCH 02/26] rv/rvgen: remove bare except clauses in generator
From: Wander Lairson Costa @ 2026-01-19 20:45 UTC (permalink / raw)
To: Steven Rostedt, Gabriele Monaco, Nam Cao, Wander Lairson Costa,
open list, open list:RUNTIME VERIFICATION (RV)
In-Reply-To: <20260119205601.105821-1-wander@redhat.com>
Remove bare except clauses from the generator module that were
catching all exceptions including KeyboardInterrupt and SystemExit.
This follows the same exception handling improvements made in the
previous AutomataError commit and addresses PEP 8 violations.
The bare except clause in __create_directory was silently catching
and ignoring all errors after printing a message, which could mask
serious issues. For __write_file, the bare except created a critical
bug where the file variable could remain undefined if open() failed,
causing a NameError when attempting to write to or close the file.
These methods now let OSError propagate naturally, allowing callers
to handle file system errors appropriately. This provides clearer
error reporting and allows Python's exception handling to show
complete stack traces with proper error types and locations.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/verification/rvgen/rvgen/generator.py | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/tools/verification/rvgen/rvgen/generator.py b/tools/verification/rvgen/rvgen/generator.py
index a7bee6b1ea70c..af1662e2c20a7 100644
--- a/tools/verification/rvgen/rvgen/generator.py
+++ b/tools/verification/rvgen/rvgen/generator.py
@@ -198,17 +198,10 @@ obj-$(CONFIG_RV_MON_%s) += monitors/%s/%s.o
os.mkdir(path)
except FileExistsError:
return
- except:
- print("Fail creating the output dir: %s" % self.name)
def __write_file(self, file_name, content):
- try:
- file = open(file_name, 'w')
- except:
- print("Fail writing to file: %s" % file_name)
-
+ file = open(file_name, 'w')
file.write(content)
-
file.close()
def _create_file(self, file_name, content):
--
2.52.0
^ permalink raw reply related
* [PATCH 01/26] rv/rvgen: introduce AutomataError exception class
From: Wander Lairson Costa @ 2026-01-19 20:45 UTC (permalink / raw)
To: Steven Rostedt, Gabriele Monaco, Nam Cao, Wander Lairson Costa,
open list, open list:RUNTIME VERIFICATION (RV)
In-Reply-To: <20260119205601.105821-1-wander@redhat.com>
Replace generic Exception usage with a custom AutomataError class
that inherits from OSError throughout the rvgen tool. This change
provides more precise exception handling for automata parsing and
validation errors while avoiding overly broad exception catches that
could mask programming errors like SyntaxError or TypeError.
The AutomataError class inherits from OSError rather than Exception
because most error conditions involve file I/O operations such as
reading DOT files or handling file access issues. This semantic
alignment makes exception handling more specific and appropriate.
The exception is raised when DOT file processing fails due to invalid
format, I/O errors, or malformed automaton definitions.
Additionally, remove the broad try-except block from __main__.py that
was catching all exceptions. This allows Python's default exception
handling to provide complete stack traces, making debugging
significantly easier by showing exact error types and locations.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/verification/rvgen/__main__.py | 25 +++++++++------------
tools/verification/rvgen/rvgen/automata.py | 17 +++++++++-----
tools/verification/rvgen/rvgen/dot2c.py | 4 ++--
tools/verification/rvgen/rvgen/generator.py | 7 ++----
4 files changed, 26 insertions(+), 27 deletions(-)
diff --git a/tools/verification/rvgen/__main__.py b/tools/verification/rvgen/__main__.py
index fa6fc1f4de2f7..768b11a1e978b 100644
--- a/tools/verification/rvgen/__main__.py
+++ b/tools/verification/rvgen/__main__.py
@@ -39,22 +39,17 @@ if __name__ == '__main__':
params = parser.parse_args()
- try:
- if params.subcmd == "monitor":
- print("Opening and parsing the specification file %s" % params.spec)
- if params.monitor_class == "da":
- monitor = dot2k(params.spec, params.monitor_type, vars(params))
- elif params.monitor_class == "ltl":
- monitor = ltl2k(params.spec, params.monitor_type, vars(params))
- else:
- print("Unknown monitor class:", params.monitor_class)
- sys.exit(1)
+ if params.subcmd == "monitor":
+ print("Opening and parsing the specification file %s" % params.spec)
+ if params.monitor_class == "da":
+ monitor = dot2k(params.spec, params.monitor_type, vars(params))
+ elif params.monitor_class == "ltl":
+ monitor = ltl2k(params.spec, params.monitor_type, vars(params))
else:
- monitor = Container(vars(params))
- except Exception as e:
- print('Error: '+ str(e))
- print("Sorry : :-(")
- sys.exit(1)
+ print("Unknown monitor class:", params.monitor_class)
+ sys.exit(1)
+ else:
+ monitor = Container(vars(params))
print("Writing the monitor into the directory %s" % monitor.name)
monitor.print_files()
diff --git a/tools/verification/rvgen/rvgen/automata.py b/tools/verification/rvgen/rvgen/automata.py
index d9a3fe2b74bf2..8d88c3b65d00d 100644
--- a/tools/verification/rvgen/rvgen/automata.py
+++ b/tools/verification/rvgen/rvgen/automata.py
@@ -10,6 +10,13 @@
import ntpath
+class AutomataError(OSError):
+ """Exception raised for errors in automata parsing and validation.
+
+ Raised when DOT file processing fails due to invalid format, I/O errors,
+ or malformed automaton definitions.
+ """
+
class Automata:
"""Automata class: Reads a dot file and part it as an automata.
@@ -32,11 +39,11 @@ class Automata:
basename = ntpath.basename(self.__dot_path)
if not basename.endswith(".dot") and not basename.endswith(".gv"):
print("not a dot file")
- raise Exception("not a dot file: %s" % self.__dot_path)
+ raise AutomataError("not a dot file: %s" % self.__dot_path)
model_name = ntpath.splitext(basename)[0]
if model_name.__len__() == 0:
- raise Exception("not a dot file: %s" % self.__dot_path)
+ raise AutomataError("not a dot file: %s" % self.__dot_path)
return model_name
@@ -45,8 +52,8 @@ class Automata:
dot_lines = []
try:
dot_file = open(self.__dot_path)
- except:
- raise Exception("Cannot open the file: %s" % self.__dot_path)
+ except OSError as exc:
+ raise AutomataError(f"Cannot open the file: {self.__dot_path}") from exc
dot_lines = dot_file.read().splitlines()
dot_file.close()
@@ -55,7 +62,7 @@ class Automata:
line = dot_lines[cursor].split()
if (line[0] != "digraph") and (line[1] != "state_automaton"):
- raise Exception("Not a valid .dot format: %s" % self.__dot_path)
+ raise AutomataError("Not a valid .dot format: %s" % self.__dot_path)
else:
cursor += 1
return dot_lines
diff --git a/tools/verification/rvgen/rvgen/dot2c.py b/tools/verification/rvgen/rvgen/dot2c.py
index b9b6f14cc536a..1a1770e7f20c0 100644
--- a/tools/verification/rvgen/rvgen/dot2c.py
+++ b/tools/verification/rvgen/rvgen/dot2c.py
@@ -13,7 +13,7 @@
# For further information, see:
# Documentation/trace/rv/deterministic_automata.rst
-from .automata import Automata
+from .automata import Automata, AutomataError
class Dot2c(Automata):
enum_suffix = ""
@@ -93,7 +93,7 @@ class Dot2c(Automata):
min_type = "unsigned int"
if self.states.__len__() > 1000000:
- raise Exception("Too many states: %d" % self.states.__len__())
+ raise AutomataError("Too many states: %d" % self.states.__len__())
return min_type
diff --git a/tools/verification/rvgen/rvgen/generator.py b/tools/verification/rvgen/rvgen/generator.py
index 3441385c11770..a7bee6b1ea70c 100644
--- a/tools/verification/rvgen/rvgen/generator.py
+++ b/tools/verification/rvgen/rvgen/generator.py
@@ -51,10 +51,7 @@ class RVGenerator:
raise FileNotFoundError("Could not find the rv directory, do you have the kernel source installed?")
def _read_file(self, path):
- try:
- fd = open(path, 'r')
- except OSError:
- raise Exception("Cannot open the file: %s" % path)
+ fd = open(path, 'r')
content = fd.read()
@@ -65,7 +62,7 @@ class RVGenerator:
try:
path = os.path.join(self.abs_template_dir, file)
return self._read_file(path)
- except Exception:
+ except OSError:
# Specific template file not found. Try the generic template file in the template/
# directory, which is one level up
path = os.path.join(self.abs_template_dir, "..", file)
--
2.52.0
^ permalink raw reply related
* [PATCH 00/26] rv/rvgen: Robustness, modernization, and fixes
From: Wander Lairson Costa @ 2026-01-19 20:45 UTC (permalink / raw)
To: Steven Rostedt, Gabriele Monaco, Nam Cao, Wander Lairson Costa,
open list, open list:RUNTIME VERIFICATION (RV)
This patch series introduces a number of fixes and improvements to the
RV Generator (rvgen) tool in tools/verification. The primary goal is to
enhance the tool's robustness, maintainability, and correctness by
addressing several latent bugs, modernizing the Python codebase, and
improving its overall structure and error handling.
The changes can be broadly categorized into several areas. A number of
bugs have been fixed, including logic errors in DOT file validation, an
incorrect isinstance check, and several unbound variable errors that
could lead to runtime crashes. Exception handling is now more robust
with the introduction of a custom AutomataError class and the removal
of dangerous bare except clauses that could mask underlying issues. The
codebase has also been updated to use contemporary Python idioms such
as f-strings and context managers for file I/O.
Finally, a general cleanup pass removes dead code, adds missing abstract
method stubs to satisfy class interfaces, and introduces type
annotations to resolve pyright errors and improve static analysis.
Together, these changes make the rvgen tool more reliable, easier to
debug, and more approachable for future development and maintenance.
Wander Lairson Costa (26):
rv/rvgen: introduce AutomataError exception class
rv/rvgen: remove bare except clauses in generator
rv/rvgen: replace % string formatting with f-strings
rv/rvgen: replace __len__() calls with len()
rv/rvgen: remove unnecessary semicolons
rv/rvgen: use context managers for file operations
rv/rvgen: replace __contains__() with in operator
rv/rvgen: simplify boolean comparison
rv/rvgen: replace inline NotImplemented with decorator
rv/rvgen: fix typos in automata docstring and comments
rv/rvgen: fix typo in generator module docstring
rv/rvgen: fix PEP 8 whitespace violations
rv/rvgen: fix DOT file validation logic error
rv/rvgen: remove redundant initial_state removal
rv/rvgen: use class constant for init marker
rv/rvgen: fix unbound initial_state variable
rv/rvgen: fix possibly unbound variable in ltl2k
rv/rvgen: add fill_tracepoint_args_skel stub to ltl2k
rv/rvgen: add abstract method stubs to Container class
rv/rvgen: refactor automata.py to use iterator-based parsing
rv/rvgen: remove unused sys import from dot2c
rv/rvgen: remove unused __get_main_name method
rv/rvgen: add type annotations to fix pyright errors
rv/rvgen: make monitor arguments required in rvgen
rv/rvgen: fix isinstance check in Variable.expand()
rv/rvgen: extract node marker string to class constant
tools/verification/rvgen/__main__.py | 36 ++---
tools/verification/rvgen/dot2c | 1 -
tools/verification/rvgen/rvgen/automata.py | 155 +++++++++++++-------
tools/verification/rvgen/rvgen/container.py | 12 ++
tools/verification/rvgen/rvgen/dot2c.py | 64 ++++----
tools/verification/rvgen/rvgen/dot2k.py | 32 ++--
tools/verification/rvgen/rvgen/generator.py | 141 ++++++++----------
tools/verification/rvgen/rvgen/ltl2ba.py | 54 ++++---
tools/verification/rvgen/rvgen/ltl2k.py | 36 ++---
tools/verification/rvgen/rvgen/utils.py | 36 +++++
10 files changed, 322 insertions(+), 245 deletions(-)
create mode 100644 tools/verification/rvgen/rvgen/utils.py
--
2.52.0
^ permalink raw reply
* Re: [PATCH bpf RESEND v2 2/2] bpf: Require ARG_PTR_TO_MEM with memory flag
From: Eduard Zingerman @ 2026-01-19 20:25 UTC (permalink / raw)
To: Zesen Liu, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Song Liu, Yonghong Song, John Fastabend,
KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa, Matt Bobrowski,
Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Daniel Xu
Cc: bpf, linux-kernel, linux-trace-kernel, netdev, Shuran Liu,
Peili Gao, Haoran Ni
In-Reply-To: <20260118-helper_proto-v2-2-ab3a1337e755@gmail.com>
On Sun, 2026-01-18 at 16:16 +0800, Zesen Liu wrote:
> Add check to ensure that ARG_PTR_TO_MEM is used with either MEM_WRITE or
> MEM_RDONLY.
>
> Using ARG_PTR_TO_MEM alone without tags does not make sense because:
>
> - If the helper does not change the argument, missing MEM_RDONLY causes the
> verifier to incorrectly reject a read-only buffer.
> - If the helper does change the argument, missing MEM_WRITE causes the
> verifier to incorrectly assume the memory is unchanged, leading to errors
> in code optimization.
>
> Co-developed-by: Shuran Liu <electronlsr@gmail.com>
> Signed-off-by: Shuran Liu <electronlsr@gmail.com>
> Co-developed-by: Peili Gao <gplhust955@gmail.com>
> Signed-off-by: Peili Gao <gplhust955@gmail.com>
> Co-developed-by: Haoran Ni <haoran.ni.cs@gmail.com>
> Signed-off-by: Haoran Ni <haoran.ni.cs@gmail.com>
> Signed-off-by: Zesen Liu <ftyghome@gmail.com>
> ---
Note: this patch no longer applies properly because of the change in
the check_func_proto() signature.
[...]
^ permalink raw reply
* Re: [PATCH bpf RESEND v2 1/2] bpf: Fix memory access flags in helper prototypes
From: Eduard Zingerman @ 2026-01-19 20:24 UTC (permalink / raw)
To: Zesen Liu, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Song Liu, Yonghong Song, John Fastabend,
KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa, Matt Bobrowski,
Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Daniel Xu
Cc: bpf, linux-kernel, linux-trace-kernel, netdev, Shuran Liu,
Peili Gao, Haoran Ni
In-Reply-To: <20260118-helper_proto-v2-1-ab3a1337e755@gmail.com>
On Sun, 2026-01-18 at 16:16 +0800, Zesen Liu wrote:
> After commit 37cce22dbd51 ("bpf: verifier: Refactor helper access type tracking"),
> the verifier started relying on the access type flags in helper
> function prototypes to perform memory access optimizations.
>
> Currently, several helper functions utilizing ARG_PTR_TO_MEM lack the
> corresponding MEM_RDONLY or MEM_WRITE flags. This omission causes the
> verifier to incorrectly assume that the buffer contents are unchanged
> across the helper call. Consequently, the verifier may optimize away
> subsequent reads based on this wrong assumption, leading to correctness
> issues.
>
> For bpf_get_stack_proto_raw_tp, the original MEM_RDONLY was incorrect
> since the helper writes to the buffer. Change it to ARG_PTR_TO_UNINIT_MEM
> which correctly indicates write access to potentially uninitialized memory.
>
> Similar issues were recently addressed for specific helpers in commit
> ac44dcc788b9 ("bpf: Fix verifier assumptions of bpf_d_path's output buffer")
> and commit 2eb7648558a7 ("bpf: Specify access type of bpf_sysctl_get_name args").
>
> Fix these prototypes by adding the correct memory access flags.
>
> Fixes: 37cce22dbd51 ("bpf: verifier: Refactor helper access type tracking")
> Co-developed-by: Shuran Liu <electronlsr@gmail.com>
> Signed-off-by: Shuran Liu <electronlsr@gmail.com>
> Co-developed-by: Peili Gao <gplhust955@gmail.com>
> Signed-off-by: Peili Gao <gplhust955@gmail.com>
> Co-developed-by: Haoran Ni <haoran.ni.cs@gmail.com>
> Signed-off-by: Haoran Ni <haoran.ni.cs@gmail.com>
> Signed-off-by: Zesen Liu <ftyghome@gmail.com>
> ---
I looked trough the helpers annotated with MEM_WRITE in this patch,
indeed the write annotation is missing from these helpers.
In conjunction with the following logic in verifier.c:check_func_arg:
case ARG_PTR_TO_MEM:
/* The access to this pointer is only checked when we hit the
* next is_mem_size argument below.
*/
meta->raw_mode = arg_type & MEM_UNINIT;
if (arg_type & MEM_FIXED_SIZE) {
err = check_helper_mem_access(env, regno, fn->arg_size[arg],
arg_type & MEM_WRITE ? BPF_WRITE : BPF_READ,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// arguments considered read-only by default
false, meta);
if (err)
return err;
if (arg_type & MEM_ALIGNED)
err = check_ptr_alignment(env, reg, 0, fn->arg_size[arg], true);
}
break;
This patch fixes a real problem.
[...]
> index fe28d86f7c35..59c2394981c7 100644
> --- a/kernel/trace/bpf_trace.c
> +++ b/kernel/trace/bpf_trace.c
[...]
> @@ -1526,7 +1526,7 @@ static const struct bpf_func_proto bpf_read_branch_records_proto = {
> .gpl_only = true,
> .ret_type = RET_INTEGER,
> .arg1_type = ARG_PTR_TO_CTX,
> - .arg2_type = ARG_PTR_TO_MEM_OR_NULL,
> + .arg2_type = ARG_PTR_TO_MEM_OR_NULL | MEM_WRITE,
> .arg3_type = ARG_CONST_SIZE_OR_ZERO,
> .arg4_type = ARG_ANYTHING,
> };
> @@ -1661,7 +1661,7 @@ static const struct bpf_func_proto bpf_get_stack_proto_raw_tp = {
> .gpl_only = true,
> .ret_type = RET_INTEGER,
> .arg1_type = ARG_PTR_TO_CTX,
> - .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
> + .arg2_type = ARG_PTR_TO_UNINIT_MEM,
Q: why ARG_PTR_TO_UNINIT_MEM here, but not for a previous function and
not for snprintf variants?
> .arg3_type = ARG_CONST_SIZE_OR_ZERO,
> .arg4_type = ARG_ANYTHING,
> };
[...]
^ permalink raw reply
* Re: [PATCH bpf-next v3 1/2] bpf: support bpf_get_func_arg() for BPF_TRACE_RAW_TP
From: bot+bpf-ci @ 2026-01-19 18:44 UTC (permalink / raw)
To: menglong8.dong, andrii, ast
Cc: daniel, john.fastabend, martin.lau, eddyz87, song, yonghong.song,
kpsingh, sdf, haoluo, jolsa, mattbobrowski, rostedt, mhiramat,
mathieu.desnoyers, bpf, linux-kernel, linux-trace-kernel, ast,
andrii, daniel, martin.lau, eddyz87, yonghong.song, clm,
ihor.solodrai
In-Reply-To: <20260119023732.130642-2-dongml2@chinatelecom.cn>
[-- Attachment #1: Type: text/plain, Size: 3022 bytes --]
> diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
> index f73e08c223b5..64976009ba3c 100644
> --- a/kernel/trace/bpf_trace.c
> +++ b/kernel/trace/bpf_trace.c
> @@ -1734,11 +1734,11 @@ tracing_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
> case BPF_FUNC_d_path:
> return &bpf_d_path_proto;
> case BPF_FUNC_get_func_arg:
> - return bpf_prog_has_trampoline(prog) ? &bpf_get_func_arg_proto : NULL;
> + return &bpf_get_func_arg_proto;
Removing the bpf_prog_has_trampoline() check here allows all TRACING
program types to use bpf_get_func_arg(), not just RAW_TP and trampoline-
based types. In particular, BPF_TRACE_ITER programs can now use this
helper.
However, looking at do_misc_fixups() in verifier.c, the inline code
generation only handles BPF_TRACE_RAW_TP specially. For other non-
trampoline types like BPF_TRACE_ITER, the else branch generates:
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8)
This loads nr_args from ctx-8, but ITER programs use a different context
layout (e.g. struct bpf_iter__bpf_map_elem with meta, map, key, value
pointers). There is no nr_args at ctx-8 for ITER programs.
Would this cause ITER programs using bpf_get_func_arg() to read arbitrary
memory at ctx-8, potentially leaking kernel data or causing incorrect
bounds checks for subsequent argument access?
> case BPF_FUNC_get_func_ret:
> return bpf_prog_has_trampoline(prog) ? &bpf_get_func_ret_proto : NULL;
> case BPF_FUNC_get_func_arg_cnt:
> - return bpf_prog_has_trampoline(prog) ? &bpf_get_func_arg_cnt_proto : NULL;
> + return &bpf_get_func_arg_cnt_proto;
Same question applies here for bpf_get_func_arg_cnt() with ITER programs.
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 9de0ec0c3ed9..0b281b7c41eb 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -23323,8 +23323,20 @@ static int do_misc_fixups(struct bpf_verifier_env *env)
> /* Implement bpf_get_func_arg inline. */
> if (prog_type == BPF_PROG_TYPE_TRACING &&
> insn->imm == BPF_FUNC_get_func_arg) {
> + if (eatype == BPF_TRACE_RAW_TP) {
> + int nr_args = btf_type_vlen(prog->aux->attach_func_proto);
> +
> + /*
> + * skip first 'void *__data' argument in btf_trace_##name
> + * typedef
> + */
> + nr_args--;
> + /* Save nr_args to reg0 */
> + insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, nr_args);
> + } else {
> + /* Load nr_args from ctx - 8 */
> + insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8);
> + }
This else branch now applies to BPF_TRACE_ITER as well, since the
trampoline check was removed in tracing_prog_func_proto(). Should the
condition be extended to also handle ITER, or should ITER be explicitly
blocked from using these helpers?
[ ... ]
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/21147849826
^ permalink raw reply
* Re: [PATCH net-next v3] page_pool: Add page_pool_release_stalled tracepoint
From: Jesper Dangaard Brouer @ 2026-01-19 17:26 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Leon Hwang, netdev, Ilias Apalodimas, Steven Rostedt,
Masami Hiramatsu, Mathieu Desnoyers, David S . Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, kerneljasonxing,
lance.yang, jiayuan.chen, linux-kernel, linux-trace-kernel,
Leon Huang Fu, Dragos Tatulea, kernel-team, Yan Zhai
In-Reply-To: <20260104084347.5de3a537@kernel.org>
On 04/01/2026 17.43, Jakub Kicinski wrote:
> On Fri, 2 Jan 2026 12:43:46 +0100 Jesper Dangaard Brouer wrote:
>> On 02/01/2026 08.17, Leon Hwang wrote:
>>> Introduce a new tracepoint to track stalled page pool releases,
>>> providing better observability for page pool lifecycle issues.
>>
>> In general I like/support adding this tracepoint for "debugability" of
>> page pool lifecycle issues.
>>
>> For "observability" @Kuba added a netlink scheme[1][2] for page_pool[3],
>> which gives us the ability to get events and list page_pools from userspace.
>> I've not used this myself (yet) so I need input from others if this is
>> something that others have been using for page pool lifecycle issues?
>
> My input here is the least valuable (since one may expect the person
> who added the code uses it) - but FWIW yes, we do use the PP stats to
> monitor PP lifecycle issues at Meta. That said - we only monitor for
> accumulation of leaked memory from orphaned pages, as the whole reason
> for adding this code was that in practice the page may be sitting in
> a socket rx queue (or defer free queue etc.) IOW a PP which is not
> getting destroyed for a long time is not necessarily a kernel issue.
>
>> Need input from @Kuba/others as the "page-pool-get"[4] state that "Only
>> Page Pools associated with a net_device can be listed". Don't we want
>> the ability to list "invisible" page_pool's to allow debugging issues?
>>
>> [1] https://docs.kernel.org/userspace-api/netlink/intro-specs.html
>> [2] https://docs.kernel.org/userspace-api/netlink/index.html
>> [3] https://docs.kernel.org/netlink/specs/netdev.html
>> [4] https://docs.kernel.org/netlink/specs/netdev.html#page-pool-get
>
> The documentation should probably be updated :(
> I think what I meant is that most _drivers_ didn't link their PP to the
> netdev via params when the API was added. So if the user doesn't see the
> page pools - the driver is probably not well maintained.
>
> In practice only page pools which are not accessible / visible via the
> API are page pools from already destroyed network namespaces (assuming
> their netdevs were also destroyed and not re-parented to init_net).
> Which I'd think is a rare case?
>
>> Looking at the code, I see that NETDEV_CMD_PAGE_POOL_CHANGE_NTF netlink
>> notification is only generated once (in page_pool_destroy) and not when
>> we retry in page_pool_release_retry (like this patch). In that sense,
>> this patch/tracepoint is catching something more than netlink provides.
>> First I though we could add a netlink notification, but I can imagine
>> cases this could generate too many netlink messages e.g. a netdev with
>> 128 RX queues generating these every second for every RX queue.
>
> FWIW yes, we can add more notifications. Tho, as I mentioned at the
> start of my reply - the expectation is that page pools waiting for
> a long time to be destroyed is something that _will_ happen in
> production.
>
>> Guess, I've talked myself into liking this change, what do other
>> maintainers think? (e.g. netlink scheme and debugging balance)
>
> We added the Netlink API to mute the pr_warn() in all practical cases.
> If Xiang Mei is seeing the pr_warn() I think we should start by asking
> what kernel and driver they are using, and what the usage pattern is :(
> As I mentioned most commonly the pr_warn() will trigger because driver
> doesn't link the pp to a netdev.
The commit that introduced this be0096676e23 ("net: page_pool: mute the
periodic warning for visible page pools") (Author: Jakub Kicinski) was
added in kernel v6.8. Our fleet runs 6.12.
Looking at production logs I'm still seeing these messages, e.g.:
"page_pool_release_retry() stalled pool shutdown: id 322, 1 inflight
591248 sec"
Looking at one of these servers it runs kernel 6.12.59 and ice NIC driver.
I'm surprised to see these on our normal servers and also the long
period. Previously I was seeing these on k8s servers, which makes more
sense at veth interfaces are likely to be removed and easier reach the
pr_warn() (as Jakub added extra if statement checking netdev in commit
(!netdev || netdev == NET_PTR_POISON)).
An example from a k8s server have smaller stalled period, and I think it
recovered:
"page_pool_release_retry() stalled pool shutdown: id 18, 1 inflight
3020 sec"
I'm also surprised to see ice NIC driver, as previously we mostly seen
these warning on driver bnxt_en. I did manage to find some cases of the
bnxt_en driver now, but I see that the server likely have a hardware defect.
Bottom-line yes these stalled pool shutdown pr_warn() are still
happening in production.
--Jesper
^ permalink raw reply
* Re: [PATCH net-next v4] page_pool: Add page_pool_release_stalled tracepoint
From: Jakub Kicinski @ 2026-01-19 17:23 UTC (permalink / raw)
To: Jesper Dangaard Brouer
Cc: Leon Hwang, netdev, Ilias Apalodimas, Steven Rostedt,
Masami Hiramatsu, Mathieu Desnoyers, David S . Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, kerneljasonxing,
lance.yang, jiayuan.chen, linux-kernel, linux-trace-kernel,
Leon Huang Fu
In-Reply-To: <47152311-1357-44f8-ae12-61e4850e62c6@kernel.org>
On Mon, 19 Jan 2026 17:43:20 +0100 Jesper Dangaard Brouer wrote:
> On 19/01/2026 17.37, Jakub Kicinski wrote:
> > On Mon, 19 Jan 2026 18:21:19 +0800 Leon Hwang wrote:
> >> Introduce a new tracepoint to track stalled page pool releases,
> >> providing better observability for page pool lifecycle issues.
> >
> > Sorry, I really want you to answer the questions from the last
> > paragraph of:
> >
> > https://lore.kernel.org/netdev/20260104084347.5de3a537@kernel.org/
>
> Okay, I will answer that, if you will answer:
To be clear I was asking Leon about his setup :)
^ permalink raw reply
* Re: [PATCH net-next v4] page_pool: Add page_pool_release_stalled tracepoint
From: Jesper Dangaard Brouer @ 2026-01-19 16:43 UTC (permalink / raw)
To: Jakub Kicinski, Leon Hwang
Cc: netdev, Ilias Apalodimas, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, David S . Miller, Eric Dumazet, Paolo Abeni,
Simon Horman, kerneljasonxing, lance.yang, jiayuan.chen,
linux-kernel, linux-trace-kernel, Leon Huang Fu
In-Reply-To: <20260119083759.5deeaa3c@kernel.org>
On 19/01/2026 17.37, Jakub Kicinski wrote:
> On Mon, 19 Jan 2026 18:21:19 +0800 Leon Hwang wrote:
>> Introduce a new tracepoint to track stalled page pool releases,
>> providing better observability for page pool lifecycle issues.
>
> Sorry, I really want you to answer the questions from the last
> paragraph of:
>
> https://lore.kernel.org/netdev/20260104084347.5de3a537@kernel.org/
Okay, I will answer that, if you will answer:
What monitoring tool did production people add metrics to?
People at CF recommend that I/we add this to prometheus node_exporter[0].
Perhaps somebody else already added this to some other FOSS tool?
--Jesper
[0] https://github.com/prometheus/node_exporter
^ permalink raw reply
* Re: [PATCH net-next v3] page_pool: Add page_pool_release_stalled tracepoint
From: Jakub Kicinski @ 2026-01-19 16:43 UTC (permalink / raw)
To: Jesper Dangaard Brouer
Cc: Leon Hwang, netdev, Ilias Apalodimas, Steven Rostedt,
Masami Hiramatsu, Mathieu Desnoyers, David S . Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, kerneljasonxing,
lance.yang, jiayuan.chen, linux-kernel, linux-trace-kernel,
Leon Huang Fu, Dragos Tatulea, kernel-team, Yan Zhai
In-Reply-To: <34a10265-e6de-489d-b079-6f6c5cc48dc7@kernel.org>
On Mon, 19 Jan 2026 10:54:13 +0100 Jesper Dangaard Brouer wrote:
> On 19/01/2026 09.49, Leon Hwang wrote:
> >> My input here is the least valuable (since one may expect the person
> >> who added the code uses it) - but FWIW yes, we do use the PP stats to
> >> monitor PP lifecycle issues at Meta. That said - we only monitor for
> >> accumulation of leaked memory from orphaned pages, as the whole reason
> >> for adding this code was that in practice the page may be sitting in
> >> a socket rx queue (or defer free queue etc.) IOW a PP which is not
> >> getting destroyed for a long time is not necessarily a kernel issue.
> >>
>
> What monitoring tool did production people add metrics to?
>
> People at CF recommend that I/we add this to prometheus/node_exporter.
> Perhaps somebody else already added this to some other FOSS tool?
>
> https://github.com/prometheus/node_exporter
We added it to this:
https://github.com/facebookincubator/dynolog
But AFAICT it's missing from the open source version(?!)
Luckily ynltool now exists so one can just plug it into any monitoring
system that can hoover up JSON:
ynltool -j page-pool stats
^ permalink raw reply
* Re: [PATCH net-next v4] page_pool: Add page_pool_release_stalled tracepoint
From: Jakub Kicinski @ 2026-01-19 16:37 UTC (permalink / raw)
To: Leon Hwang
Cc: netdev, Jesper Dangaard Brouer, Ilias Apalodimas, Steven Rostedt,
Masami Hiramatsu, Mathieu Desnoyers, David S . Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, kerneljasonxing,
lance.yang, jiayuan.chen, linux-kernel, linux-trace-kernel,
Leon Huang Fu
In-Reply-To: <20260119102119.176211-1-leon.hwang@linux.dev>
On Mon, 19 Jan 2026 18:21:19 +0800 Leon Hwang wrote:
> Introduce a new tracepoint to track stalled page pool releases,
> providing better observability for page pool lifecycle issues.
Sorry, I really want you to answer the questions from the last
paragraph of:
https://lore.kernel.org/netdev/20260104084347.5de3a537@kernel.org/
--
pw-bot: cr
^ permalink raw reply
* Re: iommu: Fix NULL pointer deref when io_page_fault tracepoint fires
From: Daniel Thompson @ 2026-01-19 16:15 UTC (permalink / raw)
To: Markus Elfring
Cc: linux-trace-kernel, linux-arm-kernel, Masami Hiramatsu,
Mathieu Desnoyers, Steven Rostedt, LKML, Robin Murphy,
Will Deacon
In-Reply-To: <a2aa3091-4a93-48be-970a-8bc506fb0cd3@web.de>
On Mon, Jan 19, 2026 at 04:56:04PM +0100, Markus Elfring wrote:
> >> …
> >>> Fix this by adding logic to the tracepoint to safely propagate NULL.
> >>
> >> * How do you think about to add any tags (like “Fixes” and “Cc”) accordingly?
> >
> > I could add a
> >
> > Fixes: f8f934c180f6 ("iommu/arm-smmu: Add support for driver IOMMU fault handlers")
> >
> > However, who do you think I neglected to Cc:?
>
> See also once more:
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?h=v6.19-rc5#n262
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/stable-kernel-rules.rst?h=v6.19-rc5#n34
That's not what I asked! You suggested I add people to Cc:, who do you
think I missed?
> >> * Would a summary phrase like “Prevent null pointer dereference for a tracepoint”
> >> be a bit nicer?
> >
> > I don't understand what is wrong with the original phrasing. Can you
> > explain why this change matters to you?
>
> * Questionable abbreviation “deref”
> * when clause
I dislike the proposed new summary. I think keeping "io_page_fault"
in the summary is a much better use of characters than spelling
dereference in full.
Daniel.
^ permalink raw reply
* Re: iommu: Fix NULL pointer deref when io_page_fault tracepoint fires
From: Markus Elfring @ 2026-01-19 15:56 UTC (permalink / raw)
To: Daniel Thompson, linux-trace-kernel, linux-arm-kernel
Cc: Masami Hiramatsu, Mathieu Desnoyers, Steven Rostedt, LKML,
Robin Murphy, Will Deacon
In-Reply-To: <aW5CIA1aCC8FVyFl@aspen.lan>
>> …
>>> Fix this by adding logic to the tracepoint to safely propagate NULL.
>>
>> * How do you think about to add any tags (like “Fixes” and “Cc”) accordingly?
>
> I could add a
>
> Fixes: f8f934c180f6 ("iommu/arm-smmu: Add support for driver IOMMU fault handlers")
>
> However, who do you think I neglected to Cc:?
See also once more:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?h=v6.19-rc5#n262
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/stable-kernel-rules.rst?h=v6.19-rc5#n34
>> * Would a summary phrase like “Prevent null pointer dereference for a tracepoint”
>> be a bit nicer?
>
> I don't understand what is wrong with the original phrasing. Can you
> explain why this change matters to you?
* Questionable abbreviation “deref”
* when clause
Regards,
Markus
^ permalink raw reply
* Re: [PATCH v3 0/2] tracing: Remove backup instance after read all
From: Masami Hiramatsu @ 2026-01-19 15:27 UTC (permalink / raw)
To: Masami Hiramatsu (Google)
Cc: Steven Rostedt, Mathieu Desnoyers, linux-kernel,
linux-trace-kernel
In-Reply-To: <176828713313.2161268.62228177827727824.stgit@mhiramat.tok.corp.google.com>
I found another bug on this (or persistent ring buffer itself)
Let me fix it first.
On Tue, 13 Jan 2026 15:52:13 +0900
"Masami Hiramatsu (Google)" <mhiramat@kernel.org> wrote:
> Hi,
>
> Here is the 3rd version of the series to improve backup instances of
> the persistent ring buffer. The previous version is here:
>
> https://lore.kernel.org/all/176788217131.1398317.11144318616426272901.stgit@mhiramat.tok.corp.google.com/
>
> In this version, I updated [1/2] to back to checking readonly
> flag and consolidate the eventfs_entries.
>
> Since backup instances are a kind of snapshot of the persistent
> ring buffer, it should be readonly. And if it is readonly
> there is no reason to keep it after reading all data via trace_pipe
> because the data has been consumed.
> Thus, [1/2] makes backup instances readonly (not able to write any
> events, cleanup trace, change buffer size). Also, [2/2] removes the
> backup instance after consuming all data via trace_pipe.
> With this improvements, even if we makes a backup instance (using
> the same amount of memory of the persistent ring buffer), it will
> be removed after reading the data automatically.
>
> ---
>
> Masami Hiramatsu (Google) (2):
> tracing: Make the backup instance readonly
> tracing: Add autoremove feature to the backup instance
>
>
> kernel/trace/trace.c | 164 +++++++++++++++++++++++++++++++++++--------
> kernel/trace/trace.h | 14 +++-
> kernel/trace/trace_boot.c | 5 +
> kernel/trace/trace_events.c | 68 +++++++++++-------
> 4 files changed, 191 insertions(+), 60 deletions(-)
>
> --
> Masami Hiramatsu (Google) <mhiramat@kernel.org>
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply
* Re: [PATCH] iommu: Fix NULL pointer deref when io_page_fault tracepoint fires
From: Daniel Thompson @ 2026-01-19 14:39 UTC (permalink / raw)
To: Markus Elfring
Cc: linux-trace-kernel, linux-arm-kernel, Masami Hiramatsu,
Mathieu Desnoyers, Steven Rostedt, LKML, Robin Murphy,
Will Deacon
In-Reply-To: <fca8f2cd-c3e5-40b0-a793-bded109e37bc@web.de>
On Fri, Jan 16, 2026 at 05:02:35PM +0100, Markus Elfring wrote:
> …
> > Fix this by adding logic to the tracepoint to safely propagate NULL.
>
> * How do you think about to add any tags (like “Fixes” and “Cc”) accordingly?
I could add a
Fixes: f8f934c180f6 ("iommu/arm-smmu: Add support for driver IOMMU fault handlers")
However, who do you think I neglected to Cc:?
> * Would a summary phrase like “Prevent null pointer dereference for a tracepoint”
> be a bit nicer?
I don't understand what is wrong with the original phrasing. Can you
explain why this change matters to you?
Daniel.
^ permalink raw reply
* [GIT PULL] RTLA additional fixes for v6.20
From: Tomas Glozar @ 2026-01-19 13:50 UTC (permalink / raw)
To: Steven Rostedt; +Cc: Costa Shulyupin, LKML, Linux Trace Kernel, Tomas Glozar
Steven,
please pull additional fixes for bugs that were caught in RTLA during
the testing of linux-next.
Thanks,
Tomas
The following changes since commit fb8b8183208d8efe824e8d2c73fb1ab5ad1191fd:
rtla: Fix parse_cpu_set() return value documentation (2026-01-07 15:57:56 +0100)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/tglozar/linux.git/ tags/rtla-v6.20-fixups
for you to fetch changes up to 6ea8a206108fe8b5940c2797afc54ae9f5a7bbdd:
rtla: Fix parse_cpu_set() bug introduced by strtoi() (2026-01-13 08:32:52 +0100)
----------------------------------------------------------------
RTLA additional fixes for v6.20
- Fix bug in cpuset parsing
A commit queued for 6.20 changed atoi() to a new strtoi() function on
a tree-wide level. This broke cpuset parsing, which relies on atoi()'s
behavior of skipping non-numeric prefixes.
Revert cpuset parsing back to using atoi() to prevent the breakage.
The log entries above are purely informative; since the fix is for a bug
not yet merged upstream, it needs no mention in the merge description.
The tag was tested (make && make check) as well as pre-tested on top of
next-20260116. There are no additional known conflicts.
Signed-off-by: Tomas Glozar <tglozar@redhat.com>
----------------------------------------------------------------
Costa Shulyupin (1):
rtla: Fix parse_cpu_set() bug introduced by strtoi()
tools/tracing/rtla/src/utils.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
^ permalink raw reply
* Re: [PATCH v4 14/15] rv: Add deadline monitors
From: Juri Lelli @ 2026-01-19 13:16 UTC (permalink / raw)
To: Gabriele Monaco
Cc: linux-kernel, Steven Rostedt, Nam Cao, Juri Lelli,
Jonathan Corbet, Masami Hiramatsu, linux-trace-kernel, linux-doc,
Peter Zijlstra, Tomas Glozar, Clark Williams, John Kacur
In-Reply-To: <5df16facba05b84857ad09cee12df0c19a551285.camel@redhat.com>
On 19/01/26 12:35, Gabriele Monaco wrote:
> On Mon, 2026-01-19 at 12:04 +0100, Juri Lelli wrote:
> > Why use pi_of() in above cases?
> >
> > For the first, in case the macro is called while the task is actually
> > boosted, we then might continue to use that even after such task gets
> > deboosted?
>
> Mmh, yeah thinking about it again it doesn't make much sense considering we are
> not tracking when a task is deboosted, unless that always corresponds to a
> replenish. Thought that doesn't seem the case..
>
> > For the second, current PI implementation (even if admittedly not ideal)
> > uses donor's static dl_runtime to replenish boosted task runtime, but
> > then accounting is performed again the task dynamic runtime, not the
> > donor's (this all will hopefully change soon with proxy exec..)?
>
> At this point I should probably just ignore the pi_of() right?
> I'm assuming the original (non-boosted) parameters are more conservative anyway
> so it shouldn't be a problem for the model.
Yeah, it seems alright (at least for now) to use original parameters.
Thanks,
Juri
^ permalink raw reply
* Re: [RFC 5/5] ext4: mark group extend fast-commit ineligible
From: Li Chen @ 2026-01-19 12:37 UTC (permalink / raw)
To: Theodore Tso
Cc: Andreas Dilger, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, linux-ext4, linux-kernel, linux-trace-kernel
In-Reply-To: <20260119025857.GC19954@macsyma.local>
Hi Theodore,
Thanks for your reply.
> On Thu, Dec 11, 2025 at 07:51:42PM +0800, Li Chen wrote:
> > Fast commits only log operations that have dedicated replay support.
> > EXT4_IOC_GROUP_EXTEND grows the filesystem to the end of the last
> > block group and updates the same on-disk metadata without going
> > through the fast commit tracking paths.
> > In practice these operations are rare and usually followed by further
> > updates, but mixing them into a fast commit makes the overall
> > semantics harder to reason about and risks replay gaps if new call
> > sites appear.
> >
> > Teach ext4 to mark the filesystem fast-commit ineligible when
> > EXT4_IOC_GROUP_EXTEND grows the filesystem.
> > This forces those transactions to fall back to a full commit,
> > ensuring that the group extension changes are captured by the normal
> > journal rather than partially encoded in fast commit TLVs.
> > This change should not affect common workloads but makes online
> > resize via GROUP_EXTEND safer and easier to reason about under fast
> > commit.
> >
> > Testing:
> > 1. prepare:
> > dd if=/dev/zero of=/root/fc_resize.img bs=1M count=0 seek=256
> > mkfs.ext4 -O fast_commit -F /root/fc_resize.img
> > mkdir -p /mnt/fc_resize && mount -t ext4 -o loop /root/fc_resize.img /mnt/fc_resize
> > 2. Extended the filesystem to the end of the last block group using a
> > helper that calls EXT4_IOC_GROUP_EXTEND on the mounted filesystem
> > and checked fc_info:
> > ./group_extend_helper /mnt/fc_resize
> > cat /proc/fs/ext4/loop0/fc_info
> > shows the "Resize" ineligible reason increased.
> > 3. Fsynced a file on the resized filesystem and confirmed that the fast
> > commit ineligible counter incremented for the resize transaction:
> > touch /mnt/fc_resize/file
> > /root/fsync_file /mnt/fc_resize/file
> > sync
> > cat /proc/fs/ext4/loop0/fc_info
> >
> > Signed-off-by: Li Chen <me@linux.beauty>
>
> I'm curious what version of the kernel you were testing against? I
> needed to mnake the final fix up to allow the patch to compile:
I'm sorry I didn't mention the kernel version in the cover letter. This patchset is built against 7d0a66e4bb90 (tag: v6.18) Linux 6.18.
Regards,
Li
> diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c
> index 9354083222b1..ce1f738dff93 100644
> --- a/fs/ext4/move_extent.c
> +++ b/fs/ext4/move_extent.c
> @@ -321,7 +321,8 @@ static int mext_move_extent(struct mext_data *mext, u64 *m_len)
> ret = PTR_ERR(handle);
> goto out;
> }
> - ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_MOVE_EXT, handle);
> + ext4_fc_mark_ineligible(orig_inode->i_sb, EXT4_FC_REASON_MOVE_EXT,
> + handle);
>
> ret = mext_move_begin(mext, folio, &move_type);
> if (ret)
>
> - Ted
>
^ permalink raw reply
* [PATCH 2/2] Documentation/rtla: Document --stack-format option
From: Tomas Glozar @ 2026-01-19 11:52 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar
Cc: Costa Shulyupin, Crystal Wood, John Kacur, Luis Goncalves,
Wander Lairson Costa, LKML, Linux Trace Kernel
In-Reply-To: <20260119115222.744150-1-tglozar@redhat.com>
Add documentation for --stack-format option of rtla-timerlat into its
common options.
Signed-off-by: Tomas Glozar <tglozar@redhat.com>
---
Documentation/tools/rtla/common_timerlat_options.txt | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/Documentation/tools/rtla/common_timerlat_options.txt b/Documentation/tools/rtla/common_timerlat_options.txt
index 07a285fcf7cf..ab159b2cbfe7 100644
--- a/Documentation/tools/rtla/common_timerlat_options.txt
+++ b/Documentation/tools/rtla/common_timerlat_options.txt
@@ -83,3 +83,15 @@
**Note**: BPF actions require BPF support to be available. If BPF is not available
or disabled, the tool falls back to tracefs mode and BPF actions are not supported.
+
+**--stack-format** *format*
+
+ Adjust the format of the stack trace printed during auto-analysis.
+
+ The supported values for *format* are:
+
+ * **truncate** Print the stack trace up to the first unknown address (default).
+ * **skip** Skip unknown addresses.
+ * **full** Print the entire stack trace, including unknown addresses.
+
+ For unknown addresses, the raw pointer is printed.
--
2.52.0
^ permalink raw reply related
* [PATCH 1/2] rtla/timerlat: Add --stack-format option
From: Tomas Glozar @ 2026-01-19 11:52 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar
Cc: Costa Shulyupin, Crystal Wood, John Kacur, Luis Goncalves,
Wander Lairson Costa, LKML, Linux Trace Kernel
In the current implementation, the auto-analysis code for printing the
stack captured in the tracefs buffer of the aa instance stops at the
first encountered address that cannot be resolved into a function
symbol.
This is not always the desired behavior on all platforms; sometimes,
there might be resolvable entries after unresolvable ones, and
sometimes, the user might want to inspect the raw pointers for the
unresolvable entries.
Add a new option, --stack-format, with three values:
- truncate: stop at first unresolvable entry. This is the current
behavior, and is kept as the default.
- skip: skip unresolvable entries, but do not stop on them.
- full: print all entries, including unresolvable ones.
To make this work, the "size" field of the stack entry is now also read
and used as the maximum number of entries to print, capped at 64, since
that is the fixed length of the "caller" field.
Signed-off-by: Tomas Glozar <tglozar@redhat.com>
---
tools/tracing/rtla/src/timerlat.c | 2 +-
tools/tracing/rtla/src/timerlat.h | 1 +
tools/tracing/rtla/src/timerlat_aa.c | 36 +++++++++++++++++++++-----
tools/tracing/rtla/src/timerlat_aa.h | 2 +-
tools/tracing/rtla/src/timerlat_hist.c | 10 +++++++
tools/tracing/rtla/src/timerlat_top.c | 10 +++++++
tools/tracing/rtla/src/utils.c | 18 +++++++++++++
tools/tracing/rtla/src/utils.h | 7 +++++
8 files changed, 77 insertions(+), 9 deletions(-)
diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c
index 8f8811f7a13b..9e4daed0aafc 100644
--- a/tools/tracing/rtla/src/timerlat.c
+++ b/tools/tracing/rtla/src/timerlat.c
@@ -134,7 +134,7 @@ int timerlat_enable(struct osnoise_tool *tool)
if (!tool->aa)
return -1;
- retval = timerlat_aa_init(tool->aa, params->dump_tasks);
+ retval = timerlat_aa_init(tool->aa, params->dump_tasks, params->stack_format);
if (retval) {
err_msg("Failed to enable the auto analysis instance\n");
return retval;
diff --git a/tools/tracing/rtla/src/timerlat.h b/tools/tracing/rtla/src/timerlat.h
index 8dd5d134ce08..364203a29abd 100644
--- a/tools/tracing/rtla/src/timerlat.h
+++ b/tools/tracing/rtla/src/timerlat.h
@@ -28,6 +28,7 @@ struct timerlat_params {
int deepest_idle_state;
enum timerlat_tracing_mode mode;
const char *bpf_action_program;
+ enum stack_format stack_format;
};
#define to_timerlat_params(ptr) container_of(ptr, struct timerlat_params, common)
diff --git a/tools/tracing/rtla/src/timerlat_aa.c b/tools/tracing/rtla/src/timerlat_aa.c
index 31e66ea2b144..178de60dcef9 100644
--- a/tools/tracing/rtla/src/timerlat_aa.c
+++ b/tools/tracing/rtla/src/timerlat_aa.c
@@ -104,6 +104,7 @@ struct timerlat_aa_data {
struct timerlat_aa_context {
int nr_cpus;
int dump_tasks;
+ enum stack_format stack_format;
/* per CPU data */
struct timerlat_aa_data *taa_data;
@@ -481,23 +482,43 @@ static int timerlat_aa_stack_handler(struct trace_seq *s, struct tep_record *rec
{
struct timerlat_aa_context *taa_ctx = timerlat_aa_get_ctx();
struct timerlat_aa_data *taa_data = timerlat_aa_get_data(taa_ctx, record->cpu);
+ enum stack_format stack_format = taa_ctx->stack_format;
unsigned long *caller;
const char *function;
- int val, i;
+ int val;
+ unsigned long long i;
trace_seq_reset(taa_data->stack_seq);
trace_seq_printf(taa_data->stack_seq, " Blocking thread stack trace\n");
caller = tep_get_field_raw(s, event, "caller", record, &val, 1);
+
if (caller) {
- for (i = 0; ; i++) {
+ unsigned long long size;
+ unsigned long long max_entries;
+
+ if (tep_get_field_val(s, event, "size", record, &size, 1) == 0)
+ max_entries = size < 64 ? size : 64;
+ else
+ max_entries = 64;
+
+ for (i = 0; i < max_entries; i++) {
function = tep_find_function(taa_ctx->tool->trace.tep, caller[i]);
- if (!function)
- break;
- trace_seq_printf(taa_data->stack_seq, " %.*s -> %s\n",
- 14, spaces, function);
+ if (!function) {
+ if (stack_format == STACK_FORMAT_TRUNCATE)
+ break;
+ else if (stack_format == STACK_FORMAT_SKIP)
+ continue;
+ else if (stack_format == STACK_FORMAT_FULL)
+ trace_seq_printf(taa_data->stack_seq, " %.*s -> 0x%lx\n",
+ 14, spaces, caller[i]);
+ } else {
+ trace_seq_printf(taa_data->stack_seq, " %.*s -> %s\n",
+ 14, spaces, function);
+ }
}
}
+
return 0;
}
@@ -1020,7 +1041,7 @@ void timerlat_aa_destroy(void)
*
* Returns 0 on success, -1 otherwise.
*/
-int timerlat_aa_init(struct osnoise_tool *tool, int dump_tasks)
+int timerlat_aa_init(struct osnoise_tool *tool, int dump_tasks, enum stack_format stack_format)
{
int nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
struct timerlat_aa_context *taa_ctx;
@@ -1035,6 +1056,7 @@ int timerlat_aa_init(struct osnoise_tool *tool, int dump_tasks)
taa_ctx->nr_cpus = nr_cpus;
taa_ctx->tool = tool;
taa_ctx->dump_tasks = dump_tasks;
+ taa_ctx->stack_format = stack_format;
taa_ctx->taa_data = calloc(nr_cpus, sizeof(*taa_ctx->taa_data));
if (!taa_ctx->taa_data)
diff --git a/tools/tracing/rtla/src/timerlat_aa.h b/tools/tracing/rtla/src/timerlat_aa.h
index cea4bb1531a8..a11b5f30cdce 100644
--- a/tools/tracing/rtla/src/timerlat_aa.h
+++ b/tools/tracing/rtla/src/timerlat_aa.h
@@ -3,7 +3,7 @@
* Copyright (C) 2023 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
*/
-int timerlat_aa_init(struct osnoise_tool *tool, int dump_task);
+int timerlat_aa_init(struct osnoise_tool *tool, int dump_task, enum stack_format stack_format);
void timerlat_aa_destroy(void);
void timerlat_auto_analysis(int irq_thresh, int thread_thresh);
diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c
index 4e8c38a61197..e5b3d4f098b2 100644
--- a/tools/tracing/rtla/src/timerlat_hist.c
+++ b/tools/tracing/rtla/src/timerlat_hist.c
@@ -747,6 +747,7 @@ static void timerlat_hist_usage(void)
" --on-threshold <action>: define action to be executed at latency threshold, multiple are allowed",
" --on-end <action>: define action to be executed at measurement end, multiple are allowed",
" --bpf-action <program>: load and execute BPF program when latency threshold is exceeded",
+ " --stack-format <format>: set the stack format (truncate, skip, full)",
NULL,
};
@@ -787,6 +788,9 @@ static struct common_params
/* default to BPF mode */
params->mode = TRACING_MODE_BPF;
+ /* default to truncate stack format */
+ params->stack_format = STACK_FORMAT_TRUNCATE;
+
while (1) {
static struct option long_options[] = {
{"auto", required_argument, 0, 'a'},
@@ -819,6 +823,7 @@ static struct common_params
{"on-threshold", required_argument, 0, '\5'},
{"on-end", required_argument, 0, '\6'},
{"bpf-action", required_argument, 0, '\7'},
+ {"stack-format", required_argument, 0, '\10'},
{0, 0, 0, 0}
};
@@ -966,6 +971,11 @@ static struct common_params
case '\7':
params->bpf_action_program = optarg;
break;
+ case '\10':
+ params->stack_format = parse_stack_format(optarg);
+ if (params->stack_format == -1)
+ fatal("Invalid --stack-format option");
+ break;
default:
fatal("Invalid option");
}
diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c
index 284b74773c2b..d6ce7dcb8e82 100644
--- a/tools/tracing/rtla/src/timerlat_top.c
+++ b/tools/tracing/rtla/src/timerlat_top.c
@@ -518,6 +518,7 @@ static void timerlat_top_usage(void)
" --on-threshold <action>: define action to be executed at latency threshold, multiple are allowed",
" --on-end: define action to be executed at measurement end, multiple are allowed",
" --bpf-action <program>: load and execute BPF program when latency threshold is exceeded",
+ " --stack-format <format>: set the stack format (truncate, skip, full)",
NULL,
};
@@ -556,6 +557,9 @@ static struct common_params
/* default to BPF mode */
params->mode = TRACING_MODE_BPF;
+ /* default to truncate stack format */
+ params->stack_format = STACK_FORMAT_TRUNCATE;
+
while (1) {
static struct option long_options[] = {
{"auto", required_argument, 0, 'a'},
@@ -582,6 +586,7 @@ static struct common_params
{"on-threshold", required_argument, 0, '9'},
{"on-end", required_argument, 0, '\1'},
{"bpf-action", required_argument, 0, '\2'},
+ {"stack-format", required_argument, 0, '\3'},
{0, 0, 0, 0}
};
@@ -716,6 +721,11 @@ static struct common_params
case '\2':
params->bpf_action_program = optarg;
break;
+ case '\3':
+ params->stack_format = parse_stack_format(optarg);
+ if (params->stack_format == -1)
+ fatal("Invalid --stack-format option");
+ break;
default:
fatal("Invalid option");
}
diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c
index 0da3b2470c31..d979159f6b70 100644
--- a/tools/tracing/rtla/src/utils.c
+++ b/tools/tracing/rtla/src/utils.c
@@ -164,6 +164,24 @@ int parse_cpu_set(char *cpu_list, cpu_set_t *set)
return 1;
}
+/*
+ * parse_stack_format - parse the stack format
+ *
+ * Return: the stack format on success, -1 otherwise.
+ */
+int parse_stack_format(char *arg)
+{
+ if (!strcmp(arg, "truncate"))
+ return STACK_FORMAT_TRUNCATE;
+ if (!strcmp(arg, "skip"))
+ return STACK_FORMAT_SKIP;
+ if (!strcmp(arg, "full"))
+ return STACK_FORMAT_FULL;
+
+ debug_msg("Error parsing the stack format %s\n", arg);
+ return -1;
+}
+
/*
* parse_duration - parse duration with s/m/h/d suffix converting it to seconds
*/
diff --git a/tools/tracing/rtla/src/utils.h b/tools/tracing/rtla/src/utils.h
index f7c2a52a0ab5..80d5ec0cf934 100644
--- a/tools/tracing/rtla/src/utils.h
+++ b/tools/tracing/rtla/src/utils.h
@@ -62,8 +62,15 @@ struct sched_attr {
};
#endif /* SCHED_ATTR_SIZE_VER0 */
+enum stack_format {
+ STACK_FORMAT_TRUNCATE,
+ STACK_FORMAT_SKIP,
+ STACK_FORMAT_FULL
+};
+
int parse_prio(char *arg, struct sched_attr *sched_param);
int parse_cpu_set(char *cpu_list, cpu_set_t *set);
+int parse_stack_format(char *arg);
int __set_sched_attr(int pid, struct sched_attr *attr);
int set_comm_sched_attr(const char *comm_prefix, struct sched_attr *attr);
int set_comm_cgroup(const char *comm_prefix, const char *cgroup);
--
2.52.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox