mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00
rust: add tracepoint support
Make it possible to have Rust code call into tracepoints defined by C code. It is still required that the tracepoint is declared in a C header, and that this header is included in the input to bindgen. Instead of calling __DO_TRACE directly, the exported rust_do_trace_ function calls an inline helper function. This is because the `cond` argument does not exist at the callsite of DEFINE_RUST_DO_TRACE. __DECLARE_TRACE always emits an inline static and an extern declaration that is only used when CREATE_RUST_TRACE_POINTS is set. These should not end up in the final binary so it is not a problem that they sometimes are emitted without a user. Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Josh Poimboeuf <jpoimboe@kernel.org> Cc: Jason Baron <jbaron@akamai.com> Cc: Ard Biesheuvel <ardb@kernel.org> Cc: Miguel Ojeda <ojeda@kernel.org> Cc: Alex Gaynor <alex.gaynor@gmail.com> Cc: Wedson Almeida Filho <wedsonaf@gmail.com> Cc: " =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= " <bjorn3_gh@protonmail.com> Cc: Benno Lossin <benno.lossin@proton.me> Cc: Andreas Hindborg <a.hindborg@kernel.org> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Ingo Molnar <mingo@redhat.com> Cc: Borislav Petkov <bp@alien8.de> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Sean Christopherson <seanjc@google.com> Cc: Uros Bizjak <ubizjak@gmail.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Will Deacon <will@kernel.org> Cc: Marc Zyngier <maz@kernel.org> Cc: Oliver Upton <oliver.upton@linux.dev> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Ryan Roberts <ryan.roberts@arm.com> Cc: Fuad Tabba <tabba@google.com> Cc: Paul Walmsley <paul.walmsley@sifive.com> Cc: Palmer Dabbelt <palmer@dabbelt.com> Cc: Albert Ou <aou@eecs.berkeley.edu> Cc: Anup Patel <apatel@ventanamicro.com> Cc: Andrew Jones <ajones@ventanamicro.com> Cc: Alexandre Ghiti <alexghiti@rivosinc.com> Cc: Conor Dooley <conor.dooley@microchip.com> Cc: Samuel Holland <samuel.holland@sifive.com> Cc: Huacai Chen <chenhuacai@kernel.org> Cc: WANG Xuerui <kernel@xen0n.name> Cc: Bibo Mao <maobibo@loongson.cn> Cc: Tiezhu Yang <yangtiezhu@loongson.cn> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Tianrui Zhao <zhaotianrui@loongson.cn> Link: https://lore.kernel.org/20241030-tracepoint-v12-2-eec7f0f8ad22@google.com Reviewed-by: Carlos Llamas <cmllamas@google.com> Reviewed-by: Gary Guo <gary@garyguo.net> Reviewed-by: Boqun Feng <boqun.feng@gmail.com> Signed-off-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
This commit is contained in:
parent
6e59bcc9c8
commit
ad37bcd965
@ -225,6 +225,18 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
|
|||||||
preempt_enable_notrace(); \
|
preempt_enable_notrace(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Declare an exported function that Rust code can call to trigger this
|
||||||
|
* tracepoint. This function does not include the static branch; that is done
|
||||||
|
* in Rust to avoid a function call when the tracepoint is disabled.
|
||||||
|
*/
|
||||||
|
#define DEFINE_RUST_DO_TRACE(name, proto, args)
|
||||||
|
#define __DEFINE_RUST_DO_TRACE(name, proto, args) \
|
||||||
|
notrace void rust_do_trace_##name(proto) \
|
||||||
|
{ \
|
||||||
|
__rust_do_trace_##name(args); \
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure the alignment of the structure in the __tracepoints section will
|
* Make sure the alignment of the structure in the __tracepoints section will
|
||||||
* not add unwanted padding between the beginning of the section and the
|
* not add unwanted padding between the beginning of the section and the
|
||||||
@ -240,6 +252,7 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
|
|||||||
extern int __traceiter_##name(data_proto); \
|
extern int __traceiter_##name(data_proto); \
|
||||||
DECLARE_STATIC_CALL(tp_func_##name, __traceiter_##name); \
|
DECLARE_STATIC_CALL(tp_func_##name, __traceiter_##name); \
|
||||||
extern struct tracepoint __tracepoint_##name; \
|
extern struct tracepoint __tracepoint_##name; \
|
||||||
|
extern void rust_do_trace_##name(proto); \
|
||||||
static inline int \
|
static inline int \
|
||||||
register_trace_##name(void (*probe)(data_proto), void *data) \
|
register_trace_##name(void (*probe)(data_proto), void *data) \
|
||||||
{ \
|
{ \
|
||||||
@ -271,6 +284,12 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
|
|||||||
|
|
||||||
#define __DECLARE_TRACE(name, proto, args, cond, data_proto) \
|
#define __DECLARE_TRACE(name, proto, args, cond, data_proto) \
|
||||||
__DECLARE_TRACE_COMMON(name, PARAMS(proto), PARAMS(args), cond, PARAMS(data_proto)) \
|
__DECLARE_TRACE_COMMON(name, PARAMS(proto), PARAMS(args), cond, PARAMS(data_proto)) \
|
||||||
|
static inline void __rust_do_trace_##name(proto) \
|
||||||
|
{ \
|
||||||
|
__DO_TRACE(name, \
|
||||||
|
TP_ARGS(args), \
|
||||||
|
TP_CONDITION(cond), 0); \
|
||||||
|
} \
|
||||||
static inline void trace_##name(proto) \
|
static inline void trace_##name(proto) \
|
||||||
{ \
|
{ \
|
||||||
if (static_branch_unlikely(&__tracepoint_##name.key)) \
|
if (static_branch_unlikely(&__tracepoint_##name.key)) \
|
||||||
@ -285,6 +304,12 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
|
|||||||
|
|
||||||
#define __DECLARE_TRACE_SYSCALL(name, proto, args, cond, data_proto) \
|
#define __DECLARE_TRACE_SYSCALL(name, proto, args, cond, data_proto) \
|
||||||
__DECLARE_TRACE_COMMON(name, PARAMS(proto), PARAMS(args), cond, PARAMS(data_proto)) \
|
__DECLARE_TRACE_COMMON(name, PARAMS(proto), PARAMS(args), cond, PARAMS(data_proto)) \
|
||||||
|
static inline void __rust_do_trace_##name(proto) \
|
||||||
|
{ \
|
||||||
|
__DO_TRACE(name, \
|
||||||
|
TP_ARGS(args), \
|
||||||
|
TP_CONDITION(cond), 1); \
|
||||||
|
} \
|
||||||
static inline void trace_##name(proto) \
|
static inline void trace_##name(proto) \
|
||||||
{ \
|
{ \
|
||||||
if (static_branch_unlikely(&__tracepoint_##name.key)) \
|
if (static_branch_unlikely(&__tracepoint_##name.key)) \
|
||||||
@ -339,7 +364,8 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
|
|||||||
void __probestub_##_name(void *__data, proto) \
|
void __probestub_##_name(void *__data, proto) \
|
||||||
{ \
|
{ \
|
||||||
} \
|
} \
|
||||||
DEFINE_STATIC_CALL(tp_func_##_name, __traceiter_##_name);
|
DEFINE_STATIC_CALL(tp_func_##_name, __traceiter_##_name); \
|
||||||
|
DEFINE_RUST_DO_TRACE(_name, TP_PROTO(proto), TP_ARGS(args))
|
||||||
|
|
||||||
#define DEFINE_TRACE(name, proto, args) \
|
#define DEFINE_TRACE(name, proto, args) \
|
||||||
DEFINE_TRACE_FN(name, NULL, NULL, PARAMS(proto), PARAMS(args));
|
DEFINE_TRACE_FN(name, NULL, NULL, PARAMS(proto), PARAMS(args));
|
||||||
|
@ -76,6 +76,13 @@
|
|||||||
#define DECLARE_TRACE(name, proto, args) \
|
#define DECLARE_TRACE(name, proto, args) \
|
||||||
DEFINE_TRACE(name, PARAMS(proto), PARAMS(args))
|
DEFINE_TRACE(name, PARAMS(proto), PARAMS(args))
|
||||||
|
|
||||||
|
/* If requested, create helpers for calling these tracepoints from Rust. */
|
||||||
|
#ifdef CREATE_RUST_TRACE_POINTS
|
||||||
|
#undef DEFINE_RUST_DO_TRACE
|
||||||
|
#define DEFINE_RUST_DO_TRACE(name, proto, args) \
|
||||||
|
__DEFINE_RUST_DO_TRACE(name, PARAMS(proto), PARAMS(args))
|
||||||
|
#endif
|
||||||
|
|
||||||
#undef TRACE_INCLUDE
|
#undef TRACE_INCLUDE
|
||||||
#undef __TRACE_INCLUDE
|
#undef __TRACE_INCLUDE
|
||||||
|
|
||||||
@ -134,6 +141,11 @@
|
|||||||
# undef UNDEF_TRACE_INCLUDE_PATH
|
# undef UNDEF_TRACE_INCLUDE_PATH
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CREATE_RUST_TRACE_POINTS
|
||||||
|
# undef DEFINE_RUST_DO_TRACE
|
||||||
|
# define DEFINE_RUST_DO_TRACE(name, proto, args)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* We may be processing more files */
|
/* We may be processing more files */
|
||||||
#define CREATE_TRACE_POINTS
|
#define CREATE_TRACE_POINTS
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <linux/refcount.h>
|
#include <linux/refcount.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/tracepoint.h>
|
||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ pub mod str;
|
|||||||
pub mod sync;
|
pub mod sync;
|
||||||
pub mod task;
|
pub mod task;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
|
pub mod tracepoint;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod uaccess;
|
pub mod uaccess;
|
||||||
pub mod workqueue;
|
pub mod workqueue;
|
||||||
|
49
rust/kernel/tracepoint.rs
Normal file
49
rust/kernel/tracepoint.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
// Copyright (C) 2024 Google LLC.
|
||||||
|
|
||||||
|
//! Logic for tracepoints.
|
||||||
|
|
||||||
|
/// Declare the Rust entry point for a tracepoint.
|
||||||
|
///
|
||||||
|
/// This macro generates an unsafe function that calls into C, and its safety requirements will be
|
||||||
|
/// whatever the relevant C code requires. To document these safety requirements, you may add
|
||||||
|
/// doc-comments when invoking the macro.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! declare_trace {
|
||||||
|
($($(#[$attr:meta])* $pub:vis unsafe fn $name:ident($($argname:ident : $argtyp:ty),* $(,)?);)*) => {$(
|
||||||
|
$( #[$attr] )*
|
||||||
|
#[inline(always)]
|
||||||
|
$pub unsafe fn $name($($argname : $argtyp),*) {
|
||||||
|
#[cfg(CONFIG_TRACEPOINTS)]
|
||||||
|
{
|
||||||
|
// SAFETY: It's always okay to query the static key for a tracepoint.
|
||||||
|
let should_trace = unsafe {
|
||||||
|
$crate::macros::paste! {
|
||||||
|
$crate::jump_label::static_branch_unlikely!(
|
||||||
|
$crate::bindings::[< __tracepoint_ $name >],
|
||||||
|
$crate::bindings::tracepoint,
|
||||||
|
key
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if should_trace {
|
||||||
|
$crate::macros::paste! {
|
||||||
|
// SAFETY: The caller guarantees that it is okay to call this tracepoint.
|
||||||
|
unsafe { $crate::bindings::[< rust_do_trace_ $name >]($($argname),*) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(CONFIG_TRACEPOINTS))]
|
||||||
|
{
|
||||||
|
// If tracepoints are disabled, insert a trivial use of each argument
|
||||||
|
// to avoid unused argument warnings.
|
||||||
|
$( let _unused = $argname; )*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use declare_trace;
|
Loading…
Reference in New Issue
Block a user