* Re: [PATCH bpf-next 1/2] arm64/ftrace,bpf: Fix partial regs after bpf_prog_run
From: Will Deacon @ 2026-01-07 14:16 UTC (permalink / raw)
To: Jiri Olsa
Cc: Masami Hiramatsu, Steven Rostedt, Mahe Tardy, Peter Zijlstra, bpf,
linux-trace-kernel, linux-arm-kernel, x86, Yonghong Song,
Song Liu, Andrii Nakryiko, Mark Rutland
In-Reply-To: <20260107093256.54616-1-jolsa@kernel.org>
On Wed, Jan 07, 2026 at 10:32:55AM +0100, Jiri Olsa wrote:
> Mahe reported issue with bpf_override_return helper not working when
> executed from kprobe.multi bpf program on arm.
>
> The problem is that on arm we use alternate storage for pt_regs object
> that is passed to bpf_prog_run and if any register is changed (which
> is the case of bpf_override_return) it's not propagated back to actual
> pt_regs object.
>
> Fixing this by introducing and calling ftrace_partial_regs_update function
> to propagate the values of changed registers (ip and stack).
>
> Fixes: b9b55c8912ce ("tracing: Add ftrace_partial_regs() for converting ftrace_regs to pt_regs")
> Reported-by: Mahe Tardy <mahe.tardy@gmail.com>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> ---
> v1 changes:
> - used ftrace_partial_regs_update with comments from Steven
>
> arch/arm64/include/asm/ftrace.h | 24 ++++++++++++++++++++++++
> include/linux/ftrace.h | 3 +++
> kernel/trace/bpf_trace.c | 1 +
> 3 files changed, 28 insertions(+)
>
> diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h
> index 1621c84f44b3..177c7bbf3b84 100644
> --- a/arch/arm64/include/asm/ftrace.h
> +++ b/arch/arm64/include/asm/ftrace.h
> @@ -157,6 +157,30 @@ ftrace_partial_regs(const struct ftrace_regs *fregs, struct pt_regs *regs)
> return regs;
> }
>
> +/*
> + * ftrace_partial_regs_update - update the original ftrace_regs from regs
> + * @fregs: The ftrace_regs to update from @regs
> + * @regs: The partial regs from ftrace_partial_regs() that was updated
> + *
> + * Some architectures have the partial regs living in the ftrace_regs
> + * structure, whereas other architectures need to make a different copy
> + * of the @regs. If a partial @regs is retrieved by ftrace_partial_regs() and
> + * if the code using @regs updates a field (like the instruction pointer or
> + * stack pointer) it may need to propagate that change to the original @fregs
> + * it retrieved the partial @regs from. Use this function to guarantee that
> + * update happens.
> + */
> +static __always_inline void
> +ftrace_partial_regs_update(const struct ftrace_regs *fregs, struct pt_regs *regs)
> +{
> + struct __arch_ftrace_regs *afregs = arch_ftrace_regs(fregs);
> +
> + if (afregs->pc != regs->pc) {
> + afregs->pc = regs->pc;
> + afregs->regs[0] = regs->regs[0];
> + }
> +}
I still don't understand why we need anything new in the arch code for this.
We've selected HAVE_ARCH_FTRACE_REGS and we implement
ftrace_regs_set_instruction_pointer() and ftrace_regs_set_return_value()
so the core code already has everything it needs to make this work
without additional arch support.
Will
^ permalink raw reply
* Re: [PATCH v9 25/30] KVM: arm64: Sync boot clock with the nVHE/pKVM hyp
From: Marc Zyngier @ 2026-01-07 14:23 UTC (permalink / raw)
To: Vincent Donnefort
Cc: rostedt, mhiramat, mathieu.desnoyers, linux-trace-kernel,
oliver.upton, joey.gouly, suzuki.poulose, yuzenghui, kvmarm,
linux-arm-kernel, jstultz, qperret, will, aneesh.kumar,
kernel-team, linux-kernel, Thomas Gleixner, Stephen Boyd,
Christopher S. Hall, Richard Cochran
In-Reply-To: <20251202093623.2337860-26-vdonnefort@google.com>
On Tue, 02 Dec 2025 09:36:18 +0000,
Vincent Donnefort <vdonnefort@google.com> wrote:
>
> Configure the hypervisor tracing clock with the kernel boot clock. For
> tracing purposes, the boot clock is interesting: it doesn't stop on
> suspend. However, it is corrected on a regular basis, which implies the
> need to re-evaluate it every once in a while.
>
> Cc: John Stultz <jstultz@google.com>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Stephen Boyd <sboyd@kernel.org>
> Cc: Christopher S. Hall <christopher.s.hall@intel.com>
> Cc: Richard Cochran <richardcochran@gmail.com>
> Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
>
> diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> index f83650a7aad9..375607c67285 100644
> --- a/arch/arm64/include/asm/kvm_asm.h
> +++ b/arch/arm64/include/asm/kvm_asm.h
> @@ -93,6 +93,7 @@ enum __kvm_host_smccc_func {
> __KVM_HOST_SMCCC_FUNC___tracing_unload,
> __KVM_HOST_SMCCC_FUNC___tracing_enable,
> __KVM_HOST_SMCCC_FUNC___tracing_swap_reader,
> + __KVM_HOST_SMCCC_FUNC___tracing_update_clock,
> };
>
> #define DECLARE_KVM_VHE_SYM(sym) extern char sym[]
> diff --git a/arch/arm64/kvm/hyp/include/nvhe/trace.h b/arch/arm64/kvm/hyp/include/nvhe/trace.h
> index 7da8788ce527..fd641e1b1c23 100644
> --- a/arch/arm64/kvm/hyp/include/nvhe/trace.h
> +++ b/arch/arm64/kvm/hyp/include/nvhe/trace.h
> @@ -11,6 +11,7 @@ int __tracing_load(unsigned long desc_va, size_t desc_size);
> void __tracing_unload(void);
> int __tracing_enable(bool enable);
> int __tracing_swap_reader(unsigned int cpu);
> +void __tracing_update_clock(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc);
> #else
> static inline void *tracing_reserve_entry(unsigned long length) { return NULL; }
> static inline void tracing_commit_entry(void) { }
> @@ -19,5 +20,6 @@ static inline int __tracing_load(unsigned long desc_va, size_t desc_size) { retu
> static inline void __tracing_unload(void) { }
> static inline int __tracing_enable(bool enable) { return -ENODEV; }
> static inline int __tracing_swap_reader(unsigned int cpu) { return -ENODEV; }
> +static inline void __tracing_update_clock(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc) { }
> #endif
> #endif
> diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> index 8b78b29c2069..45b8f70828de 100644
> --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> @@ -613,6 +613,18 @@ static void handle___tracing_swap_reader(struct kvm_cpu_context *host_ctxt)
> cpu_reg(host_ctxt, 1) = __tracing_swap_reader(cpu);
> }
>
> +static void handle___tracing_update_clock(struct kvm_cpu_context *host_ctxt)
> +{
> + DECLARE_REG(u32, mult, host_ctxt, 1);
> + DECLARE_REG(u32, shift, host_ctxt, 2);
> + DECLARE_REG(u64, epoch_ns, host_ctxt, 3);
> + DECLARE_REG(u64, epoch_cyc, host_ctxt, 4);
> +
> + __tracing_update_clock(mult, shift, epoch_ns, epoch_cyc);
> +
> + cpu_reg(host_ctxt, 1) = 0;
What's the purpose of setting X1 to 0? This is a call returning void,
so I don't immediately see the need for this.
> +}
> +
> typedef void (*hcall_t)(struct kvm_cpu_context *);
>
> #define HANDLE_FUNC(x) [__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x
> @@ -658,6 +670,7 @@ static const hcall_t host_hcall[] = {
> HANDLE_FUNC(__tracing_unload),
> HANDLE_FUNC(__tracing_enable),
> HANDLE_FUNC(__tracing_swap_reader),
> + HANDLE_FUNC(__tracing_update_clock),
> };
>
> static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
> diff --git a/arch/arm64/kvm/hyp/nvhe/trace.c b/arch/arm64/kvm/hyp/nvhe/trace.c
> index df9d66fcb3c9..97e9f6c1a52c 100644
> --- a/arch/arm64/kvm/hyp/nvhe/trace.c
> +++ b/arch/arm64/kvm/hyp/nvhe/trace.c
> @@ -271,3 +271,19 @@ int __tracing_swap_reader(unsigned int cpu)
>
> return ret;
> }
> +
> +void __tracing_update_clock(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc)
> +{
> + int cpu;
> +
> + /* After this loop, all CPUs are observing the new bank... */
> + for (cpu = 0; cpu < hyp_nr_cpus; cpu++) {
> + struct simple_rb_per_cpu *simple_rb = per_cpu_ptr(trace_buffer.simple_rbs, cpu);
> +
> + while (READ_ONCE(simple_rb->status) == SIMPLE_RB_WRITING)
> + ;
> + }
> +
> + /* ...we can now override the old one and swap. */
> + trace_clock_update(mult, shift, epoch_ns, epoch_cyc);
> +}
> diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
> index 2866effe28ec..1e5fc27f0e9d 100644
> --- a/arch/arm64/kvm/hyp_trace.c
> +++ b/arch/arm64/kvm/hyp_trace.c
> @@ -4,15 +4,133 @@
> * Author: Vincent Donnefort <vdonnefort@google.com>
> */
>
> +#include <linux/cpumask.h>
> #include <linux/trace_remote.h>
> +#include <linux/tracefs.h>
> #include <linux/simple_ring_buffer.h>
>
> +#include <asm/arch_timer.h>
> #include <asm/kvm_host.h>
> #include <asm/kvm_hyptrace.h>
> #include <asm/kvm_mmu.h>
>
> #include "hyp_trace.h"
>
> +/* Same 10min used by clocksource when width is more than 32-bits */
> +#define CLOCK_MAX_CONVERSION_S 600
> +/*
> + * Time to give for the clock init. Long enough to get a good mult/shift
> + * estimation. Short enough to not delay the tracing start too much.
> + */
> +#define CLOCK_INIT_MS 100
> +/*
> + * Time between clock checks. Must be small enough to catch clock deviation when
> + * it is still tiny.
> + */
> +#define CLOCK_UPDATE_MS 500
If these definitions are common, can't we reuse the existing ones?
Specially given that this isn't EL2 code.
Thanks,
M.
--
Without deviation from the norm, progress is not possible.
^ permalink raw reply
* Re: [PATCH v9 28/30] KVM: arm64: Add hyp_enter/hyp_exit events to nVHE/pKVM hyp
From: Marc Zyngier @ 2026-01-07 14:37 UTC (permalink / raw)
To: Vincent Donnefort
Cc: rostedt, mhiramat, mathieu.desnoyers, linux-trace-kernel,
oliver.upton, joey.gouly, suzuki.poulose, yuzenghui, kvmarm,
linux-arm-kernel, jstultz, qperret, will, aneesh.kumar,
kernel-team, linux-kernel
In-Reply-To: <20251202093623.2337860-29-vdonnefort@google.com>
On Tue, 02 Dec 2025 09:36:21 +0000,
Vincent Donnefort <vdonnefort@google.com> wrote:
>
> The hyp_enter and hyp_exit events are logged by the hypervisor any time
> it is entered and exited.
>
> Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
>
> diff --git a/arch/arm64/include/asm/kvm_hypevents.h b/arch/arm64/include/asm/kvm_hypevents.h
> index d6e033c96c52..268b3cd7a1b2 100644
> --- a/arch/arm64/include/asm/kvm_hypevents.h
> +++ b/arch/arm64/include/asm/kvm_hypevents.h
> @@ -7,4 +7,39 @@
> #include <nvhe/trace.h>
> #endif
>
> +#ifndef __HYP_ENTER_EXIT_REASON
> +#define __HYP_ENTER_EXIT_REASON
> +enum hyp_enter_exit_reason {
> + HYP_REASON_SMC,
> + HYP_REASON_HVC,
> + HYP_REASON_PSCI,
> + HYP_REASON_HOST_ABORT,
> + HYP_REASON_GUEST_EXIT,
> + HYP_REASON_ERET_HOST,
> + HYP_REASON_ERET_GUEST,
> + HYP_REASON_UNKNOWN /* Must be last */
> +};
> +#endif
> +
> +HYP_EVENT(hyp_enter,
> + HE_PROTO(u8 reason),
> + HE_STRUCT(
> + he_field(u8, reason)
> + ),
> + HE_ASSIGN(
> + __entry->reason = reason;
> + ),
> + HE_PRINTK("reason=%s", __hyp_enter_exit_reason_str(__entry->reason))
> +);
> +
> +HYP_EVENT(hyp_exit,
> + HE_PROTO(u8 reason),
> + HE_STRUCT(
> + he_field(u8, reason)
> + ),
> + HE_ASSIGN(
> + __entry->reason = reason;
> + ),
> + HE_PRINTK("reason=%s", __hyp_enter_exit_reason_str(__entry->reason))
> +);
> #endif
> diff --git a/arch/arm64/kvm/hyp/include/nvhe/arm-smccc.h b/arch/arm64/kvm/hyp/include/nvhe/arm-smccc.h
> new file mode 100644
> index 000000000000..7cd0f701f3c9
> --- /dev/null
> +++ b/arch/arm64/kvm/hyp/include/nvhe/arm-smccc.h
> @@ -0,0 +1,23 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#ifndef __ARM64_KVM_HYP_NVHE_ARM_SMCCC_H__
> +#define __ARM64_KVM_HYP_NVHE_ARM_SMCCC_H__
> +
> +#include <asm/kvm_hypevents.h>
> +
> +#include <linux/arm-smccc.h>
> +
> +#define hyp_smccc_1_1_smc(...) \
> + do { \
> + trace_hyp_exit(HYP_REASON_SMC); \
> + arm_smccc_1_1_smc(__VA_ARGS__); \
> + trace_hyp_enter(HYP_REASON_SMC); \
> + } while (0)
> +
> +#define hyp_smccc_1_2_smc(...) \
> + do { \
> + trace_hyp_exit(HYP_REASON_SMC); \
> + arm_smccc_1_2_smc(__VA_ARGS__); \
> + trace_hyp_enter(HYP_REASON_SMC); \
> + } while (0)
> +
> +#endif /* __ARM64_KVM_HYP_NVHE_ARM_SMCCC_H__ */
> diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c
> index 58b7d0c477d7..73d79f9de850 100644
> --- a/arch/arm64/kvm/hyp/nvhe/ffa.c
> +++ b/arch/arm64/kvm/hyp/nvhe/ffa.c
> @@ -26,10 +26,10 @@
> * the duration and are therefore serialised.
> */
>
> -#include <linux/arm-smccc.h>
> #include <linux/arm_ffa.h>
> #include <asm/kvm_pkvm.h>
>
> +#include <nvhe/arm-smccc.h>
> #include <nvhe/ffa.h>
> #include <nvhe/mem_protect.h>
> #include <nvhe/memory.h>
> @@ -147,7 +147,7 @@ static int ffa_map_hyp_buffers(u64 ffa_page_count)
> {
> struct arm_smccc_1_2_regs res;
>
> - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> .a0 = FFA_FN64_RXTX_MAP,
> .a1 = hyp_virt_to_phys(hyp_buffers.tx),
> .a2 = hyp_virt_to_phys(hyp_buffers.rx),
> @@ -161,7 +161,7 @@ static int ffa_unmap_hyp_buffers(void)
> {
> struct arm_smccc_1_2_regs res;
>
> - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> .a0 = FFA_RXTX_UNMAP,
> .a1 = HOST_FFA_ID,
> }, &res);
> @@ -172,7 +172,7 @@ static int ffa_unmap_hyp_buffers(void)
> static void ffa_mem_frag_tx(struct arm_smccc_1_2_regs *res, u32 handle_lo,
> u32 handle_hi, u32 fraglen, u32 endpoint_id)
> {
> - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> .a0 = FFA_MEM_FRAG_TX,
> .a1 = handle_lo,
> .a2 = handle_hi,
> @@ -184,7 +184,7 @@ static void ffa_mem_frag_tx(struct arm_smccc_1_2_regs *res, u32 handle_lo,
> static void ffa_mem_frag_rx(struct arm_smccc_1_2_regs *res, u32 handle_lo,
> u32 handle_hi, u32 fragoff)
> {
> - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> .a0 = FFA_MEM_FRAG_RX,
> .a1 = handle_lo,
> .a2 = handle_hi,
> @@ -196,7 +196,7 @@ static void ffa_mem_frag_rx(struct arm_smccc_1_2_regs *res, u32 handle_lo,
> static void ffa_mem_xfer(struct arm_smccc_1_2_regs *res, u64 func_id, u32 len,
> u32 fraglen)
> {
> - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> .a0 = func_id,
> .a1 = len,
> .a2 = fraglen,
> @@ -206,7 +206,7 @@ static void ffa_mem_xfer(struct arm_smccc_1_2_regs *res, u64 func_id, u32 len,
> static void ffa_mem_reclaim(struct arm_smccc_1_2_regs *res, u32 handle_lo,
> u32 handle_hi, u32 flags)
> {
> - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> .a0 = FFA_MEM_RECLAIM,
> .a1 = handle_lo,
> .a2 = handle_hi,
> @@ -216,7 +216,7 @@ static void ffa_mem_reclaim(struct arm_smccc_1_2_regs *res, u32 handle_lo,
>
> static void ffa_retrieve_req(struct arm_smccc_1_2_regs *res, u32 len)
> {
> - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> .a0 = FFA_FN64_MEM_RETRIEVE_REQ,
> .a1 = len,
> .a2 = len,
> @@ -225,7 +225,7 @@ static void ffa_retrieve_req(struct arm_smccc_1_2_regs *res, u32 len)
>
> static void ffa_rx_release(struct arm_smccc_1_2_regs *res)
> {
> - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> .a0 = FFA_RX_RELEASE,
> }, res);
> }
> @@ -728,7 +728,7 @@ static int hyp_ffa_post_init(void)
> size_t min_rxtx_sz;
> struct arm_smccc_1_2_regs res;
>
> - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs){
> + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs){
> .a0 = FFA_ID_GET,
> }, &res);
> if (res.a0 != FFA_SUCCESS)
> @@ -737,7 +737,7 @@ static int hyp_ffa_post_init(void)
> if (res.a2 != HOST_FFA_ID)
> return -EINVAL;
>
> - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs){
> + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs){
> .a0 = FFA_FEATURES,
> .a1 = FFA_FN64_RXTX_MAP,
> }, &res);
> @@ -788,7 +788,7 @@ static void do_ffa_version(struct arm_smccc_1_2_regs *res,
> * first if TEE supports it.
> */
> if (FFA_MINOR_VERSION(ffa_req_version) < FFA_MINOR_VERSION(hyp_ffa_version)) {
> - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> .a0 = FFA_VERSION,
> .a1 = ffa_req_version,
> }, res);
> @@ -824,7 +824,7 @@ static void do_ffa_part_get(struct arm_smccc_1_2_regs *res,
> goto out_unlock;
> }
>
> - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> .a0 = FFA_PARTITION_INFO_GET,
> .a1 = uuid0,
> .a2 = uuid1,
> @@ -939,7 +939,7 @@ int hyp_ffa_init(void *pages)
> if (kvm_host_psci_config.smccc_version < ARM_SMCCC_VERSION_1_2)
> return 0;
>
> - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) {
> .a0 = FFA_VERSION,
> .a1 = FFA_VERSION_1_2,
> }, &res);
> diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> index 446603cdad7b..ffda4850022f 100644
> --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> @@ -12,6 +12,7 @@
> #include <asm/kvm_emulate.h>
> #include <asm/kvm_host.h>
> #include <asm/kvm_hyp.h>
> +#include <asm/kvm_hypevents.h>
> #include <asm/kvm_mmu.h>
>
> #include <nvhe/ffa.h>
> @@ -728,7 +729,9 @@ static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
>
> static void default_host_smc_handler(struct kvm_cpu_context *host_ctxt)
> {
> + trace_hyp_exit(HYP_REASON_SMC);
> __kvm_hyp_host_forward_smc(host_ctxt);
> + trace_hyp_enter(HYP_REASON_SMC);
> }
>
> static void handle_host_smc(struct kvm_cpu_context *host_ctxt)
> @@ -752,18 +755,24 @@ void handle_trap(struct kvm_cpu_context *host_ctxt)
> {
> u64 esr = read_sysreg_el2(SYS_ESR);
>
> +
> switch (ESR_ELx_EC(esr)) {
> case ESR_ELx_EC_HVC64:
> + trace_hyp_enter(HYP_REASON_HVC);
> handle_host_hcall(host_ctxt);
> break;
> case ESR_ELx_EC_SMC64:
> + trace_hyp_enter(HYP_REASON_SMC);
> handle_host_smc(host_ctxt);
> break;
> case ESR_ELx_EC_IABT_LOW:
> case ESR_ELx_EC_DABT_LOW:
> + trace_hyp_enter(HYP_REASON_HOST_ABORT);
> handle_host_mem_abort(host_ctxt);
> break;
> default:
> BUG();
> }
> +
> + trace_hyp_exit(HYP_REASON_ERET_HOST);
> }
> diff --git a/arch/arm64/kvm/hyp/nvhe/psci-relay.c b/arch/arm64/kvm/hyp/nvhe/psci-relay.c
> index c3e196fb8b18..58658e09c372 100644
> --- a/arch/arm64/kvm/hyp/nvhe/psci-relay.c
> +++ b/arch/arm64/kvm/hyp/nvhe/psci-relay.c
> @@ -6,11 +6,12 @@
>
> #include <asm/kvm_asm.h>
> #include <asm/kvm_hyp.h>
> +#include <asm/kvm_hypevents.h>
> #include <asm/kvm_mmu.h>
> -#include <linux/arm-smccc.h>
> #include <linux/kvm_host.h>
> #include <uapi/linux/psci.h>
>
> +#include <nvhe/arm-smccc.h>
> #include <nvhe/memory.h>
> #include <nvhe/trap_handler.h>
>
> @@ -65,7 +66,7 @@ static unsigned long psci_call(unsigned long fn, unsigned long arg0,
> {
> struct arm_smccc_res res;
>
> - arm_smccc_1_1_smc(fn, arg0, arg1, arg2, &res);
> + hyp_smccc_1_1_smc(fn, arg0, arg1, arg2, &res);
> return res.a0;
> }
>
> @@ -205,6 +206,7 @@ asmlinkage void __noreturn __kvm_host_psci_cpu_entry(bool is_cpu_on)
> struct psci_boot_args *boot_args;
> struct kvm_cpu_context *host_ctxt;
>
> + trace_hyp_enter(HYP_REASON_PSCI);
> host_ctxt = host_data_ptr(host_ctxt);
>
> if (is_cpu_on)
> @@ -221,6 +223,7 @@ asmlinkage void __noreturn __kvm_host_psci_cpu_entry(bool is_cpu_on)
> write_sysreg_el1(INIT_SCTLR_EL1_MMU_OFF, SYS_SCTLR);
> write_sysreg(INIT_PSTATE_EL1, SPSR_EL2);
>
> + trace_hyp_exit(HYP_REASON_PSCI);
> __host_enter(host_ctxt);
> }
>
> diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
> index d3b9ec8a7c28..3dc2bbab4bfc 100644
> --- a/arch/arm64/kvm/hyp/nvhe/switch.c
> +++ b/arch/arm64/kvm/hyp/nvhe/switch.c
> @@ -7,7 +7,6 @@
> #include <hyp/switch.h>
> #include <hyp/sysreg-sr.h>
>
> -#include <linux/arm-smccc.h>
> #include <linux/kvm_host.h>
> #include <linux/types.h>
> #include <linux/jump_label.h>
> @@ -21,6 +20,7 @@
> #include <asm/kvm_asm.h>
> #include <asm/kvm_emulate.h>
> #include <asm/kvm_hyp.h>
> +#include <asm/kvm_hypevents.h>
> #include <asm/kvm_mmu.h>
> #include <asm/fpsimd.h>
> #include <asm/debug-monitors.h>
> @@ -308,10 +308,13 @@ int __kvm_vcpu_run(struct kvm_vcpu *vcpu)
> __debug_switch_to_guest(vcpu);
>
> do {
> + trace_hyp_exit(HYP_REASON_ERET_GUEST);
> +
> /* Jump in the fire! */
> exit_code = __guest_enter(vcpu);
>
> /* And we're baaack! */
> + trace_hyp_enter(HYP_REASON_GUEST_EXIT);
nit: seeing these two events back to back makes me think that one of
them is misnamed. Either the first should be GUEST_ENTER, or the
second should be GUEST_EXCEPT... Preference for the former.
> } while (fixup_guest_exit(vcpu, &exit_code));
>
> __sysreg_save_state_nvhe(guest_ctxt);
> diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
> index 0144cd26703e..1ad6a55ba95c 100644
> --- a/arch/arm64/kvm/hyp_trace.c
> +++ b/arch/arm64/kvm/hyp_trace.c
> @@ -364,8 +364,26 @@ static struct trace_remote_callbacks trace_remote_callbacks = {
> .enable_event = hyp_trace_enable_event,
> };
>
> +static const char *__hyp_enter_exit_reason_str(u8 reason);
> +
> #include <asm/kvm_define_hypevents.h>
>
> +static const char *__hyp_enter_exit_reason_str(u8 reason)
That's one ugly hack... :-(
> +{
> + static const char strs[][12] = {
> + "smc",
> + "hvc",
> + "psci",
> + "host_abort",
> + "guest_exit",
> + "eret_host",
> + "eret_guest",
> + "unknown",
> + };
> +
> + return strs[min(reason, HYP_REASON_UNKNOWN)];
> +}
> +
> static void __init hyp_trace_init_events(void)
> {
> struct hyp_event_id *hyp_event_id = __hyp_event_ids_start;
Thanks,
M.
--
Without deviation from the norm, progress is not possible.
^ permalink raw reply
* [PATCH 0/2] tracing: Remove backup instance after read all
From: Masami Hiramatsu (Google) @ 2026-01-07 14:45 UTC (permalink / raw)
To: Steven Rostedt
Cc: Masami Hiramatsu, Mathieu Desnoyers, linux-kernel,
linux-trace-kernel
Hi,
This series of patches improves backup instances of the persistent
ring buffer. 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 | 155 ++++++++++++++++++++++++++++++++++++-------
kernel/trace/trace.h | 12 +++
kernel/trace/trace_events.c | 14 +++-
3 files changed, 153 insertions(+), 28 deletions(-)
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply
* [PATCH 1/2] tracing: Make the backup instance readonly
From: Masami Hiramatsu (Google) @ 2026-01-07 14:45 UTC (permalink / raw)
To: Steven Rostedt
Cc: Masami Hiramatsu, Mathieu Desnoyers, linux-kernel,
linux-trace-kernel
In-Reply-To: <176779714767.4193242.1978666866487010024.stgit@mhiramat.tok.corp.google.com>
From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Since there is no reason to reuse the backup instance, make it
readonly. Note that only backup instances are readonly, because
other trace instances will be empty unless it is writable.
Only backup instances have copy entries from the original.
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
kernel/trace/trace.c | 91 ++++++++++++++++++++++++++++++++-----------
kernel/trace/trace.h | 6 +++
kernel/trace/trace_events.c | 14 +++++--
3 files changed, 84 insertions(+), 27 deletions(-)
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 38f7a7a55c23..725930f5980e 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4888,6 +4888,9 @@ static int tracing_open(struct inode *inode, struct file *file)
int cpu = tracing_get_cpu(inode);
struct array_buffer *trace_buf = &tr->array_buffer;
+ if (trace_array_is_readonly(tr))
+ return -EPERM;
+
#ifdef CONFIG_TRACER_MAX_TRACE
if (tr->current_trace->print_max)
trace_buf = &tr->max_buffer;
@@ -6077,6 +6080,9 @@ static int __tracing_resize_ring_buffer(struct trace_array *tr,
ssize_t tracing_resize_ring_buffer(struct trace_array *tr,
unsigned long size, int cpu_id)
{
+ if (trace_array_is_readonly(tr))
+ return -EPERM;
+
guard(mutex)(&trace_types_lock);
if (cpu_id != RING_BUFFER_ALL_CPUS) {
@@ -6298,6 +6304,10 @@ int tracing_set_tracer(struct trace_array *tr, const char *buf)
guard(mutex)(&trace_types_lock);
+ /* Not allowed to set new tracer on readonly instance. */
+ if (trace_array_is_readonly(tr))
+ return -EPERM;
+
update_last_data(tr);
if (!tr->ring_buffer_expanded) {
@@ -6413,6 +6423,9 @@ tracing_set_trace_write(struct file *filp, const char __user *ubuf,
size_t ret;
int err;
+ if (trace_array_is_readonly(tr))
+ return -EPERM;
+
ret = cnt;
if (cnt > MAX_TRACER_SIZE)
@@ -6478,6 +6491,9 @@ tracing_thresh_write(struct file *filp, const char __user *ubuf,
struct trace_array *tr = filp->private_data;
int ret;
+ if (trace_array_is_readonly(tr))
+ return -EPERM;
+
guard(mutex)(&trace_types_lock);
ret = tracing_nsecs_write(&tracing_thresh, ubuf, cnt, ppos);
if (ret < 0)
@@ -7047,6 +7063,9 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
unsigned long val;
int ret;
+ if (trace_array_is_readonly(tr))
+ return -EPERM;
+
ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
if (ret)
return ret;
@@ -7595,6 +7614,9 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
unsigned long ip;
char *buf;
+ if (trace_array_is_readonly(tr))
+ return -EPERM;
+
if (tracing_disabled)
return -EINVAL;
@@ -7675,6 +7697,9 @@ tracing_mark_raw_write(struct file *filp, const char __user *ubuf,
ssize_t written = -ENODEV;
char *buf;
+ if (trace_array_is_readonly(tr))
+ return -EPERM;
+
if (tracing_disabled)
return -EINVAL;
@@ -7757,6 +7782,9 @@ int tracing_set_clock(struct trace_array *tr, const char *clockstr)
{
int i;
+ if (trace_array_is_readonly(tr))
+ return -EPERM;
+
for (i = 0; i < ARRAY_SIZE(trace_clocks); i++) {
if (strcmp(trace_clocks[i].name, clockstr) == 0)
break;
@@ -9353,12 +9381,16 @@ static void
tracing_init_tracefs_percpu(struct trace_array *tr, long cpu)
{
struct dentry *d_percpu = tracing_dentry_percpu(tr, cpu);
+ umode_t writable_mode = TRACE_MODE_WRITE;
struct dentry *d_cpu;
char cpu_dir[30]; /* 30 characters should be more than enough */
if (!d_percpu)
return;
+ if (trace_array_is_readonly(tr))
+ writable_mode = TRACE_MODE_READ;
+
snprintf(cpu_dir, 30, "cpu%ld", cpu);
d_cpu = tracefs_create_dir(cpu_dir, d_percpu);
if (!d_cpu) {
@@ -9371,7 +9403,7 @@ tracing_init_tracefs_percpu(struct trace_array *tr, long cpu)
tr, cpu, &tracing_pipe_fops);
/* per cpu trace */
- trace_create_cpu_file("trace", TRACE_MODE_WRITE, d_cpu,
+ trace_create_cpu_file("trace", writable_mode, d_cpu,
tr, cpu, &tracing_fops);
trace_create_cpu_file("trace_pipe_raw", TRACE_MODE_READ, d_cpu,
@@ -9811,6 +9843,9 @@ rb_simple_write(struct file *filp, const char __user *ubuf,
unsigned long val;
int ret;
+ if (trace_array_is_readonly(tr))
+ return -EPERM;
+
ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
if (ret)
return ret;
@@ -10597,47 +10632,54 @@ static __init void create_trace_instances(struct dentry *d_tracer)
static void
init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer)
{
+ umode_t writable_mode = TRACE_MODE_WRITE;
+ bool readonly = trace_array_is_readonly(tr);
int cpu;
+ if (readonly)
+ writable_mode = TRACE_MODE_READ;
+
trace_create_file("available_tracers", TRACE_MODE_READ, d_tracer,
tr, &show_traces_fops);
- trace_create_file("current_tracer", TRACE_MODE_WRITE, d_tracer,
+ trace_create_file("current_tracer", writable_mode, d_tracer,
tr, &set_tracer_fops);
- trace_create_file("tracing_cpumask", TRACE_MODE_WRITE, d_tracer,
+ trace_create_file("tracing_cpumask", writable_mode, d_tracer,
tr, &tracing_cpumask_fops);
- trace_create_file("trace_options", TRACE_MODE_WRITE, d_tracer,
+ trace_create_file("trace_options", writable_mode, d_tracer,
tr, &tracing_iter_fops);
- trace_create_file("trace", TRACE_MODE_WRITE, d_tracer,
+ trace_create_file("trace", writable_mode, d_tracer,
tr, &tracing_fops);
trace_create_file("trace_pipe", TRACE_MODE_READ, d_tracer,
tr, &tracing_pipe_fops);
- trace_create_file("buffer_size_kb", TRACE_MODE_WRITE, d_tracer,
+ trace_create_file("buffer_size_kb", writable_mode, d_tracer,
tr, &tracing_entries_fops);
trace_create_file("buffer_total_size_kb", TRACE_MODE_READ, d_tracer,
tr, &tracing_total_entries_fops);
- trace_create_file("free_buffer", 0200, d_tracer,
- tr, &tracing_free_buffer_fops);
+ if (!readonly) {
+ trace_create_file("free_buffer", 0200, d_tracer,
+ tr, &tracing_free_buffer_fops);
- trace_create_file("trace_marker", 0220, d_tracer,
- tr, &tracing_mark_fops);
+ trace_create_file("trace_marker", 0220, d_tracer,
+ tr, &tracing_mark_fops);
- tr->trace_marker_file = __find_event_file(tr, "ftrace", "print");
+ tr->trace_marker_file = __find_event_file(tr, "ftrace", "print");
- trace_create_file("trace_marker_raw", 0220, d_tracer,
- tr, &tracing_mark_raw_fops);
+ trace_create_file("trace_marker_raw", 0220, d_tracer,
+ tr, &tracing_mark_raw_fops);
+ }
- trace_create_file("trace_clock", TRACE_MODE_WRITE, d_tracer, tr,
+ trace_create_file("trace_clock", writable_mode, d_tracer, tr,
&trace_clock_fops);
- trace_create_file("tracing_on", TRACE_MODE_WRITE, d_tracer,
+ trace_create_file("tracing_on", writable_mode, d_tracer,
tr, &rb_simple_fops);
trace_create_file("timestamp_mode", TRACE_MODE_READ, d_tracer, tr,
@@ -10645,22 +10687,23 @@ init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer)
tr->buffer_percent = 50;
- trace_create_file("buffer_percent", TRACE_MODE_WRITE, d_tracer,
+ trace_create_file("buffer_percent", writable_mode, d_tracer,
tr, &buffer_percent_fops);
- trace_create_file("buffer_subbuf_size_kb", TRACE_MODE_WRITE, d_tracer,
+ trace_create_file("buffer_subbuf_size_kb", writable_mode, d_tracer,
tr, &buffer_subbuf_size_fops);
- trace_create_file("syscall_user_buf_size", TRACE_MODE_WRITE, d_tracer,
+ trace_create_file("syscall_user_buf_size", writable_mode, d_tracer,
tr, &tracing_syscall_buf_fops);
create_trace_options_dir(tr);
#ifdef CONFIG_TRACER_MAX_TRACE
- trace_create_maxlat_file(tr, d_tracer);
+ if (!readonly)
+ trace_create_maxlat_file(tr, d_tracer);
#endif
- if (ftrace_create_function_files(tr, d_tracer))
+ if (!readonly && ftrace_create_function_files(tr, d_tracer))
MEM_FAIL(1, "Could not allocate function filter files");
if (tr->range_addr_start) {
@@ -10673,13 +10716,15 @@ init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer)
#endif
}
- trace_create_file("error_log", TRACE_MODE_WRITE, d_tracer,
- tr, &tracing_err_log_fops);
+ if (!readonly)
+ trace_create_file("error_log", TRACE_MODE_WRITE, d_tracer,
+ tr, &tracing_err_log_fops);
for_each_tracing_cpu(cpu)
tracing_init_tracefs_percpu(tr, cpu);
- ftrace_init_tracefs(tr, d_tracer);
+ if (!readonly)
+ ftrace_init_tracefs(tr, d_tracer);
}
#ifdef CONFIG_TRACEFS_AUTOMOUNT_DEPRECATED
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index b6d42fe06115..bc0eeb2d1d07 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -483,6 +483,12 @@ extern bool trace_clock_in_ns(struct trace_array *tr);
extern unsigned long trace_adjust_address(struct trace_array *tr, unsigned long addr);
+static inline bool trace_array_is_readonly(struct trace_array *tr)
+{
+ /* backup instance is read only. */
+ return tr->flags & TRACE_ARRAY_FL_VMALLOC;
+}
+
/*
* The global tracer (top) should be the first trace array added,
* but we check the flag anyway.
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 9b07ad9eb284..f20f717f1ea9 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1379,6 +1379,9 @@ static int __ftrace_set_clr_event(struct trace_array *tr, const char *match,
{
int ret;
+ if (trace_array_is_readonly(tr))
+ return -EPERM;
+
mutex_lock(&event_mutex);
ret = __ftrace_set_clr_event_nolock(tr, match, sub, event, set, mod);
mutex_unlock(&event_mutex);
@@ -4376,6 +4379,7 @@ static int events_callback(const char *name, umode_t *mode, void **data,
static int
create_event_toplevel_files(struct dentry *parent, struct trace_array *tr)
{
+ umode_t writable_mode = TRACE_MODE_WRITE;
struct eventfs_inode *e_events;
struct dentry *entry;
int nr_entries;
@@ -4393,9 +4397,11 @@ create_event_toplevel_files(struct dentry *parent, struct trace_array *tr)
.callback = events_callback,
},
};
+ if (trace_array_is_readonly(tr))
+ writable_mode = TRACE_MODE_READ;
- entry = trace_create_file("set_event", TRACE_MODE_WRITE, parent,
- tr, &ftrace_set_event_fops);
+ entry = trace_create_file("set_event", writable_mode, parent,
+ tr, &ftrace_set_event_fops);
if (!entry)
return -ENOMEM;
@@ -4410,11 +4416,11 @@ create_event_toplevel_files(struct dentry *parent, struct trace_array *tr)
/* There are not as crucial, just warn if they are not created */
- trace_create_file("set_event_pid", TRACE_MODE_WRITE, parent,
+ trace_create_file("set_event_pid", writable_mode, parent,
tr, &ftrace_set_event_pid_fops);
trace_create_file("set_event_notrace_pid",
- TRACE_MODE_WRITE, parent, tr,
+ writable_mode, parent, tr,
&ftrace_set_event_notrace_pid_fops);
tr->event_dir = e_events;
^ permalink raw reply related
* [PATCH 2/2] tracing: Add autoremove feature to the backup instance
From: Masami Hiramatsu (Google) @ 2026-01-07 14:46 UTC (permalink / raw)
To: Steven Rostedt
Cc: Masami Hiramatsu, Mathieu Desnoyers, linux-kernel,
linux-trace-kernel
In-Reply-To: <176779714767.4193242.1978666866487010024.stgit@mhiramat.tok.corp.google.com>
From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Since the backup instance is readonly, after reading all data
via pipe, no data is left on the instance. Thus it can be
removed safely after closing all files.
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
kernel/trace/trace.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++-
kernel/trace/trace.h | 6 +++++
2 files changed, 69 insertions(+), 1 deletion(-)
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 725930f5980e..dfd4385603e6 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -590,6 +590,55 @@ void trace_set_ring_buffer_expanded(struct trace_array *tr)
tr->ring_buffer_expanded = true;
}
+static int __remove_instance(struct trace_array *tr);
+
+static void trace_array_autoremove(struct work_struct *work)
+{
+ struct trace_array *tr = container_of(work, struct trace_array, autoremove_work);
+
+ guard(mutex)(&event_mutex);
+ guard(mutex)(&trace_types_lock);
+
+ /*
+ * This can be fail if someone gets @tr before starting this
+ * function, but in that case, this will be kicked again when
+ * putting it. So we don't care the result.
+ */
+ __remove_instance(tr);
+}
+
+static struct workqueue_struct *autoremove_wq;
+
+static void trace_array_init_autoremove(struct trace_array *tr)
+{
+ INIT_WORK(&tr->autoremove_work, trace_array_autoremove);
+}
+
+static void trace_array_kick_autoremove(struct trace_array *tr)
+{
+ if (!work_pending(&tr->autoremove_work) && autoremove_wq)
+ queue_work(autoremove_wq, &tr->autoremove_work);
+}
+
+static void trace_array_cancel_autoremove(struct trace_array *tr)
+{
+ if (work_pending(&tr->autoremove_work))
+ cancel_work(&tr->autoremove_work);
+}
+
+__init static int trace_array_init_autoremove_wq(void)
+{
+ autoremove_wq = alloc_workqueue("tr_autoremove_wq",
+ WQ_UNBOUND | WQ_HIGHPRI, 0);
+ if (!autoremove_wq) {
+ pr_err("Unable to allocate tr_autoremove_wq\n");
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+late_initcall_sync(trace_array_init_autoremove_wq);
+
LIST_HEAD(ftrace_trace_arrays);
int trace_array_get(struct trace_array *this_tr)
@@ -598,7 +647,7 @@ int trace_array_get(struct trace_array *this_tr)
guard(mutex)(&trace_types_lock);
list_for_each_entry(tr, &ftrace_trace_arrays, list) {
- if (tr == this_tr) {
+ if (tr == this_tr && !tr->free_on_close) {
tr->ref++;
return 0;
}
@@ -611,6 +660,12 @@ static void __trace_array_put(struct trace_array *this_tr)
{
WARN_ON(!this_tr->ref);
this_tr->ref--;
+ /*
+ * When free_on_close is set, prepare removing the array
+ * when the last reference is released.
+ */
+ if (this_tr->ref == 1 && this_tr->free_on_close)
+ trace_array_kick_autoremove(this_tr);
}
/**
@@ -6212,6 +6267,10 @@ static void update_last_data(struct trace_array *tr)
/* Only if the buffer has previous boot data clear and update it. */
tr->flags &= ~TRACE_ARRAY_FL_LAST_BOOT;
+ /* If this is a backup instance, mark it for autoremove. */
+ if (tr->flags & TRACE_ARRAY_FL_VMALLOC)
+ tr->free_on_close = true;
+
/* Reset the module list and reload them */
if (tr->scratch) {
struct trace_scratch *tscratch = tr->scratch;
@@ -10392,6 +10451,8 @@ trace_array_create_systems(const char *name, const char *systems,
if (ftrace_allocate_ftrace_ops(tr) < 0)
goto out_free_tr;
+ trace_array_init_autoremove(tr);
+
ftrace_init_trace_array(tr);
init_trace_flags_index(tr);
@@ -10540,6 +10601,7 @@ static int __remove_instance(struct trace_array *tr)
if (update_marker_trace(tr, 0))
synchronize_rcu();
+ trace_array_cancel_autoremove(tr);
tracing_set_nop(tr);
clear_ftrace_function_probes(tr);
event_trace_del_tracer(tr);
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index bc0eeb2d1d07..a8088a106d67 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -446,6 +446,12 @@ struct trace_array {
* we do not waste memory on systems that are not using tracing.
*/
bool ring_buffer_expanded;
+ /*
+ * If the ring buffer is a read only backup instance, it will be
+ * removed after dumping all data via pipe, because no readable data.
+ */
+ bool free_on_close;
+ struct work_struct autoremove_work;
};
enum {
^ permalink raw reply related
* Re: [PATCH] fgraph: Make sure fregs is non-null when accessing
From: Steven Rostedt @ 2026-01-07 15:16 UTC (permalink / raw)
To: sunliming
Cc: mhiramat, mark.rutland, mathieu.desnoyers, linux-kernel,
linux-trace-kernel, sunliming, kernel test robot, Dan Carpenter
In-Reply-To: <20260107015125.27659-1-sunliming@linux.dev>
On Wed, 7 Jan 2026 09:51:25 +0800
sunliming@linux.dev wrote:
> From: sunliming <sunliming@kylinos.cn>
>
> Fix below smatch warnings:
> kernel/trace/fgraph.c:834 __ftrace_return_to_handler() error: we previously
> assumed 'fregs' could be null (see line 830)
>
NACK!
> Reported-by: kernel test robot <lkp@intel.com>
> Reported-by: Dan Carpenter <error27@gmail.com>
> Closes: https://lore.kernel.org/r/202512131657.JQUt5fXQ-lkp@intel.com/
Really? Did you not read this thread you are "closing"?
-- Steve
> Signed-off-by: sunliming <sunliming@kylinos.cn>
> ---
> kernel/trace/fgraph.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/trace/fgraph.c b/kernel/trace/fgraph.c
> index cc48d16be43e..0f50a55032c5 100644
> --- a/kernel/trace/fgraph.c
> +++ b/kernel/trace/fgraph.c
> @@ -837,7 +837,8 @@ __ftrace_return_to_handler(struct ftrace_regs *fregs, unsigned long frame_pointe
> goto out;
>
> #ifdef CONFIG_FUNCTION_GRAPH_RETVAL
> - trace.retval = ftrace_regs_get_return_value(fregs);
> + if (fregs)
> + trace.retval = ftrace_regs_get_return_value(fregs);
> #endif
>
> bitmap = get_bitmap_bits(current, offset);
^ permalink raw reply
* Re: [PATCH v2] selftests/tracing: Fix test_multiple_writes stall
From: Steven Rostedt @ 2026-01-07 15:18 UTC (permalink / raw)
To: Fushuai Wang
Cc: linux-kernel, linux-kselftest, linux-trace-kernel,
mathieu.desnoyers, mhiramat, shuah, wangfushuai, Shuah Khan
In-Reply-To: <20260107034914.22315-1-fushuai.wang@linux.dev>
On Wed, 7 Jan 2026 11:49:14 +0800
Fushuai Wang <fushuai.wang@linux.dev> wrote:
> > When /sys/kernel/tracing/buffer_size_kb is less than 12KB,
> > the test_multiple_writes test will stall and wait for more
> > input due to insufficient buffer space.
> >
> > Check current buffer_size_kb value before the test. If it is
> > less than 12KB, it temporarily increase the buffer to 12KB,
> > and restore the original value after the tests are completed.
> >
> > Fixes: 37f46601383a ("selftests/tracing: Add basic test for trace_marker_raw file")
> > Suggested-by: Steven Rostedt <rostedt@goodmis.org>
> > Signed-off-by: Fushuai Wang <wangfushuai@baidu.com>
>
> Gentle ping.
>
Acked-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Shuah,
Care to take this through your tree? It does fix a bug so it likely should
go into the rc releases and not wait for the next merge window.
Thanks,
-- Steve
^ permalink raw reply
* Re: [PATCH v9 29/30] KVM: arm64: Add selftest event support to nVHE/pKVM hyp
From: Marc Zyngier @ 2026-01-07 15:40 UTC (permalink / raw)
To: Vincent Donnefort
Cc: rostedt, mhiramat, mathieu.desnoyers, linux-trace-kernel,
oliver.upton, joey.gouly, suzuki.poulose, yuzenghui, kvmarm,
linux-arm-kernel, jstultz, qperret, will, aneesh.kumar,
kernel-team, linux-kernel
In-Reply-To: <20251202093623.2337860-30-vdonnefort@google.com>
On Tue, 02 Dec 2025 09:36:22 +0000,
Vincent Donnefort <vdonnefort@google.com> wrote:
>
> Add a selftest event that can be triggered from a `write_event` tracefs
> file. This intends to be used by trace remote selftests.
>
> Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
>
> diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> index 37c015b54ff6..e2de7ad64938 100644
> --- a/arch/arm64/include/asm/kvm_asm.h
> +++ b/arch/arm64/include/asm/kvm_asm.h
> @@ -96,6 +96,7 @@ enum __kvm_host_smccc_func {
> __KVM_HOST_SMCCC_FUNC___tracing_update_clock,
> __KVM_HOST_SMCCC_FUNC___tracing_reset,
> __KVM_HOST_SMCCC_FUNC___tracing_enable_event,
> + __KVM_HOST_SMCCC_FUNC___tracing_write_event,
> };
>
> #define DECLARE_KVM_VHE_SYM(sym) extern char sym[]
> diff --git a/arch/arm64/include/asm/kvm_hypevents.h b/arch/arm64/include/asm/kvm_hypevents.h
> index 268b3cd7a1b2..c276fd28e0bf 100644
> --- a/arch/arm64/include/asm/kvm_hypevents.h
> +++ b/arch/arm64/include/asm/kvm_hypevents.h
> @@ -42,4 +42,15 @@ HYP_EVENT(hyp_exit,
> ),
> HE_PRINTK("reason=%s", __hyp_enter_exit_reason_str(__entry->reason))
> );
> +
> +HYP_EVENT(selftest,
> + HE_PROTO(u64 id),
> + HE_STRUCT(
> + he_field(u64, id)
> + ),
> + HE_ASSIGN(
> + __entry->id = id;
> + ),
> + RE_PRINTK("id=%llu", __entry->id)
Not strictly related to this patch, but I find that the trace itself
lacks context. For example:
[001] 323.847422: hyp_enter reason=hvc
[001] 323.847423: hyp_exit reason=eret_host
[001] 323.847688: hyp_enter reason=hvc
[001] 323.847688: hyp_exit reason=eret_host
[001] 323.847706: hyp_enter reason=hvc
[001] 323.847707: hyp_exit reason=eret_host
[001] 323.847722: hyp_enter reason=hvc
[001] 323.847723: hyp_exit reason=eret_host
That's all fine as long as I'm dealing with a single guest, or even
with a single vcpu. Trying to trace multiple guests, or even multiple
vcpus makes the whole thing completely unusable, because I have no
idea what I'm looking at.
To make this useful, having some context provided by the host really
is required.
Thanks,
M.
--
Without deviation from the norm, progress is not possible.
^ permalink raw reply
* Re: [BUG/RFC 1/2] arm64/ftrace,bpf: Fix partial regs after bpf_prog_run
From: Steven Rostedt @ 2026-01-07 15:53 UTC (permalink / raw)
To: Jiri Olsa
Cc: Masami Hiramatsu (Google), Will Deacon, Peter Zijlstra, bpf,
linux-trace-kernel, linux-arm-kernel, x86, Yonghong Song,
Song Liu, Andrii Nakryiko, Mark Rutland, Mahe Tardy
In-Reply-To: <aV4X5Yx07LomQji4@krava>
On Wed, 7 Jan 2026 09:23:01 +0100
Jiri Olsa <olsajiri@gmail.com> wrote:
> ---
> diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h
> index 1621c84f44b3..177c7bbf3b84 100644
> --- a/arch/arm64/include/asm/ftrace.h
> +++ b/arch/arm64/include/asm/ftrace.h
> @@ -157,6 +157,30 @@ ftrace_partial_regs(const struct ftrace_regs *fregs, struct pt_regs *regs)
> return regs;
> }
>
> +/*
> + * ftrace_partial_regs_update - update the original ftrace_regs from regs
> + * @fregs: The ftrace_regs to update from @regs
> + * @regs: The partial regs from ftrace_partial_regs() that was updated
> + *
> + * Some architectures have the partial regs living in the ftrace_regs
> + * structure, whereas other architectures need to make a different copy
> + * of the @regs. If a partial @regs is retrieved by ftrace_partial_regs() and
> + * if the code using @regs updates a field (like the instruction pointer or
> + * stack pointer) it may need to propagate that change to the original @fregs
> + * it retrieved the partial @regs from. Use this function to guarantee that
> + * update happens.
> + */
I think the kernel doc should go into the generic function, and this just say:
/* See description of this function in the generic header */
or something similar.
Also, should probably have the description in the general function say:
*
* For architectures that need to update @fregs from @regs, this function needs to be
* defined.
Or something similar.
-- Steve
> +static __always_inline void
> +ftrace_partial_regs_update(const struct ftrace_regs *fregs, struct pt_regs *regs)
> +{
> + struct __arch_ftrace_regs *afregs = arch_ftrace_regs(fregs);
> +
> + if (afregs->pc != regs->pc) {
> + afregs->pc = regs->pc;
> + afregs->regs[0] = regs->regs[0];
> + }
> +}
> +
> #define arch_ftrace_fill_perf_regs(fregs, _regs) do { \
> (_regs)->pc = arch_ftrace_regs(fregs)->pc; \
> (_regs)->regs[29] = arch_ftrace_regs(fregs)->fp; \
> diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
> index 770f0dc993cc..ae22559b4099 100644
> --- a/include/linux/ftrace.h
> +++ b/include/linux/ftrace.h
> @@ -213,6 +213,9 @@ ftrace_partial_regs(struct ftrace_regs *fregs, struct pt_regs *regs)
> return regs;
> }
>
> +static __always_inline void
> +ftrace_partial_regs_update(struct ftrace_regs *fregs, struct pt_regs *regs) { }
> +
> #endif /* !CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS || CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS */
>
> #ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS
> diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
> index 6e076485bf70..3a17f79b20c2 100644
> --- a/kernel/trace/bpf_trace.c
> +++ b/kernel/trace/bpf_trace.c
> @@ -2564,6 +2564,7 @@ kprobe_multi_link_prog_run(struct bpf_kprobe_multi_link *link,
> old_run_ctx = bpf_set_run_ctx(&run_ctx.session_ctx.run_ctx);
> err = bpf_prog_run(link->link.prog, regs);
> bpf_reset_run_ctx(old_run_ctx);
> + ftrace_partial_regs_update(fregs, bpf_kprobe_multi_pt_regs_ptr());
> rcu_read_unlock();
>
> out:
> --
^ permalink raw reply
* Re: [PATCH v9 00/30] Tracefs support for pKVM
From: Marc Zyngier @ 2026-01-07 16:00 UTC (permalink / raw)
To: Vincent Donnefort
Cc: rostedt, mhiramat, mathieu.desnoyers, linux-trace-kernel,
oliver.upton, joey.gouly, suzuki.poulose, yuzenghui, kvmarm,
linux-arm-kernel, jstultz, qperret, will, aneesh.kumar,
kernel-team, linux-kernel
In-Reply-To: <20251202093623.2337860-1-vdonnefort@google.com>
On Tue, 02 Dec 2025 09:35:53 +0000,
Vincent Donnefort <vdonnefort@google.com> wrote:
>
> The growing set of features supported by the hypervisor in protected
> mode necessitates debugging and profiling tools. Tracefs is the
> ideal candidate for this task:
[...]
I quite like the shape of this now, at least for the KVM side of
things. The comments I have can be addressed down the line, and don't
impact the actual functionality.
Now, the first 18 patches definitely need acks from the relevant
maintainers before I can queue this.
Steven?
M.
--
Without deviation from the norm, progress is not possible.
^ permalink raw reply
* Re: [PATCH bpf-next 1/2] arm64/ftrace,bpf: Fix partial regs after bpf_prog_run
From: Steven Rostedt @ 2026-01-07 16:03 UTC (permalink / raw)
To: Jiri Olsa
Cc: Masami Hiramatsu, Will Deacon, Mahe Tardy, Peter Zijlstra, bpf,
linux-trace-kernel, linux-arm-kernel, x86, Yonghong Song,
Song Liu, Andrii Nakryiko, Mark Rutland
In-Reply-To: <20260107093256.54616-1-jolsa@kernel.org>
On Wed, 7 Jan 2026 10:32:55 +0100
Jiri Olsa <jolsa@kernel.org> wrote:
> diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h
> index 1621c84f44b3..177c7bbf3b84 100644
> --- a/arch/arm64/include/asm/ftrace.h
> +++ b/arch/arm64/include/asm/ftrace.h
> @@ -157,6 +157,30 @@ ftrace_partial_regs(const struct ftrace_regs *fregs, struct pt_regs *regs)
> return regs;
> }
>
See my reply in the other email thread:
https://lore.kernel.org/all/20260107105316.2b70a308@gandalf.local.home/
-- Steve
> +/*
> + * ftrace_partial_regs_update - update the original ftrace_regs from regs
> + * @fregs: The ftrace_regs to update from @regs
> + * @regs: The partial regs from ftrace_partial_regs() that was updated
> + *
> + * Some architectures have the partial regs living in the ftrace_regs
> + * structure, whereas other architectures need to make a different copy
> + * of the @regs. If a partial @regs is retrieved by ftrace_partial_regs() and
> + * if the code using @regs updates a field (like the instruction pointer or
> + * stack pointer) it may need to propagate that change to the original @fregs
> + * it retrieved the partial @regs from. Use this function to guarantee that
> + * update happens.
> + */
> +static __always_inline void
> +ftrace_partial_regs_update(const struct ftrace_regs *fregs, struct pt_regs *regs)
> +{
> + struct __arch_ftrace_regs *afregs = arch_ftrace_regs(fregs);
> +
> + if (afregs->pc != regs->pc) {
> + afregs->pc = regs->pc;
> + afregs->regs[0] = regs->regs[0];
> + }
> +}
^ permalink raw reply
* Re: [PATCH bpf-next 1/2] arm64/ftrace,bpf: Fix partial regs after bpf_prog_run
From: Steven Rostedt @ 2026-01-07 16:08 UTC (permalink / raw)
To: Will Deacon
Cc: Jiri Olsa, Masami Hiramatsu, Mahe Tardy, Peter Zijlstra, bpf,
linux-trace-kernel, linux-arm-kernel, x86, Yonghong Song,
Song Liu, Andrii Nakryiko, Mark Rutland
In-Reply-To: <aV5qpZwxgVRu2Q8w@willie-the-truck>
On Wed, 7 Jan 2026 14:16:05 +0000
Will Deacon <will@kernel.org> wrote:
> I still don't understand why we need anything new in the arch code for this.
>
> We've selected HAVE_ARCH_FTRACE_REGS and we implement
> ftrace_regs_set_instruction_pointer() and ftrace_regs_set_return_value()
> so the core code already has everything it needs to make this work
> without additional arch support.
I believe the issue is that the BPF code takes a pt_regs and does the
update directly with that, and not the ftrace_regs.
I'm guessing this is due to BPF programs modifying the pt_regs directly,
and BPF programs do not yet understand ftrace_regs?
Because arm64 requires making a copy of pt_regs as the ftrace_regs has a
different layout, and the ftrace_regs is what does the changes, if the
pt_regs passed to the BPF program modifies the values it needs a way to
propagate that back to the ftrace_regs.
-- Steve
^ permalink raw reply
* Re: [PATCH v2] arm64: Disable branch profiling for all arm64 code
From: Steven Rostedt @ 2026-01-07 16:10 UTC (permalink / raw)
To: Breno Leitao
Cc: Mark Rutland, Catalin Marinas, Will Deacon, Laura Abbott,
linux-arm-kernel, linux-kernel, linux-trace-kernel,
Masami Hiramatsu, kernel-team, puranjay, stable
In-Reply-To: <frfmxk2ifpf5shcws42q3eeykb3xyflxocbic6junm7mzvmqik@vktwefe2zmw7>
On Wed, 7 Jan 2026 01:37:36 -0800
Breno Leitao <leitao@debian.org> wrote:
> I am starting to look and remove some of these likely/unlikely hint that
> are 100% wrong on some very sane configuration (arm64 baremetal hosts
> running a webserver).
>
> So far, these are the fixes I have in flight now.
>
> * https://lore.kernel.org/all/20260105-dcache-v1-1-f0d904b4a7c2@debian.org/
> * https://lore.kernel.org/all/20260106-blk_unlikely-v1-1-90fb556a6776@debian.org/
> * https://lore.kernel.org/all/20260105-annotated_idle-v1-1-10ddf0771b58@debian.org/
Nice. Thanks for letting me know. I'm happy to see that someone besides me
is using the annotated branch profiler to fix real issues in the kernel.
I would love it if more people did the same. Anyway, please advertise this
as much as possible. If it shows that it is helping to fix real bugs, maybe
it would attract the interest of more developers, and more importantly, it
keeps the tooling in place. I'm constantly fighting to keep it from being
removed from the kernel :-p
-- Steve
^ permalink raw reply
* Re: [PATCH] ring-buffer: Use a housekeeping CPU to wake up waiters
From: Steven Rostedt @ 2026-01-07 16:17 UTC (permalink / raw)
To: Petr Tesarik
Cc: Masami Hiramatsu, Mathieu Desnoyers, Sebastian Andrzej Siewior,
Clark Williams, linux-kernel, linux-trace-kernel, linux-rt-devel
In-Reply-To: <20260107105137.4cf9a67e@mordecai>
On Wed, 7 Jan 2026 10:51:37 +0100
Petr Tesarik <ptesarik@suse.com> wrote:
> Erm. It's actually good I had a look. :-(
>
> A helpful comment in irq_work_queue_on() explains that "arch remote IPI
> send/receive backend aren't NMI safe". That's something I wasn't aware
> of, and I'm afraid it's the end of story. The comment is followed by a
> WARN_ON_ONCE(in_nmi()), and I can easily trigger it with "perf top"
> while nmi:nmi_handler is traced.
>
> Please, remove the patch again. I'm sorry.
Or we simply change it to:
static inline void
rb_irq_work_queue(struct rb_irq_work *irq_work)
{
int cpu;
/* irq_work_queue_on() is not allowed in NMI context */
if (in_nmi()) {
irq_work_queue(&irq_work->work, cpu);
return;
}
cpu = housekeeping_any_cpu(HK_TYPE_KERNEL_NOISE);
/*
* If CPU isolation is not active, cpu is always the current
* CPU, and the following is equivallent to irq_work_queue().
*/
irq_work_queue_on(&irq_work->work, cpu);
}
-- Steve
^ permalink raw reply
* Re: [PATCH] ring-buffer: Use a housekeeping CPU to wake up waiters
From: Steven Rostedt @ 2026-01-07 16:19 UTC (permalink / raw)
To: Petr Tesarik
Cc: Masami Hiramatsu, Mathieu Desnoyers, Sebastian Andrzej Siewior,
Clark Williams, linux-kernel, linux-trace-kernel, linux-rt-devel
In-Reply-To: <20260107111709.0d115cd8@gandalf.local.home>
On Wed, 7 Jan 2026 11:17:09 -0500
Steven Rostedt <rostedt@goodmis.org> wrote:
> Or we simply change it to:
>
> static inline void
Actually, the above should be noinline, as it's in a slower path, and
should not be adding logic into the cache of the fast path.
-- Steve
> rb_irq_work_queue(struct rb_irq_work *irq_work)
> {
> int cpu;
>
> /* irq_work_queue_on() is not allowed in NMI context */
> if (in_nmi()) {
> irq_work_queue(&irq_work->work, cpu);
> return;
> }
>
> cpu = housekeeping_any_cpu(HK_TYPE_KERNEL_NOISE);
> /*
> * If CPU isolation is not active, cpu is always the current
> * CPU, and the following is equivallent to irq_work_queue().
> */
> irq_work_queue_on(&irq_work->work, cpu);
> }
^ permalink raw reply
* Re: [PATCH v2 15/18] rtla: Make stop_tracing variable volatile
From: Steven Rostedt @ 2026-01-07 16:31 UTC (permalink / raw)
To: Wander Lairson Costa
Cc: Tomas Glozar, Crystal Wood, Ivan Pravdin, Costa Shulyupin,
John Kacur, Tiezhu Yang,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
In-Reply-To: <CAAq0SUmW7mUP0iiHMJevR+T6BKHJiFoU4M8sCVjJSRMFnT2J_w@mail.gmail.com>
On Wed, 7 Jan 2026 10:24:43 -0300
Wander Lairson Costa <wander@redhat.com> wrote:
> > In the kernel, this is handled via the READ_ONCE() macro. Perhaps rtla
> > should implement that too.
> >
>
> I considered that, but, in this use case, I saw no point because it
> didn't bring any advantage and volatile was simpler.
> Furthermore, as Crystal pointed out, using volatile for variables
> shared with signals is a pretty standard practice.
OK, I've just been broken in by Linus yelling at anyone defining any
variable as volatile ;-) I now avoid it at all costs, and only have the
locations that need to be volatile defined that way.
-- Steve
^ permalink raw reply
* Re: [PATCH v9 28/30] KVM: arm64: Add hyp_enter/hyp_exit events to nVHE/pKVM hyp
From: Steven Rostedt @ 2026-01-07 16:36 UTC (permalink / raw)
To: Marc Zyngier
Cc: Vincent Donnefort, mhiramat, mathieu.desnoyers,
linux-trace-kernel, oliver.upton, joey.gouly, suzuki.poulose,
yuzenghui, kvmarm, linux-arm-kernel, jstultz, qperret, will,
aneesh.kumar, kernel-team, linux-kernel
In-Reply-To: <86a4ypmqts.wl-maz@kernel.org>
On Wed, 07 Jan 2026 14:37:35 +0000
Marc Zyngier <maz@kernel.org> wrote:
> > +static const char *__hyp_enter_exit_reason_str(u8 reason);
> > +
> > #include <asm/kvm_define_hypevents.h>
> >
> > +static const char *__hyp_enter_exit_reason_str(u8 reason)
>
> That's one ugly hack... :-(
This is basically the way TRACE_EVENT()s are created.
Have a look at include/trace/trace_event.h and include/trace/define_event.h
But I have to warn you. You may need to wear ugly hack proof glasses ;-)
-- Steve
^ permalink raw reply
* Re: [PATCH 1/2] tracing: Make the backup instance readonly
From: Steven Rostedt @ 2026-01-07 16:41 UTC (permalink / raw)
To: Masami Hiramatsu (Google)
Cc: Mathieu Desnoyers, linux-kernel, linux-trace-kernel
In-Reply-To: <176779715937.4193242.8486149802702305279.stgit@mhiramat.tok.corp.google.com>
On Wed, 7 Jan 2026 23:45:59 +0900
"Masami Hiramatsu (Google)" <mhiramat@kernel.org> wrote:
> From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
>
> Since there is no reason to reuse the backup instance, make it
> readonly. Note that only backup instances are readonly, because
> other trace instances will be empty unless it is writable.
> Only backup instances have copy entries from the original.
>
> Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
> ---
> kernel/trace/trace.c | 91 ++++++++++++++++++++++++++++++++-----------
> kernel/trace/trace.h | 6 +++
> kernel/trace/trace_events.c | 14 +++++--
> 3 files changed, 84 insertions(+), 27 deletions(-)
>
> diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
> index 38f7a7a55c23..725930f5980e 100644
> --- a/kernel/trace/trace.c
> +++ b/kernel/trace/trace.c
> @@ -4888,6 +4888,9 @@ static int tracing_open(struct inode *inode, struct file *file)
> int cpu = tracing_get_cpu(inode);
> struct array_buffer *trace_buf = &tr->array_buffer;
>
> + if (trace_array_is_readonly(tr))
> + return -EPERM;
So this fails if someone opens a file in RDONLY mode?
Why?
> +
> #ifdef CONFIG_TRACER_MAX_TRACE
> if (tr->current_trace->print_max)
> trace_buf = &tr->max_buffer;
> @@ -6077,6 +6080,9 @@ static int __tracing_resize_ring_buffer(struct trace_array *tr,
> ssize_t tracing_resize_ring_buffer(struct trace_array *tr,
> unsigned long size, int cpu_id)
> {
> + if (trace_array_is_readonly(tr))
> + return -EPERM;
In fact, I don't think we need any of these.
> +
> guard(mutex)(&trace_types_lock);
>
> if (cpu_id != RING_BUFFER_ALL_CPUS) {
> @@ -9353,12 +9381,16 @@ static void
> tracing_init_tracefs_percpu(struct trace_array *tr, long cpu)
> {
> struct dentry *d_percpu = tracing_dentry_percpu(tr, cpu);
> + umode_t writable_mode = TRACE_MODE_WRITE;
> struct dentry *d_cpu;
> char cpu_dir[30]; /* 30 characters should be more than enough */
>
> if (!d_percpu)
> return;
>
> + if (trace_array_is_readonly(tr))
> + writable_mode = TRACE_MODE_READ;
This is more like what we should do with all the files in a read-only
instance. Just make all files not allow writes.
We may need to make sure they can't be changed to write as well. But that
will require a change to tracefs (and eventfs).
-- Steve
> +
> snprintf(cpu_dir, 30, "cpu%ld", cpu);
> d_cpu = tracefs_create_dir(cpu_dir, d_percpu);
> if (!d_cpu) {
> @@ -9371,7 +9403,7 @@ tracing_init_tracefs_percpu(struct trace_array *tr, long cpu)
> tr, cpu, &tracing_pipe_fops);
>
> /* per cpu trace */
> - trace_create_cpu_file("trace", TRACE_MODE_WRITE, d_cpu,
> + trace_create_cpu_file("trace", writable_mode, d_cpu,
> tr, cpu, &tracing_fops);
>
> trace_create_cpu_file("trace_pipe_raw", TRACE_MODE_READ, d_cpu,
^ permalink raw reply
* Re: [PATCH bpf-next 1/2] arm64/ftrace,bpf: Fix partial regs after bpf_prog_run
From: Will Deacon @ 2026-01-07 16:52 UTC (permalink / raw)
To: Steven Rostedt
Cc: Jiri Olsa, Masami Hiramatsu, Mahe Tardy, Peter Zijlstra, bpf,
linux-trace-kernel, linux-arm-kernel, x86, Yonghong Song,
Song Liu, Andrii Nakryiko, Mark Rutland
In-Reply-To: <20260107110814.1dfc9ec0@gandalf.local.home>
On Wed, Jan 07, 2026 at 11:08:14AM -0500, Steven Rostedt wrote:
> On Wed, 7 Jan 2026 14:16:05 +0000
> Will Deacon <will@kernel.org> wrote:
>
> > I still don't understand why we need anything new in the arch code for this.
> >
> > We've selected HAVE_ARCH_FTRACE_REGS and we implement
> > ftrace_regs_set_instruction_pointer() and ftrace_regs_set_return_value()
> > so the core code already has everything it needs to make this work
> > without additional arch support.
>
> I believe the issue is that the BPF code takes a pt_regs and does the
> update directly with that, and not the ftrace_regs.
>
> I'm guessing this is due to BPF programs modifying the pt_regs directly,
> and BPF programs do not yet understand ftrace_regs?
>
> Because arm64 requires making a copy of pt_regs as the ftrace_regs has a
> different layout, and the ftrace_regs is what does the changes, if the
> pt_regs passed to the BPF program modifies the values it needs a way to
> propagate that back to the ftrace_regs.
Sure, but isn't that exactly what selecting HAVE_ARCH_FTRACE_REGS says,
and so any other architecture (i.e. riscv) using a separate structure
will run into the same problem?
In other words, add the helper to the core code along the lines of the
diff below (purely untested, just to illustrate what I'm trying to get
at).
Will
--->8
diff --git a/include/linux/ftrace_regs.h b/include/linux/ftrace_regs.h
index 15627ceea9bc..3ebd8cdac7c6 100644
--- a/include/linux/ftrace_regs.h
+++ b/include/linux/ftrace_regs.h
@@ -33,6 +33,15 @@ struct ftrace_regs;
#define ftrace_regs_get_frame_pointer(fregs) \
frame_pointer(&arch_ftrace_regs(fregs)->regs)
+#else
+
+static __always_inline void
+ftrace_partial_regs_update(const struct ftrace_regs *fregs, struct pt_regs *regs)
+{
+ ftrace_regs_set_instruction_pointer(fregs, instruction_pointer(regs));
+ ftrace_regs_set_return_value(fregs, regs_return_value(regs));
+}
+
#endif /* HAVE_ARCH_FTRACE_REGS */
/* This can be overridden by the architectures */
^ permalink raw reply related
* Re: [PATCH v9 00/30] Tracefs support for pKVM
From: Steven Rostedt @ 2026-01-07 16:59 UTC (permalink / raw)
To: Marc Zyngier
Cc: Vincent Donnefort, mhiramat, mathieu.desnoyers,
linux-trace-kernel, oliver.upton, joey.gouly, suzuki.poulose,
yuzenghui, kvmarm, linux-arm-kernel, jstultz, qperret, will,
aneesh.kumar, kernel-team, linux-kernel
In-Reply-To: <867bttmmzw.wl-maz@kernel.org>
On Wed, 07 Jan 2026 16:00:19 +0000
Marc Zyngier <maz@kernel.org> wrote:
> I quite like the shape of this now, at least for the KVM side of
> things. The comments I have can be addressed down the line, and don't
> impact the actual functionality.
>
> Now, the first 18 patches definitely need acks from the relevant
> maintainers before I can queue this.
>
> Steven?
Yeah, it's on my todo list to finish my review.
Thanks,
-- Steve
^ permalink raw reply
* Re: [PATCH bpf-next 1/2] arm64/ftrace,bpf: Fix partial regs after bpf_prog_run
From: Steven Rostedt @ 2026-01-07 17:14 UTC (permalink / raw)
To: Will Deacon
Cc: Jiri Olsa, Masami Hiramatsu, Mahe Tardy, Peter Zijlstra, bpf,
linux-trace-kernel, linux-arm-kernel, x86, Yonghong Song,
Song Liu, Andrii Nakryiko, Mark Rutland
In-Reply-To: <aV6PZKx9g_hCz4ZW@willie-the-truck>
On Wed, 7 Jan 2026 16:52:52 +0000
Will Deacon <will@kernel.org> wrote:
> diff --git a/include/linux/ftrace_regs.h b/include/linux/ftrace_regs.h
> index 15627ceea9bc..3ebd8cdac7c6 100644
> --- a/include/linux/ftrace_regs.h
> +++ b/include/linux/ftrace_regs.h
> @@ -33,6 +33,15 @@ struct ftrace_regs;
> #define ftrace_regs_get_frame_pointer(fregs) \
> frame_pointer(&arch_ftrace_regs(fregs)->regs)
>
> +#else
> +
> +static __always_inline void
> +ftrace_partial_regs_update(const struct ftrace_regs *fregs, struct pt_regs *regs)
> +{
> + ftrace_regs_set_instruction_pointer(fregs, instruction_pointer(regs));
> + ftrace_regs_set_return_value(fregs, regs_return_value(regs));
> +}
> +
> #endif /* HAVE_ARCH_FTRACE_REGS */
>
> /* This can be overridden by the architectures */
Hmm, maybe that would work. Of course you forgot to add the helper for the
!HAVE_ARCH_FTRACE_REGS case ;-)
-- Steve
^ permalink raw reply
* [GIT PULL] RTLA changes for v6.20
From: Tomas Glozar @ 2026-01-07 17:17 UTC (permalink / raw)
To: Steven Rostedt
Cc: Costa Shulyupin, Crystal Wood, Wander Lairson Costa, LKML,
Linux Trace Kernel, Tomas Glozar
Steven,
please pull the following changes for RTLA (more info in tag description).
Thanks,
Tomas
The following changes since commit 9ace4753a5202b02191d54e9fdf7f9e3d02b85eb:
Linux 6.19-rc4 (2026-01-04 14:41:55 -0800)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/tglozar/linux.git tags/rtla-v6.20
for you to fetch changes up to fb8b8183208d8efe824e8d2c73fb1ab5ad1191fd:
rtla: Fix parse_cpu_set() return value documentation (2026-01-07 15:57:56 +0100)
----------------------------------------------------------------
RTLA patches for v6.20
- Remove unused function declarations
Some functions were removed in recent code consolidation 6.18, but
their prototypes were not removed from headers. Remove them.
- Set stop threshold after enabling instances
Prefer recording samples without stopping on them on the start of
tracing to stopping on samples that are never recorded. This fixes
flakiness of some RTLA tests and unifies behavior of sample collection
between tracefs mode and BPF mode.
- Consolidate usage help message implementation
RTLA tools (osnoise-top, osnoise-hist, timerlat-top, timerlat-hist)
each implement usage help individually. Move common logic between
them into a new function to reduce code duplication.
- Add BPF actions feature
Add option --bpf-action to attach a BPF program (passed as filename of
its ELF representation) to be executed via BPF tail call at latency
threshold.
- Consolidate command line option parsing
Each RTLA tool implements the parsing of command line options
individually. Now that we have a common structure for parameters,
unify the parsing of those options common among all four tools into
one function.
- Deduplicage cgroup common code
Two functions in utils.c, setting cgroup for comm and setting cgroup
for pid, duplicate code for constructing the cgroup path. Extract it
to a new helper function.
- String and error handling fixes and cleanups
There were several instances of unsafe string and error handling that
could cause invalid memory access; fix them. Also, remove a few unused
headers, update .gitignore, and deduplicate code.
The tag was tested (make && make check) as well as pre-tested on top of
next-20260107. There are no known conflicts.
Signed-off-by: Tomas Glozar <tglozar@redhat.com>
----------------------------------------------------------------
Costa Shulyupin (11):
tools/rtla: Remove unused function declarations
tools/rtla: Add common_usage()
tools/rtla: Add common_parse_options()
tools/rtla: Consolidate -c/--cpus option parsing
tools/rtla: Consolidate -C/--cgroup option parsing
tools/rtla: Consolidate -D/--debug option parsing
tools/rtla: Consolidate -d/--duration option parsing
tools/rtla: Consolidate -e/--event option parsing
tools/rtla: Consolidate -P/--priority option parsing
tools/rtla: Consolidate -H/--house-keeping option parsing
tools/rtla: Deduplicate cgroup path opening code
Crystal Wood (1):
rtla: Set stop threshold after all instances are enabled
Tomas Glozar (7):
rtla/timerlat: Support tail call from BPF program
rtla/timerlat: Add --bpf-action option
rtla/timerlat: Add example for BPF action program
rtla/tests: Test BPF action program
rtla/tests: Run Test::Harness in verbose mode
Documentation/rtla: Rename sample/ to example/
Documentation/rtla: Document --bpf-action option
Wander Lairson Costa (10):
rtla: Introduce for_each_action() helper
rtla: Replace atoi() with a robust strtoi()
rtla: Use standard exit codes for result enum
rtla: Remove redundant memset after calloc
rtla: Remove unused headers
rtla: Fix NULL pointer dereference in actions_parse
rtla: Add generated output files to gitignore
rtla: Make stop_tracing variable volatile
rtla: Ensure null termination after read operations in utils.c
rtla: Fix parse_cpu_set() return value documentation
.../tools/rtla/common_timerlat_options.txt | 20 ++-
tools/tracing/rtla/.gitignore | 4 +
tools/tracing/rtla/Makefile | 19 ++-
tools/tracing/rtla/example/timerlat_bpf_action.c | 16 +++
.../rtla/{sample => example}/timerlat_load.py | 0
tools/tracing/rtla/src/actions.c | 17 +--
tools/tracing/rtla/src/actions.h | 5 +
tools/tracing/rtla/src/common.c | 140 ++++++++++++++++++++-
tools/tracing/rtla/src/common.h | 10 +-
tools/tracing/rtla/src/osnoise.c | 17 +--
tools/tracing/rtla/src/osnoise.h | 8 --
tools/tracing/rtla/src/osnoise_hist.c | 76 ++---------
tools/tracing/rtla/src/osnoise_top.c | 90 +++----------
tools/tracing/rtla/src/timerlat.bpf.c | 25 +++-
tools/tracing/rtla/src/timerlat.c | 29 ++---
tools/tracing/rtla/src/timerlat.h | 2 +-
tools/tracing/rtla/src/timerlat_bpf.c | 66 ++++++++++
tools/tracing/rtla/src/timerlat_bpf.h | 7 +-
tools/tracing/rtla/src/timerlat_hist.c | 80 +++---------
tools/tracing/rtla/src/timerlat_top.c | 80 +++---------
tools/tracing/rtla/src/trace.c | 1 -
tools/tracing/rtla/src/utils.c | 110 ++++++++++------
tools/tracing/rtla/src/utils.h | 10 +-
tools/tracing/rtla/tests/bpf/bpf_action_map.c | 25 ++++
tools/tracing/rtla/tests/engine.sh | 1 -
tools/tracing/rtla/tests/timerlat.t | 15 +++
26 files changed, 513 insertions(+), 360 deletions(-)
create mode 100644 tools/tracing/rtla/example/timerlat_bpf_action.c
rename tools/tracing/rtla/{sample => example}/timerlat_load.py (100%)
create mode 100644 tools/tracing/rtla/tests/bpf/bpf_action_map.c
^ permalink raw reply
* Re: [PATCH v3 1/2] mm: vmscan: add cgroup IDs to vmscan tracepoints
From: Shakeel Butt @ 2026-01-07 18:14 UTC (permalink / raw)
To: Thomas Ballasi; +Cc: akpm, linux-mm, linux-trace-kernel, mhiramat, rostedt
In-Reply-To: <62ia3v3oduyt2srkaneccoei7cwimifwduarteyn2ugpmmbw3p@rivcqvcksgpt>
On Mon, Jan 05, 2026 at 02:46:39PM -0800, Shakeel Butt wrote:
[...]
>
> Orthogonally I am cleaning up memcg id usage and after that cleanup,
> mem_cgroup_id() would be preferred way to get the ID. No need to do
> anything now as I will cleanup this usage later as well.
The series has been landed in mm-new. Please use mem_cgroup_id() instead
of cgroup_id(memcg->css.cgroup).
^ permalink raw reply
* Re: [PATCH v3 1/2] mm: vmscan: add cgroup IDs to vmscan tracepoints
From: Andrew Morton @ 2026-01-07 18:32 UTC (permalink / raw)
To: Shakeel Butt
Cc: Thomas Ballasi, linux-mm, linux-trace-kernel, mhiramat, rostedt
In-Reply-To: <ovqxo2mmjiuymqk36t2xydcyzvtppcqsog62yx3qtwsknbkgzq@3phadh5gfyjd>
On Wed, 7 Jan 2026 10:14:53 -0800 Shakeel Butt <shakeel.butt@linux.dev> wrote:
> On Mon, Jan 05, 2026 at 02:46:39PM -0800, Shakeel Butt wrote:
> [...]
> >
> > Orthogonally I am cleaning up memcg id usage and after that cleanup,
> > mem_cgroup_id() would be preferred way to get the ID. No need to do
> > anything now as I will cleanup this usage later as well.
>
> The series has been landed in mm-new. Please use mem_cgroup_id() instead
> of cgroup_id(memcg->css.cgroup).
fyi, I removed this series yesterday due to a CONFIG_MEMCG=n build failure.
^ permalink raw reply
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