summaryrefslogtreecommitdiffstats
path: root/scripts/rustdoc_test_builder.rs
diff options
context:
space:
mode:
authorSteven Rostedt <rostedt@goodmis.org>2026-09-02 09:55:01 -0400
committerSteven Rostedt <rostedt@goodmis.org>2026-09-02 11:08:21 -0400
commit4617721c502b2ddaa4e324e86da4997edf738fa5 (patch)
tree350aa83b47da0b574a814795392b20b0bed83cbc /scripts/rustdoc_test_builder.rs
downloadlinux-stable-4617721c502b2ddaa4e324e86da4997edf738fa5.tar.gz
linux-stable-4617721c502b2ddaa4e324e86da4997edf738fa5.zip
ftrace: Synchronize the initialization of ftrace_opsgrafted
There's some internal state that ftrace_ops needs to have set, but since it can be declared outside of the ftrace.c code, it calls ftrace_ops_init() on the ops in every global function. The issue is that if two tasks call it on the same ops at the same time it is possible to have the initialization of one corrupt the initialization of the other call. Create a ops_mutex to use to synchronize every initialization of the ftrace_ops. The mutex is taken within checking the ftrace_ops flag that states it was initializied but the flag is checked again after the mutex has been taken. Checking first outside the mutex allows it to shortcut having to take the mutex. But then the check needs to be done again after the mute is taken in case of races. Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260902095501.6b59af20@gandalf.local.home Fixes: f04f24fb7e48d ("ftrace, kprobes: Fix a deadlock on ftrace_regex_lock") Reported-by: sashiko-bot@kernel.org Close: https://lore.kernel.org/all/20260829025528.49A831F000E9@smtp.kernel.org/ Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'scripts/rustdoc_test_builder.rs')
-rw-r--r--scripts/rustdoc_test_builder.rs78
1 files changed, 78 insertions, 0 deletions
diff --git a/scripts/rustdoc_test_builder.rs b/scripts/rustdoc_test_builder.rs
new file mode 100644
index 000000000..df864437c
--- /dev/null
+++ b/scripts/rustdoc_test_builder.rs
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Test builder for `rustdoc`-generated tests.
+//!
+//! This script is a hack to extract the test from `rustdoc`'s output. Ideally, `rustdoc` would
+//! have an option to generate this information instead, e.g. as JSON output.
+//!
+//! The `rustdoc`-generated test names look like `{file}_{line}_{number}`, e.g.
+//! `...path_rust_kernel_sync_arc_rs_42_0`. `number` is the "test number", needed in cases like
+//! a macro that expands into items with doctests is invoked several times within the same line.
+//!
+//! However, since these names are used for bisection in CI, the line number makes it not stable
+//! at all. In the future, we would like `rustdoc` to give us the Rust item path associated with
+//! the test, plus a "test number" (for cases with several examples per item) and generate a name
+//! from that. For the moment, we generate ourselves a new name, `{file}_{number}` instead, in
+//! the `gen` script (done there since we need to be aware of all the tests in a given file).
+
+use std::io::Read;
+
+fn main() {
+ let mut stdin = std::io::stdin().lock();
+ let mut body = String::new();
+ stdin.read_to_string(&mut body).unwrap();
+
+ // Find the generated function name looking for the inner function inside `main()`.
+ //
+ // The line we are looking for looks like one of the following:
+ //
+ // ```
+ // fn main() { #[allow(non_snake_case)] fn _doctest_main_rust_kernel_file_rs_28_0() {
+ // fn main() { #[allow(non_snake_case)] fn _doctest_main_rust_kernel_file_rs_37_0() -> Result<(), impl core::fmt::Debug> {
+ // ```
+ //
+ // It should be unlikely that doctest code matches such lines (when code is formatted properly).
+ let rustdoc_function_name = body
+ .lines()
+ .find_map(|line| {
+ Some(
+ line.split_once("fn main() {")?
+ .1
+ .split_once("fn ")?
+ .1
+ .split_once("()")?
+ .0,
+ )
+ .filter(|x| x.chars().all(|c| c.is_alphanumeric() || c == '_'))
+ })
+ .expect("No test function found in `rustdoc`'s output.");
+
+ // Replicate `rustdoc` 1.87+ behaviour [1] by fully qualifying `Result` to avoid the collision
+ // with our own `Result` coming from the prelude.
+ //
+ // [1]: https://github.com/rust-lang/rust/pull/137807
+ //
+ // TODO: Remove this when MSRV is bumped above 1.87.
+ let body = body.replace(
+ &format!("{rustdoc_function_name}() -> Result<(), impl core::fmt::Debug> {{"),
+ // This intentionally does not use absolute paths to match `rustdoc` 1.87 behaviour.
+ &format!("{rustdoc_function_name}() -> core::result::Result<(), impl core::fmt::Debug> {{"),
+ );
+
+ // For tests that get generated with `Result`, like above, `rustdoc` generates an `unwrap()` on
+ // the return value to check there were no returned errors. Instead, we use our assert macro
+ // since we want to just fail the test, not panic the kernel.
+ //
+ // We save the result in a variable so that the failed assertion message looks nicer.
+ let body = body.replace(
+ &format!("}} {rustdoc_function_name}().unwrap() }}"),
+ &format!("}} let test_return_value = {rustdoc_function_name}(); assert!(test_return_value.is_ok()); }}"),
+ );
+
+ // Figure out a smaller test name based on the generated function name.
+ let name = rustdoc_function_name.split_once("_rust_kernel_").unwrap().1;
+
+ let path = format!("rust/test/doctests/kernel/{name}");
+
+ std::fs::write(path, body.as_bytes()).unwrap();
+}