Linux Trace Kernel
 help / color / mirror / Atom feed
* [PATCH v10 24/30] KVM: arm64: Add trace remote for the nVHE/pKVM hyp
From: Vincent Donnefort @ 2026-01-26 10:44 UTC (permalink / raw)
  To: rostedt, mhiramat, mathieu.desnoyers, linux-trace-kernel, maz,
	oliver.upton, joey.gouly, suzuki.poulose, yuzenghui
  Cc: kvmarm, linux-arm-kernel, jstultz, qperret, will, aneesh.kumar,
	kernel-team, linux-kernel, Vincent Donnefort
In-Reply-To: <20260126104419.1649811-1-vdonnefort@google.com>

In both protected and nVHE mode, the hypervisor is capable of writing
events into tracefs compatible ring-buffers. Create a trace remote so
the kernel can read those buffers.

This currently doesn't provide any event support which will come later.

Signed-off-by: Vincent Donnefort <vdonnefort@google.com>

diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index c7f50492f2cf..aad0228f24db 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -76,6 +76,7 @@ if NVHE_EL2_DEBUG
 config NVHE_EL2_TRACING
 	bool
 	depends on TRACING
+	select TRACE_REMOTE
 	default y
 
 config PKVM_DISABLE_STAGE2_ON_PANIC
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 3ebc0570345c..59612d2f277c 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -30,6 +30,8 @@ kvm-$(CONFIG_HW_PERF_EVENTS)  += pmu-emul.o pmu.o
 kvm-$(CONFIG_ARM64_PTR_AUTH)  += pauth.o
 kvm-$(CONFIG_PTDUMP_STAGE2_DEBUGFS) += ptdump.o
 
+kvm-$(CONFIG_NVHE_EL2_TRACING) += hyp_trace.o
+
 always-y := hyp_constants.h hyp-constants.s
 
 define rule_gen_hyp_constants
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index be1fd6c5f74c..f7f222ecaf88 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -24,6 +24,7 @@
 
 #define CREATE_TRACE_POINTS
 #include "trace_arm.h"
+#include "hyp_trace.h"
 
 #include <linux/uaccess.h>
 #include <asm/ptrace.h>
@@ -2361,6 +2362,10 @@ static int __init init_subsystems(void)
 
 	kvm_register_perf_callbacks(NULL);
 
+	err = kvm_hyp_trace_init();
+	if (err)
+		kvm_err("Failed to initialize Hyp tracing\n");
+
 out:
 	if (err)
 		hyp_cpu_pm_exit();
diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
new file mode 100644
index 000000000000..2866effe28ec
--- /dev/null
+++ b/arch/arm64/kvm/hyp_trace.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 Google LLC
+ * Author: Vincent Donnefort <vdonnefort@google.com>
+ */
+
+#include <linux/trace_remote.h>
+#include <linux/simple_ring_buffer.h>
+
+#include <asm/kvm_host.h>
+#include <asm/kvm_hyptrace.h>
+#include <asm/kvm_mmu.h>
+
+#include "hyp_trace.h"
+
+/* Access to this struct within the trace_remote_callbacks are protected by the trace_remote lock */
+static struct hyp_trace_buffer {
+	struct hyp_trace_desc	*desc;
+	size_t			desc_size;
+} trace_buffer;
+
+static int __map_hyp(void *start, size_t size)
+{
+	if (is_protected_kvm_enabled())
+		return 0;
+
+	return create_hyp_mappings(start, start + size, PAGE_HYP);
+}
+
+static int __share_page(unsigned long va)
+{
+	return kvm_share_hyp((void *)va, (void *)va + 1);
+}
+
+static void __unshare_page(unsigned long va)
+{
+	kvm_unshare_hyp((void *)va, (void *)va + 1);
+}
+
+static int hyp_trace_buffer_alloc_bpages_backing(struct hyp_trace_buffer *trace_buffer, size_t size)
+{
+	int nr_bpages = (PAGE_ALIGN(size) / PAGE_SIZE) + 1;
+	size_t backing_size;
+	void *start;
+
+	backing_size = PAGE_ALIGN(sizeof(struct simple_buffer_page) * nr_bpages *
+				  num_possible_cpus());
+
+	start = alloc_pages_exact(backing_size, GFP_KERNEL_ACCOUNT);
+	if (!start)
+		return -ENOMEM;
+
+	trace_buffer->desc->bpages_backing_start = (unsigned long)start;
+	trace_buffer->desc->bpages_backing_size = backing_size;
+
+	return __map_hyp(start, backing_size);
+}
+
+static void hyp_trace_buffer_free_bpages_backing(struct hyp_trace_buffer *trace_buffer)
+{
+	free_pages_exact((void *)trace_buffer->desc->bpages_backing_start,
+			 trace_buffer->desc->bpages_backing_size);
+}
+
+static void hyp_trace_buffer_unshare_hyp(struct hyp_trace_buffer *trace_buffer, int last_cpu)
+{
+	struct ring_buffer_desc *rb_desc;
+	int cpu, p;
+
+	for_each_ring_buffer_desc(rb_desc, cpu, &trace_buffer->desc->trace_buffer_desc) {
+		if (cpu > last_cpu)
+			break;
+
+		__share_page(rb_desc->meta_va);
+		for (p = 0; p < rb_desc->nr_page_va; p++)
+			__unshare_page(rb_desc->page_va[p]);
+	}
+}
+
+static int hyp_trace_buffer_share_hyp(struct hyp_trace_buffer *trace_buffer)
+{
+	struct ring_buffer_desc *rb_desc;
+	int cpu, p, ret = 0;
+
+	for_each_ring_buffer_desc(rb_desc, cpu, &trace_buffer->desc->trace_buffer_desc) {
+		ret = __share_page(rb_desc->meta_va);
+		if (ret)
+			break;
+
+		for (p = 0; p < rb_desc->nr_page_va; p++) {
+			ret = __share_page(rb_desc->page_va[p]);
+			if (ret)
+				break;
+		}
+
+		if (ret) {
+			for (p--; p >= 0; p--)
+				__unshare_page(rb_desc->page_va[p]);
+			break;
+		}
+	}
+
+	if (ret)
+		hyp_trace_buffer_unshare_hyp(trace_buffer, cpu--);
+
+	return ret;
+}
+
+static struct trace_buffer_desc *hyp_trace_load(unsigned long size, void *priv)
+{
+	struct hyp_trace_buffer *trace_buffer = priv;
+	struct hyp_trace_desc *desc;
+	size_t desc_size;
+	int ret;
+
+	if (WARN_ON(trace_buffer->desc))
+		return ERR_PTR(-EINVAL);
+
+	desc_size = trace_buffer_desc_size(size, num_possible_cpus());
+	if (desc_size == SIZE_MAX)
+		return ERR_PTR(-E2BIG);
+
+	desc_size = PAGE_ALIGN(desc_size);
+	desc = (struct hyp_trace_desc *)alloc_pages_exact(desc_size, GFP_KERNEL);
+	if (!desc)
+		return ERR_PTR(-ENOMEM);
+
+	ret = __map_hyp(desc, desc_size);
+	if (ret)
+		goto err_free_desc;
+
+	trace_buffer->desc = desc;
+
+	ret = hyp_trace_buffer_alloc_bpages_backing(trace_buffer, size);
+	if (ret)
+		goto err_free_desc;
+
+	ret = trace_remote_alloc_buffer(&desc->trace_buffer_desc, desc_size, size,
+					cpu_possible_mask);
+	if (ret)
+		goto err_free_backing;
+
+	ret = hyp_trace_buffer_share_hyp(trace_buffer);
+	if (ret)
+		goto err_free_buffer;
+
+	ret = kvm_call_hyp_nvhe(__tracing_load, (unsigned long)desc, desc_size);
+	if (ret)
+		goto err_unload_pages;
+
+	return &desc->trace_buffer_desc;
+
+err_unload_pages:
+	hyp_trace_buffer_unshare_hyp(trace_buffer, INT_MAX);
+
+err_free_buffer:
+	trace_remote_free_buffer(&desc->trace_buffer_desc);
+
+err_free_backing:
+	hyp_trace_buffer_free_bpages_backing(trace_buffer);
+
+err_free_desc:
+	free_pages_exact(desc, desc_size);
+	trace_buffer->desc = NULL;
+
+	return ERR_PTR(ret);
+}
+
+static void hyp_trace_unload(struct trace_buffer_desc *desc, void *priv)
+{
+	struct hyp_trace_buffer *trace_buffer = priv;
+
+	if (WARN_ON(desc != &trace_buffer->desc->trace_buffer_desc))
+		return;
+
+	kvm_call_hyp_nvhe(__tracing_unload);
+	hyp_trace_buffer_unshare_hyp(trace_buffer, INT_MAX);
+	trace_remote_free_buffer(desc);
+	hyp_trace_buffer_free_bpages_backing(trace_buffer);
+	free_pages_exact(trace_buffer->desc, trace_buffer->desc_size);
+	trace_buffer->desc = NULL;
+}
+
+static int hyp_trace_enable_tracing(bool enable, void *priv)
+{
+	return kvm_call_hyp_nvhe(__tracing_enable, enable);
+}
+
+static int hyp_trace_swap_reader_page(unsigned int cpu, void *priv)
+{
+	return kvm_call_hyp_nvhe(__tracing_swap_reader, cpu);
+}
+
+static int hyp_trace_reset(unsigned int cpu, void *priv)
+{
+	return 0;
+}
+
+static int hyp_trace_enable_event(unsigned short id, bool enable, void *priv)
+{
+	return 0;
+}
+
+static struct trace_remote_callbacks trace_remote_callbacks = {
+	.load_trace_buffer	= hyp_trace_load,
+	.unload_trace_buffer	= hyp_trace_unload,
+	.enable_tracing		= hyp_trace_enable_tracing,
+	.swap_reader_page	= hyp_trace_swap_reader_page,
+	.reset			= hyp_trace_reset,
+	.enable_event		= hyp_trace_enable_event,
+};
+
+int __init kvm_hyp_trace_init(void)
+{
+	if (is_kernel_in_hyp_mode())
+		return 0;
+
+	return trace_remote_register("hypervisor", &trace_remote_callbacks, &trace_buffer, NULL, 0);
+}
diff --git a/arch/arm64/kvm/hyp_trace.h b/arch/arm64/kvm/hyp_trace.h
new file mode 100644
index 000000000000..c991b1ec65f1
--- /dev/null
+++ b/arch/arm64/kvm/hyp_trace.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ARM64_KVM_HYP_TRACE_H__
+#define __ARM64_KVM_HYP_TRACE_H__
+
+#ifdef CONFIG_NVHE_EL2_TRACING
+int kvm_hyp_trace_init(void);
+#else
+static inline int kvm_hyp_trace_init(void) { return 0; }
+#endif
+#endif
-- 
2.52.0.457.g6b5491de43-goog


^ permalink raw reply related

* [PATCH v10 25/30] KVM: arm64: Sync boot clock with the nVHE/pKVM hyp
From: Vincent Donnefort @ 2026-01-26 10:44 UTC (permalink / raw)
  To: rostedt, mhiramat, mathieu.desnoyers, linux-trace-kernel, maz,
	oliver.upton, joey.gouly, suzuki.poulose, yuzenghui
  Cc: kvmarm, linux-arm-kernel, jstultz, qperret, will, aneesh.kumar,
	kernel-team, linux-kernel, Vincent Donnefort, Thomas Gleixner,
	Stephen Boyd, Christopher S. Hall, Richard Cochran
In-Reply-To: <20260126104419.1649811-1-vdonnefort@google.com>

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 c3a7fc939f42..352ebbedaab2 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 eddbf5df5d13..9df0d37a494b 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -615,6 +615,16 @@ 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);
+}
+
 typedef void (*hcall_t)(struct kvm_cpu_context *);
 
 #define HANDLE_FUNC(x)	[__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x
@@ -660,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
+
+static struct hyp_trace_clock {
+	u64			cycles;
+	u64			cyc_overflow64;
+	u64			boot;
+	u32			mult;
+	u32			shift;
+	struct delayed_work	work;
+	struct completion	ready;
+	struct mutex		lock;
+	bool			running;
+} hyp_clock;
+
+static void __hyp_clock_work(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct hyp_trace_clock *hyp_clock;
+	struct system_time_snapshot snap;
+	u64 rate, delta_cycles;
+	u64 boot, delta_boot;
+
+	hyp_clock = container_of(dwork, struct hyp_trace_clock, work);
+
+	ktime_get_snapshot(&snap);
+	boot = ktime_to_ns(snap.boot);
+
+	delta_boot = boot - hyp_clock->boot;
+	delta_cycles = snap.cycles - hyp_clock->cycles;
+
+	/* Compare hyp clock with the kernel boot clock */
+	if (hyp_clock->mult) {
+		u64 err, cur = delta_cycles;
+
+		if (WARN_ON_ONCE(cur >= hyp_clock->cyc_overflow64)) {
+			__uint128_t tmp = (__uint128_t)cur * hyp_clock->mult;
+
+			cur = tmp >> hyp_clock->shift;
+		} else {
+			cur *= hyp_clock->mult;
+			cur >>= hyp_clock->shift;
+		}
+		cur += hyp_clock->boot;
+
+		err = abs_diff(cur, boot);
+		/* No deviation, only update epoch if necessary */
+		if (!err) {
+			if (delta_cycles >= (hyp_clock->cyc_overflow64 >> 1))
+				goto fast_forward;
+
+			goto resched;
+		}
+
+		/* Warn if the error is above tracing precision (1us) */
+		if (err > NSEC_PER_USEC)
+			pr_warn_ratelimited("hyp trace clock off by %lluus\n",
+					    err / NSEC_PER_USEC);
+	}
+
+	rate = div64_u64(delta_cycles * NSEC_PER_SEC, delta_boot);
+
+	clocks_calc_mult_shift(&hyp_clock->mult, &hyp_clock->shift,
+			       rate, NSEC_PER_SEC, CLOCK_MAX_CONVERSION_S);
+
+	/* Add a comfortable 50% margin */
+	hyp_clock->cyc_overflow64 = (U64_MAX / hyp_clock->mult) >> 1;
+
+fast_forward:
+	hyp_clock->cycles = snap.cycles;
+	hyp_clock->boot = boot;
+	kvm_call_hyp_nvhe(__tracing_update_clock, hyp_clock->mult,
+			  hyp_clock->shift, hyp_clock->boot, hyp_clock->cycles);
+	complete(&hyp_clock->ready);
+
+resched:
+	schedule_delayed_work(&hyp_clock->work,
+			      msecs_to_jiffies(CLOCK_UPDATE_MS));
+}
+
+static void hyp_trace_clock_enable(struct hyp_trace_clock *hyp_clock, bool enable)
+{
+	struct system_time_snapshot snap;
+
+	if (hyp_clock->running == enable)
+		return;
+
+	if (!enable) {
+		cancel_delayed_work_sync(&hyp_clock->work);
+		hyp_clock->running = false;
+	}
+
+	ktime_get_snapshot(&snap);
+
+	hyp_clock->boot = ktime_to_ns(snap.boot);
+	hyp_clock->cycles = snap.cycles;
+	hyp_clock->mult = 0;
+
+	init_completion(&hyp_clock->ready);
+	INIT_DELAYED_WORK(&hyp_clock->work, __hyp_clock_work);
+	schedule_delayed_work(&hyp_clock->work, msecs_to_jiffies(CLOCK_INIT_MS));
+	wait_for_completion(&hyp_clock->ready);
+	hyp_clock->running = true;
+}
+
 /* Access to this struct within the trace_remote_callbacks are protected by the trace_remote lock */
 static struct hyp_trace_buffer {
 	struct hyp_trace_desc	*desc;
@@ -183,6 +301,8 @@ static void hyp_trace_unload(struct trace_buffer_desc *desc, void *priv)
 
 static int hyp_trace_enable_tracing(bool enable, void *priv)
 {
+	hyp_trace_clock_enable(&hyp_clock, enable);
+
 	return kvm_call_hyp_nvhe(__tracing_enable, enable);
 }
 
@@ -201,7 +321,22 @@ static int hyp_trace_enable_event(unsigned short id, bool enable, void *priv)
 	return 0;
 }
 
+static int hyp_trace_clock_show(struct seq_file *m, void *v)
+{
+	seq_puts(m, "[boot]\n");
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(hyp_trace_clock);
+
+static int hyp_trace_init_tracefs(struct dentry *d, void *priv)
+{
+	return tracefs_create_file("trace_clock", 0440, d, NULL, &hyp_trace_clock_fops) ?
+		0 : -ENOMEM;
+}
+
 static struct trace_remote_callbacks trace_remote_callbacks = {
+	.init			= hyp_trace_init_tracefs,
 	.load_trace_buffer	= hyp_trace_load,
 	.unload_trace_buffer	= hyp_trace_unload,
 	.enable_tracing		= hyp_trace_enable_tracing,
@@ -212,8 +347,22 @@ static struct trace_remote_callbacks trace_remote_callbacks = {
 
 int __init kvm_hyp_trace_init(void)
 {
+	int cpu;
+
 	if (is_kernel_in_hyp_mode())
 		return 0;
 
+#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND
+	for_each_possible_cpu(cpu) {
+		const struct arch_timer_erratum_workaround *wa =
+			per_cpu(timer_unstable_counter_workaround, cpu);
+
+		if (wa && wa->read_cntvct_el0) {
+			pr_warn("hyp trace can't handle CNTVCT workaround '%s'\n", wa->desc);
+			return -EOPNOTSUPP;
+		}
+	}
+#endif
+
 	return trace_remote_register("hypervisor", &trace_remote_callbacks, &trace_buffer, NULL, 0);
 }
-- 
2.52.0.457.g6b5491de43-goog


^ permalink raw reply related

* [PATCH v10 26/30] KVM: arm64: Add trace reset to the nVHE/pKVM hyp
From: Vincent Donnefort @ 2026-01-26 10:44 UTC (permalink / raw)
  To: rostedt, mhiramat, mathieu.desnoyers, linux-trace-kernel, maz,
	oliver.upton, joey.gouly, suzuki.poulose, yuzenghui
  Cc: kvmarm, linux-arm-kernel, jstultz, qperret, will, aneesh.kumar,
	kernel-team, linux-kernel, Vincent Donnefort
In-Reply-To: <20260126104419.1649811-1-vdonnefort@google.com>

Make the hypervisor reset either the whole tracing buffer or a specific
ring-buffer, on remotes/hypervisor/trace or per_cpu/<cpu>/trace write
access.

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 352ebbedaab2..c5cb2adde7ed 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -94,6 +94,7 @@ enum __kvm_host_smccc_func {
 	__KVM_HOST_SMCCC_FUNC___tracing_enable,
 	__KVM_HOST_SMCCC_FUNC___tracing_swap_reader,
 	__KVM_HOST_SMCCC_FUNC___tracing_update_clock,
+	__KVM_HOST_SMCCC_FUNC___tracing_reset,
 };
 
 #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 fd641e1b1c23..44912869d184 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/trace.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/trace.h
@@ -12,6 +12,7 @@ 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);
+int __tracing_reset(unsigned int cpu);
 #else
 static inline void *tracing_reserve_entry(unsigned long length) { return NULL; }
 static inline void tracing_commit_entry(void) { }
@@ -21,5 +22,6 @@ 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) { }
+static inline int __tracing_reset(unsigned int cpu) { return -ENODEV; }
 #endif
 #endif
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 9df0d37a494b..5acbd451efbd 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -625,6 +625,13 @@ static void handle___tracing_update_clock(struct kvm_cpu_context *host_ctxt)
 	__tracing_update_clock(mult, shift, epoch_ns, epoch_cyc);
 }
 
+static void handle___tracing_reset(struct kvm_cpu_context *host_ctxt)
+{
+	DECLARE_REG(unsigned int, cpu, host_ctxt, 1);
+
+	cpu_reg(host_ctxt, 1) = __tracing_reset(cpu);
+}
+
 typedef void (*hcall_t)(struct kvm_cpu_context *);
 
 #define HANDLE_FUNC(x)	[__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x
@@ -671,6 +678,7 @@ static const hcall_t host_hcall[] = {
 	HANDLE_FUNC(__tracing_enable),
 	HANDLE_FUNC(__tracing_swap_reader),
 	HANDLE_FUNC(__tracing_update_clock),
+	HANDLE_FUNC(__tracing_reset),
 };
 
 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 97e9f6c1a52c..93475cc36640 100644
--- a/arch/arm64/kvm/hyp/nvhe/trace.c
+++ b/arch/arm64/kvm/hyp/nvhe/trace.c
@@ -287,3 +287,20 @@ void __tracing_update_clock(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc)
 	/* ...we can now override the old one and swap. */
 	trace_clock_update(mult, shift, epoch_ns, epoch_cyc);
 }
+
+int __tracing_reset(unsigned int cpu)
+{
+	int ret = -ENODEV;
+
+	if (cpu >= hyp_nr_cpus)
+		return -EINVAL;
+
+	hyp_spin_lock(&trace_buffer.lock);
+
+	if (hyp_trace_buffer_loaded(&trace_buffer))
+		ret = simple_ring_buffer_reset(per_cpu_ptr(trace_buffer.simple_rbs, cpu));
+
+	hyp_spin_unlock(&trace_buffer.lock);
+
+	return ret;
+}
diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
index 1e5fc27f0e9d..09bc192e3514 100644
--- a/arch/arm64/kvm/hyp_trace.c
+++ b/arch/arm64/kvm/hyp_trace.c
@@ -313,7 +313,7 @@ static int hyp_trace_swap_reader_page(unsigned int cpu, void *priv)
 
 static int hyp_trace_reset(unsigned int cpu, void *priv)
 {
-	return 0;
+	return kvm_call_hyp_nvhe(__tracing_reset, cpu);
 }
 
 static int hyp_trace_enable_event(unsigned short id, bool enable, void *priv)
-- 
2.52.0.457.g6b5491de43-goog


^ permalink raw reply related

* [PATCH v10 27/30] KVM: arm64: Add event support to the nVHE/pKVM hyp and trace remote
From: Vincent Donnefort @ 2026-01-26 10:44 UTC (permalink / raw)
  To: rostedt, mhiramat, mathieu.desnoyers, linux-trace-kernel, maz,
	oliver.upton, joey.gouly, suzuki.poulose, yuzenghui
  Cc: kvmarm, linux-arm-kernel, jstultz, qperret, will, aneesh.kumar,
	kernel-team, linux-kernel, Vincent Donnefort
In-Reply-To: <20260126104419.1649811-1-vdonnefort@google.com>

Allow the creation of hypervisor and trace remote events with a single
macro HYP_EVENT(). That macro expands in the kernel side to add all
the required declarations (based on REMOTE_EVENT()) as well as in the
hypervisor side to create the trace_<event>() function.

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 c5cb2adde7ed..f8fa556ec3e1 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -95,6 +95,7 @@ enum __kvm_host_smccc_func {
 	__KVM_HOST_SMCCC_FUNC___tracing_swap_reader,
 	__KVM_HOST_SMCCC_FUNC___tracing_update_clock,
 	__KVM_HOST_SMCCC_FUNC___tracing_reset,
+	__KVM_HOST_SMCCC_FUNC___tracing_enable_event,
 };
 
 #define DECLARE_KVM_VHE_SYM(sym)	extern char sym[]
diff --git a/arch/arm64/include/asm/kvm_define_hypevents.h b/arch/arm64/include/asm/kvm_define_hypevents.h
new file mode 100644
index 000000000000..77d6790252a6
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_define_hypevents.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#define REMOTE_EVENT_INCLUDE_FILE arch/arm64/include/asm/kvm_hypevents.h
+
+#define REMOTE_EVENT_SECTION "_hyp_events"
+
+#define HE_STRUCT(__args)		__args
+#define HE_PRINTK(__args...)		__args
+#define he_field			re_field
+
+#define HYP_EVENT(__name, __proto, __struct, __assign, __printk) \
+	REMOTE_EVENT(__name, 0, RE_STRUCT(__struct), RE_PRINTK(__printk))
+
+#define HYP_EVENT_MULTI_READ
+#include <trace/define_remote_events.h>
+#undef HYP_EVENT_MULTI_READ
diff --git a/arch/arm64/include/asm/kvm_hypevents.h b/arch/arm64/include/asm/kvm_hypevents.h
new file mode 100644
index 000000000000..d6e033c96c52
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_hypevents.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#if !defined(__ARM64_KVM_HYPEVENTS_H_) || defined(HYP_EVENT_MULTI_READ)
+#define __ARM64_KVM_HYPEVENTS_H_
+
+#ifdef __KVM_NVHE_HYPERVISOR__
+#include <nvhe/trace.h>
+#endif
+
+#endif
diff --git a/arch/arm64/include/asm/kvm_hyptrace.h b/arch/arm64/include/asm/kvm_hyptrace.h
index 9c30a479bc36..de133b735f72 100644
--- a/arch/arm64/include/asm/kvm_hyptrace.h
+++ b/arch/arm64/include/asm/kvm_hyptrace.h
@@ -10,4 +10,17 @@ struct hyp_trace_desc {
 	struct trace_buffer_desc	trace_buffer_desc;
 
 };
+
+struct hyp_event_id {
+	unsigned short	id;
+	atomic_t	enabled;
+};
+
+extern struct remote_event __hyp_events_start[];
+extern struct remote_event __hyp_events_end[];
+
+/* hyp_event section used by the hypervisor */
+extern struct hyp_event_id __hyp_event_ids_start[];
+extern struct hyp_event_id __hyp_event_ids_end[];
+
 #endif
diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h
index 211f0e2e55e2..4639f92685cb 100644
--- a/arch/arm64/kernel/image-vars.h
+++ b/arch/arm64/kernel/image-vars.h
@@ -139,6 +139,10 @@ KVM_NVHE_ALIAS(__hyp_data_start);
 KVM_NVHE_ALIAS(__hyp_data_end);
 KVM_NVHE_ALIAS(__hyp_rodata_start);
 KVM_NVHE_ALIAS(__hyp_rodata_end);
+#ifdef CONFIG_NVHE_EL2_TRACING
+KVM_NVHE_ALIAS(__hyp_event_ids_start);
+KVM_NVHE_ALIAS(__hyp_event_ids_end);
+#endif
 
 /* pKVM static key */
 KVM_NVHE_ALIAS(kvm_protected_mode_initialized);
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index ad6133b89e7a..273a461c6076 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -13,12 +13,23 @@
 	*(__kvm_ex_table)					\
 	__stop___kvm_ex_table = .;
 
+#ifdef CONFIG_NVHE_EL2_TRACING
+#define HYPERVISOR_EVENT_IDS 					\
+	. = ALIGN(PAGE_SIZE);					\
+	__hyp_event_ids_start = .;				\
+	*(HYP_SECTION_NAME(.event_ids))				\
+	__hyp_event_ids_end = .;
+#else
+#define HYPERVISOR_EVENT_IDS
+#endif
+
 #define HYPERVISOR_RODATA_SECTIONS				\
 	HYP_SECTION_NAME(.rodata) : {				\
 		. = ALIGN(PAGE_SIZE);				\
 		__hyp_rodata_start = .;				\
 		*(HYP_SECTION_NAME(.data..ro_after_init))	\
 		*(HYP_SECTION_NAME(.rodata))			\
+		HYPERVISOR_EVENT_IDS				\
 		. = ALIGN(PAGE_SIZE);				\
 		__hyp_rodata_end = .;				\
 	}
@@ -307,6 +318,13 @@ SECTIONS
 
 	HYPERVISOR_DATA_SECTION
 
+#ifdef CONFIG_NVHE_EL2_TRACING
+	.data.hyp_events : {
+		__hyp_events_start = .;
+		*(SORT(_hyp_events.*))
+		__hyp_events_end = .;
+	}
+#endif
 	/*
 	 * Data written with the MMU off but read with the MMU on requires
 	 * cache lines to be invalidated, discarding up to a Cache Writeback
diff --git a/arch/arm64/kvm/hyp/include/nvhe/define_events.h b/arch/arm64/kvm/hyp/include/nvhe/define_events.h
new file mode 100644
index 000000000000..776d4c6cb702
--- /dev/null
+++ b/arch/arm64/kvm/hyp/include/nvhe/define_events.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#undef HYP_EVENT
+#define HYP_EVENT(__name, __proto, __struct, __assign, __printk)	\
+	struct hyp_event_id hyp_event_id_##__name			\
+	__section(".hyp.event_ids."#__name) = {				\
+		.enabled = ATOMIC_INIT(0),				\
+	}
+
+#define HYP_EVENT_MULTI_READ
+#include <asm/kvm_hypevents.h>
+#undef HYP_EVENT_MULTI_READ
+
+#undef HYP_EVENT
diff --git a/arch/arm64/kvm/hyp/include/nvhe/trace.h b/arch/arm64/kvm/hyp/include/nvhe/trace.h
index 44912869d184..802a18b77c56 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/trace.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/trace.h
@@ -1,9 +1,36 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 #ifndef __ARM64_KVM_HYP_NVHE_TRACE_H
 #define __ARM64_KVM_HYP_NVHE_TRACE_H
+
+#include <linux/trace_remote_event.h>
+
 #include <asm/kvm_hyptrace.h>
 
+#define HE_PROTO(__args...)	__args
+#define HE_ASSIGN(__args...)	__args
+#define HE_STRUCT		RE_STRUCT
+#define he_field		re_field
+
 #ifdef CONFIG_NVHE_EL2_TRACING
+
+#define HYP_EVENT(__name, __proto, __struct, __assign, __printk)		\
+	REMOTE_EVENT_FORMAT(__name, __struct);					\
+	extern struct hyp_event_id hyp_event_id_##__name;			\
+	static __always_inline void trace_##__name(__proto)			\
+	{									\
+		struct remote_event_format_##__name *__entry;			\
+		size_t length = sizeof(*__entry);				\
+										\
+		if (!atomic_read(&hyp_event_id_##__name.enabled))		\
+			return;							\
+		__entry = tracing_reserve_entry(length);			\
+		if (!__entry)							\
+			return;							\
+		__entry->hdr.id = hyp_event_id_##__name.id;			\
+		__assign							\
+		tracing_commit_entry();						\
+	}
+
 void *tracing_reserve_entry(unsigned long length);
 void tracing_commit_entry(void);
 
@@ -13,9 +40,12 @@ 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);
 int __tracing_reset(unsigned int cpu);
+int __tracing_enable_event(unsigned short id, bool enable);
 #else
 static inline void *tracing_reserve_entry(unsigned long length) { return NULL; }
 static inline void tracing_commit_entry(void) { }
+#define HYP_EVENT(__name, __proto, __struct, __assign, __printk)      \
+	static inline void trace_##__name(__proto) {}
 
 static inline int __tracing_load(unsigned long desc_va, size_t desc_size) { return -ENODEV; }
 static inline void __tracing_unload(void) { }
@@ -23,5 +53,6 @@ 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) { }
 static inline int __tracing_reset(unsigned int cpu) { return -ENODEV; }
+static inline int __tracing_enable_event(unsigned short id, bool enable)  { return -ENODEV; }
 #endif
 #endif
diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile
index f1840628d2d6..143d55ec7298 100644
--- a/arch/arm64/kvm/hyp/nvhe/Makefile
+++ b/arch/arm64/kvm/hyp/nvhe/Makefile
@@ -29,7 +29,7 @@ hyp-obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o ../entry.o \
 	 ../fpsimd.o ../hyp-entry.o ../exception.o ../pgtable.o
 hyp-obj-y += ../../../kernel/smccc-call.o
 hyp-obj-$(CONFIG_LIST_HARDENED) += list_debug.o
-hyp-obj-$(CONFIG_NVHE_EL2_TRACING) += clock.o trace.o
+hyp-obj-$(CONFIG_NVHE_EL2_TRACING) += clock.o trace.o events.o
 hyp-obj-y += $(lib-objs)
 
 # Path to simple_ring_buffer.c
diff --git a/arch/arm64/kvm/hyp/nvhe/events.c b/arch/arm64/kvm/hyp/nvhe/events.c
new file mode 100644
index 000000000000..add9383aadb5
--- /dev/null
+++ b/arch/arm64/kvm/hyp/nvhe/events.c
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 Google LLC
+ * Author: Vincent Donnefort <vdonnefort@google.com>
+ */
+
+#include <nvhe/mm.h>
+#include <nvhe/trace.h>
+
+#include <nvhe/define_events.h>
+
+int __tracing_enable_event(unsigned short id, bool enable)
+{
+	struct hyp_event_id *event_id = &__hyp_event_ids_start[id];
+	atomic_t *enabled;
+
+	if (event_id >= __hyp_event_ids_end)
+		return -EINVAL;
+
+	enabled = hyp_fixmap_map(__hyp_pa(&event_id->enabled));
+	atomic_set(enabled, enable);
+	hyp_fixmap_unmap();
+
+	return 0;
+}
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 5acbd451efbd..7f5b9807c42d 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -632,6 +632,14 @@ static void handle___tracing_reset(struct kvm_cpu_context *host_ctxt)
 	cpu_reg(host_ctxt, 1) = __tracing_reset(cpu);
 }
 
+static void handle___tracing_enable_event(struct kvm_cpu_context *host_ctxt)
+{
+	DECLARE_REG(unsigned short, id, host_ctxt, 1);
+	DECLARE_REG(bool, enable, host_ctxt, 2);
+
+	cpu_reg(host_ctxt, 1) = __tracing_enable_event(id, enable);
+}
+
 typedef void (*hcall_t)(struct kvm_cpu_context *);
 
 #define HANDLE_FUNC(x)	[__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x
@@ -679,6 +687,7 @@ static const hcall_t host_hcall[] = {
 	HANDLE_FUNC(__tracing_swap_reader),
 	HANDLE_FUNC(__tracing_update_clock),
 	HANDLE_FUNC(__tracing_reset),
+	HANDLE_FUNC(__tracing_enable_event),
 };
 
 static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp.lds.S b/arch/arm64/kvm/hyp/nvhe/hyp.lds.S
index d724f6d69302..7a02837203d1 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp.lds.S
+++ b/arch/arm64/kvm/hyp/nvhe/hyp.lds.S
@@ -16,6 +16,12 @@ SECTIONS {
 	HYP_SECTION(.text)
 	HYP_SECTION(.data..ro_after_init)
 	HYP_SECTION(.rodata)
+#ifdef CONFIG_NVHE_EL2_TRACING
+	. = ALIGN(PAGE_SIZE);
+	BEGIN_HYP_SECTION(.event_ids)
+		*(SORT(.hyp.event_ids.*))
+	END_HYP_SECTION
+#endif
 
 	/*
 	 * .hyp..data..percpu needs to be page aligned to maintain the same
diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
index 09bc192e3514..0144cd26703e 100644
--- a/arch/arm64/kvm/hyp_trace.c
+++ b/arch/arm64/kvm/hyp_trace.c
@@ -318,6 +318,25 @@ static int hyp_trace_reset(unsigned int cpu, void *priv)
 
 static int hyp_trace_enable_event(unsigned short id, bool enable, void *priv)
 {
+	struct hyp_event_id *event_id = lm_alias(&__hyp_event_ids_start[id]);
+	struct page *page;
+	atomic_t *enabled;
+	void *map;
+
+	if (is_protected_kvm_enabled())
+		return kvm_call_hyp_nvhe(__tracing_enable_event, id, enable);
+
+	enabled = &event_id->enabled;
+	page = virt_to_page(enabled);
+	map = vmap(&page, 1, VM_MAP, PAGE_KERNEL);
+	if (!map)
+		return -ENOMEM;
+
+	enabled = map + offset_in_page(enabled);
+	atomic_set(enabled, enable);
+
+	vunmap(map);
+
 	return 0;
 }
 
@@ -345,6 +364,19 @@ static struct trace_remote_callbacks trace_remote_callbacks = {
 	.enable_event		= hyp_trace_enable_event,
 };
 
+#include <asm/kvm_define_hypevents.h>
+
+static void __init hyp_trace_init_events(void)
+{
+	struct hyp_event_id *hyp_event_id = __hyp_event_ids_start;
+	struct remote_event *event = __hyp_events_start;
+	int id = 0;
+
+	/* Events on both sides hypervisor are sorted */
+	for (; event < __hyp_events_end; event++, hyp_event_id++, id++)
+		event->id = hyp_event_id->id = id;
+}
+
 int __init kvm_hyp_trace_init(void)
 {
 	int cpu;
@@ -364,5 +396,8 @@ int __init kvm_hyp_trace_init(void)
 	}
 #endif
 
-	return trace_remote_register("hypervisor", &trace_remote_callbacks, &trace_buffer, NULL, 0);
+	hyp_trace_init_events();
+
+	return trace_remote_register("hypervisor", &trace_remote_callbacks, &trace_buffer,
+				     __hyp_events_start, __hyp_events_end - __hyp_events_start);
 }
-- 
2.52.0.457.g6b5491de43-goog


^ permalink raw reply related

* [PATCH v10 28/30] KVM: arm64: Add hyp_enter/hyp_exit events to nVHE/pKVM hyp
From: Vincent Donnefort @ 2026-01-26 10:44 UTC (permalink / raw)
  To: rostedt, mhiramat, mathieu.desnoyers, linux-trace-kernel, maz,
	oliver.upton, joey.gouly, suzuki.poulose, yuzenghui
  Cc: kvmarm, linux-arm-kernel, jstultz, qperret, will, aneesh.kumar,
	kernel-team, linux-kernel, Vincent Donnefort
In-Reply-To: <20260126104419.1649811-1-vdonnefort@google.com>

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_host.h b/arch/arm64/include/asm/kvm_host.h
index ac7f970c7883..58f7fe685150 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -896,6 +896,9 @@ struct kvm_vcpu_arch {
 
 	/* Per-vcpu TLB for VNCR_EL2 -- NULL when !NV */
 	struct vncr_tlb	*vncr_tlb;
+
+	/* Hyp-readable copy of kvm_vcpu::pid */
+	pid_t pid;
 };
 
 /*
diff --git a/arch/arm64/include/asm/kvm_hypevents.h b/arch/arm64/include/asm/kvm_hypevents.h
index d6e033c96c52..221a1dacb2f0 100644
--- a/arch/arm64/include/asm/kvm_hypevents.h
+++ b/arch/arm64/include/asm/kvm_hypevents.h
@@ -7,4 +7,43 @@
 #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(struct kvm_cpu_context *host_ctxt, u8 reason),
+	HE_STRUCT(
+		he_field(u8, reason)
+		he_field(pid_t, vcpu)
+	),
+	HE_ASSIGN(
+		__entry->reason = reason;
+		__entry->vcpu = __tracing_get_vcpu_pid(host_ctxt);
+	),
+	HE_PRINTK("reason=%s vcpu=%d", __hyp_enter_exit_reason_str(__entry->reason), __entry->vcpu)
+);
+
+HYP_EVENT(hyp_exit,
+	HE_PROTO(struct kvm_cpu_context *host_ctxt, u8 reason),
+	HE_STRUCT(
+		he_field(u8, reason)
+		he_field(pid_t, vcpu)
+	),
+	HE_ASSIGN(
+		__entry->reason = reason;
+		__entry->vcpu = __tracing_get_vcpu_pid(host_ctxt);
+	),
+	HE_PRINTK("reason=%s vcpu=%d", __hyp_enter_exit_reason_str(__entry->reason), __entry->vcpu)
+);
 #endif
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index f7f222ecaf88..5b7c728c69ca 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -662,6 +662,8 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 
 	if (!cpumask_test_cpu(cpu, vcpu->kvm->arch.supported_cpus))
 		vcpu_set_on_unsupported_cpu(vcpu);
+
+	vcpu->arch.pid = pid_nr(vcpu->pid);
 }
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
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..1258bc84477f
--- /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(NULL, HYP_REASON_SMC);		\
+		arm_smccc_1_1_smc(__VA_ARGS__);			\
+		trace_hyp_enter(NULL, HYP_REASON_SMC);		\
+	} while (0)
+
+#define hyp_smccc_1_2_smc(...)					\
+	do {							\
+		trace_hyp_exit(NULL, HYP_REASON_SMC);		\
+		arm_smccc_1_2_smc(__VA_ARGS__);			\
+		trace_hyp_enter(NULL, HYP_REASON_SMC);		\
+	} while (0)
+
+#endif /* __ARM64_KVM_HYP_NVHE_ARM_SMCCC_H__ */
diff --git a/arch/arm64/kvm/hyp/include/nvhe/trace.h b/arch/arm64/kvm/hyp/include/nvhe/trace.h
index 802a18b77c56..8813ff250f8e 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/trace.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/trace.h
@@ -6,6 +6,18 @@
 
 #include <asm/kvm_hyptrace.h>
 
+static inline pid_t __tracing_get_vcpu_pid(struct kvm_cpu_context *host_ctxt)
+{
+	struct kvm_vcpu *vcpu;
+
+	if (!host_ctxt)
+		host_ctxt = host_data_ptr(host_ctxt);
+
+	vcpu = host_ctxt->__hyp_running_vcpu;
+
+	return vcpu ? vcpu->arch.pid : 0;
+}
+
 #define HE_PROTO(__args...)	__args
 #define HE_ASSIGN(__args...)	__args
 #define HE_STRUCT		RE_STRUCT
diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c
index f731cc4c3f28..ee5d49e733c0 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 7f5b9807c42d..e1d4a53260ff 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>
@@ -137,6 +138,8 @@ static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
 	hyp_vcpu->vcpu.arch.vsesr_el2	= host_vcpu->arch.vsesr_el2;
 
 	hyp_vcpu->vcpu.arch.vgic_cpu.vgic_v3 = host_vcpu->arch.vgic_cpu.vgic_v3;
+
+	hyp_vcpu->vcpu.arch.pid = host_vcpu->arch.pid;
 }
 
 static void sync_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
@@ -728,7 +731,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(host_ctxt, HYP_REASON_SMC);
 	__kvm_hyp_host_forward_smc(host_ctxt);
+	trace_hyp_enter(host_ctxt, HYP_REASON_SMC);
 }
 
 static void handle_host_smc(struct kvm_cpu_context *host_ctxt)
@@ -752,18 +757,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(host_ctxt, HYP_REASON_HVC);
 		handle_host_hcall(host_ctxt);
 		break;
 	case ESR_ELx_EC_SMC64:
+		trace_hyp_enter(host_ctxt, HYP_REASON_SMC);
 		handle_host_smc(host_ctxt);
 		break;
 	case ESR_ELx_EC_IABT_LOW:
 	case ESR_ELx_EC_DABT_LOW:
+		trace_hyp_enter(host_ctxt, HYP_REASON_HOST_ABORT);
 		handle_host_mem_abort(host_ctxt);
 		break;
 	default:
 		BUG();
 	}
+
+	trace_hyp_exit(host_ctxt, 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..ab4c7bddb163 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;
 }
 
@@ -206,6 +207,7 @@ asmlinkage void __noreturn __kvm_host_psci_cpu_entry(bool is_cpu_on)
 	struct kvm_cpu_context *host_ctxt;
 
 	host_ctxt = host_data_ptr(host_ctxt);
+	trace_hyp_enter(host_ctxt, HYP_REASON_PSCI);
 
 	if (is_cpu_on)
 		boot_args = this_cpu_ptr(&cpu_on_args);
@@ -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(host_ctxt, 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 779089e42681..ca60721501d1 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(host_ctxt, HYP_REASON_ERET_GUEST);
+
 		/* Jump in the fire! */
 		exit_code = __guest_enter(vcpu);
 
 		/* And we're baaack! */
+		trace_hyp_enter(host_ctxt, HYP_REASON_GUEST_EXIT);
 	} 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)
+{
+	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;
-- 
2.52.0.457.g6b5491de43-goog


^ permalink raw reply related

* [PATCH v10 29/30] KVM: arm64: Add selftest event support to nVHE/pKVM hyp
From: Vincent Donnefort @ 2026-01-26 10:44 UTC (permalink / raw)
  To: rostedt, mhiramat, mathieu.desnoyers, linux-trace-kernel, maz,
	oliver.upton, joey.gouly, suzuki.poulose, yuzenghui
  Cc: kvmarm, linux-arm-kernel, jstultz, qperret, will, aneesh.kumar,
	kernel-team, linux-kernel, Vincent Donnefort
In-Reply-To: <20260126104419.1649811-1-vdonnefort@google.com>

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 f8fa556ec3e1..c045c074614b 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 221a1dacb2f0..743c49bd878f 100644
--- a/arch/arm64/include/asm/kvm_hypevents.h
+++ b/arch/arm64/include/asm/kvm_hypevents.h
@@ -46,4 +46,15 @@ HYP_EVENT(hyp_exit,
 	),
 	HE_PRINTK("reason=%s vcpu=%d", __hyp_enter_exit_reason_str(__entry->reason), __entry->vcpu)
 );
+
+HYP_EVENT(selftest,
+	HE_PROTO(u64 id),
+	HE_STRUCT(
+		he_field(u64, id)
+	),
+	HE_ASSIGN(
+		__entry->id = id;
+	),
+	RE_PRINTK("id=%llu", __entry->id)
+);
 #endif
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index e1d4a53260ff..5655c1690f4a 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -643,6 +643,13 @@ static void handle___tracing_enable_event(struct kvm_cpu_context *host_ctxt)
 	cpu_reg(host_ctxt, 1) = __tracing_enable_event(id, enable);
 }
 
+static void handle___tracing_write_event(struct kvm_cpu_context *host_ctxt)
+{
+	DECLARE_REG(u64, id, host_ctxt, 1);
+
+	trace_selftest(id);
+}
+
 typedef void (*hcall_t)(struct kvm_cpu_context *);
 
 #define HANDLE_FUNC(x)	[__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x
@@ -691,6 +698,7 @@ static const hcall_t host_hcall[] = {
 	HANDLE_FUNC(__tracing_update_clock),
 	HANDLE_FUNC(__tracing_reset),
 	HANDLE_FUNC(__tracing_enable_event),
+	HANDLE_FUNC(__tracing_write_event),
 };
 
 static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
index 1ad6a55ba95c..c1e28f6581ab 100644
--- a/arch/arm64/kvm/hyp_trace.c
+++ b/arch/arm64/kvm/hyp_trace.c
@@ -348,8 +348,30 @@ static int hyp_trace_clock_show(struct seq_file *m, void *v)
 }
 DEFINE_SHOW_ATTRIBUTE(hyp_trace_clock);
 
+static ssize_t hyp_trace_write_event_write(struct file *f, const char __user *ubuf,
+					   size_t cnt, loff_t *pos)
+{
+	unsigned long val;
+	int ret;
+
+	ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
+	if (ret)
+		return ret;
+
+	kvm_call_hyp_nvhe(__tracing_write_event, val);
+
+	return cnt;
+}
+
+static const struct file_operations hyp_trace_write_event_fops = {
+	.write	= hyp_trace_write_event_write,
+};
+
 static int hyp_trace_init_tracefs(struct dentry *d, void *priv)
 {
+	if (!tracefs_create_file("write_event", 0200, d, NULL, &hyp_trace_write_event_fops))
+		return -ENOMEM;
+
 	return tracefs_create_file("trace_clock", 0440, d, NULL, &hyp_trace_clock_fops) ?
 		0 : -ENOMEM;
 }
-- 
2.52.0.457.g6b5491de43-goog


^ permalink raw reply related

* [PATCH v10 30/30] tracing: selftests: Add hypervisor trace remote tests
From: Vincent Donnefort @ 2026-01-26 10:44 UTC (permalink / raw)
  To: rostedt, mhiramat, mathieu.desnoyers, linux-trace-kernel, maz,
	oliver.upton, joey.gouly, suzuki.poulose, yuzenghui
  Cc: kvmarm, linux-arm-kernel, jstultz, qperret, will, aneesh.kumar,
	kernel-team, linux-kernel, Vincent Donnefort, Shuah Khan,
	linux-kselftest
In-Reply-To: <20260126104419.1649811-1-vdonnefort@google.com>

Run the trace remote selftests with the trace remote 'hypervisor', This
trace remote is most likely created when the arm64 KVM nVHE/pKVM
hypervisor is in use.

Cc: Shuah Khan <skhan@linuxfoundation.org>
Cc: linux-kselftest@vger.kernel.org
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>

diff --git a/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/buffer_size.tc b/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/buffer_size.tc
new file mode 100644
index 000000000000..64bf859d6406
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/buffer_size.tc
@@ -0,0 +1,11 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Test hypervisor trace buffer size
+# requires: remotes/hypervisor/write_event
+
+SOURCE_REMOTE_TEST=1
+. $TEST_DIR/remotes/buffer_size.tc
+
+set -e
+setup_remote "hypervisor"
+test_buffer_size
diff --git a/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/reset.tc b/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/reset.tc
new file mode 100644
index 000000000000..7fe3b09b34e3
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/reset.tc
@@ -0,0 +1,11 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Test hypervisor trace buffer reset
+# requires: remotes/hypervisor/write_event
+
+SOURCE_REMOTE_TEST=1
+. $TEST_DIR/remotes/reset.tc
+
+set -e
+setup_remote "hypervisor"
+test_reset
diff --git a/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/trace.tc b/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/trace.tc
new file mode 100644
index 000000000000..b937c19ca7f9
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/trace.tc
@@ -0,0 +1,11 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Test hypervisor non-consuming trace read
+# requires: remotes/hypervisor/write_event
+
+SOURCE_REMOTE_TEST=1
+. $TEST_DIR/remotes/trace.tc
+
+set -e
+setup_remote "hypervisor"
+test_trace
diff --git a/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/trace_pipe.tc b/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/trace_pipe.tc
new file mode 100644
index 000000000000..66aa1b76c147
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/trace_pipe.tc
@@ -0,0 +1,11 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Test hypervisor consuming trace read
+# requires: remotes/hypervisor/write_event
+
+SOURCE_REMOTE_TEST=1
+. $TEST_DIR/remotes/trace_pipe.tc
+
+set -e
+setup_remote "hypervisor"
+test_trace_pipe
diff --git a/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/unloading.tc b/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/unloading.tc
new file mode 100644
index 000000000000..1dafde3414ab
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/remotes/hypervisor/unloading.tc
@@ -0,0 +1,11 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Test hypervisor trace buffer unloading
+# requires: remotes/hypervisor/write_event
+
+SOURCE_REMOTE_TEST=1
+. $TEST_DIR/remotes/unloading.tc
+
+set -e
+setup_remote "hypervisor"
+test_unloading
-- 
2.52.0.457.g6b5491de43-goog


^ permalink raw reply related

* Re: [PATCH mm-unstable v14 00/16] khugepaged: mTHP support
From: Lorenzo Stoakes @ 2026-01-26 11:21 UTC (permalink / raw)
  To: Nico Pache
  Cc: linux-mm, linux-doc, linux-kernel, linux-trace-kernel, akpm,
	david, ziy, baolin.wang, Liam.Howlett, ryan.roberts, dev.jain,
	baohua, lance.yang, vbabka, rppt, surenb, mhocko, corbet, rostedt,
	mhiramat, mathieu.desnoyers, matthew.brost, joshua.hahnjy,
	rakie.kim, byungchul, gourry, ying.huang, apopple, jannh,
	pfalcato, jackmanb, hannes, willy, peterx, wangkefeng.wang,
	usamaarif642, sunnanyong, vishal.moola, thomas.hellstrom, yang,
	kas, aarcange, raquini, anshuman.khandual, catalin.marinas, tiwai,
	will, dave.hansen, jack, cl, jglisse, zokeefe, rientjes, rdunlap,
	hughd, richard.weiyang
In-Reply-To: <20260122192841.128719-1-npache@redhat.com>

One small point on this - I don't necessarily blame you for wrapping up some
other stuff in review with the rebase, BUT - it makes difficult for reviewers
when it comes to picking up changes between v13 and v14.

You're going to have issues anyway given the flurry of THP patches we get every
cycle, but part of the review process often is to use git range-diff to check
what _actually_ change between revisions.

And in this case, I had to resolve a whole bunch of merge conflicts just to get
v13 to a point where it _kind of_ represents what was there before on a common
base.

Obviously I'm not asking you to constantly rebase series :P but I'd say in
future it might be useful to separate out the rebase step from the respin, when
asked for a resend to just do a resend, THEN if the time is right for a respin,
to do that separately.

Really more applicable to larger series like this and it's all a bit fuzzy, but
in this case it definitely would have helped!

Thanks, Lorenzo

^ permalink raw reply

* Re: [PATCH mm-unstable v14 00/16] khugepaged: mTHP support
From: Lorenzo Stoakes @ 2026-01-26 11:32 UTC (permalink / raw)
  To: Nico Pache
  Cc: linux-mm, linux-doc, linux-kernel, linux-trace-kernel, akpm,
	david, ziy, baolin.wang, Liam.Howlett, ryan.roberts, dev.jain,
	baohua, lance.yang, vbabka, rppt, surenb, mhocko, corbet, rostedt,
	mhiramat, mathieu.desnoyers, matthew.brost, joshua.hahnjy,
	rakie.kim, byungchul, gourry, ying.huang, apopple, jannh,
	pfalcato, jackmanb, hannes, willy, peterx, wangkefeng.wang,
	usamaarif642, sunnanyong, vishal.moola, thomas.hellstrom, yang,
	kas, aarcange, raquini, anshuman.khandual, catalin.marinas, tiwai,
	will, dave.hansen, jack, cl, jglisse, zokeefe, rientjes, rdunlap,
	hughd, richard.weiyang
In-Reply-To: <20260122192841.128719-1-npache@redhat.com>

On Thu, Jan 22, 2026 at 12:28:25PM -0700, Nico Pache wrote:
> V14 Changes:
> - Added review tags
> - refactored is_mthp_order() to is_pmd_order(), utilized it in more places, and
>   moved it to the first commit of the series
> - squashed fixup sent with v13
> - rebased and handled conflicts with new madvise_collapse writeback retry logic [3]
> - handled conflict with khugepaged cleanup series [4]

Hmm no mention of change to 3/16, unless it's folded into one of the above?

Very important to make reviewers aware of this stuff.

It's also worth separating out things at a fine-grained level, really
everything. More detail is good. See [0] for example - I practice what I preach
:)

Thanks, Lorenzo

[0]:https://lore.kernel.org/linux-mm/cover.1769198904.git.lorenzo.stoakes@oracle.com/

^ permalink raw reply

* Re: [PATCH mm-unstable v14 03/16] introduce collapse_single_pmd to unify khugepaged and madvise_collapse
From: Lorenzo Stoakes @ 2026-01-26 11:40 UTC (permalink / raw)
  To: Lance Yang
  Cc: Nico Pache, akpm, david, ziy, baolin.wang, Liam.Howlett,
	ryan.roberts, dev.jain, baohua, vbabka, rppt, surenb, mhocko,
	linux-trace-kernel, linux-doc, corbet, rostedt, mhiramat,
	mathieu.desnoyers, linux-kernel, matthew.brost, joshua.hahnjy,
	rakie.kim, byungchul, gourry, ying.huang, apopple, jannh,
	pfalcato, jackmanb, hannes, willy, peterx, wangkefeng.wang,
	usamaarif642, sunnanyong, vishal.moola, thomas.hellstrom, yang,
	kas, aarcange, raquini, anshuman.khandual, catalin.marinas, tiwai,
	will, dave.hansen, jack, cl, jglisse, zokeefe, rientjes, rdunlap,
	hughd, richard.weiyang, David Hildenbrand, linux-mm
In-Reply-To: <65dcf7ab-1299-411f-9cbc-438ae72ff757@linux.dev>

Andrew - when this goes into mm-new if there isn't a respin between, please
drop all tags except any obviously sent re: the fix-patch.

Thanks!

On Fri, Jan 23, 2026 at 01:07:16PM +0800, Lance Yang wrote:
>
>
> On 2026/1/23 03:28, Nico Pache wrote:
> > The khugepaged daemon and madvise_collapse have two different
> > implementations that do almost the same thing.
> >
> > Create collapse_single_pmd to increase code reuse and create an entry
> > point to these two users.
> >
> > Refactor madvise_collapse and collapse_scan_mm_slot to use the new
> > collapse_single_pmd function. This introduces a minor behavioral change
> > that is most likely an undiscovered bug. The current implementation of
> > khugepaged tests collapse_test_exit_or_disable before calling
> > collapse_pte_mapped_thp, but we weren't doing it in the madvise_collapse
> > case. By unifying these two callers madvise_collapse now also performs
> > this check. We also modify the return value to be SCAN_ANY_PROCESS which
> > properly indicates that this process is no longer valid to operate on.
> >
> > We also guard the khugepaged_pages_collapsed variable to ensure its only
> > incremented for khugepaged.
> >
> > Reviewed-by: Wei Yang <richard.weiyang@gmail.com>
> > Reviewed-by: Lance Yang <lance.yang@linux.dev>
> > Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
> > Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
> > Reviewed-by: Zi Yan <ziy@nvidia.com>
> > Acked-by: David Hildenbrand <david@redhat.com>
> > Signed-off-by: Nico Pache <npache@redhat.com>
> > ---
>
> I think this patch introduces some functional changes compared to previous
> version[1] ...
>
> Maybe we should drop the r-b tags and let folks take another look?

Yes thanks Lance, absolutely this should happen.

Especially on a small-iteration respin (I really wanted to get to v13 but the
rebase issue killed that).

I know it wasn't intentional, not suggesting that of course :) just obviously as
a process thing - it's _very_ important to make clear what you've changed and
what you haven't. For truly minor changes no need to drop the tags, but often my
workflow is:

- Check which patches I haven't reviewed yet.
- Go review those.

So I might well have missed that.

I often try to do a git range-diff, but in this case I probably wouldn't have on
basis of the v13 having merge conflicts.

But obviously given the above I went and fixed them up and applied v13 locally
so I could check everything :)

>
> There might be an issue with the vma access in madvise_collapse(). See
> below:
>
> [1]
> https://lore.kernel.org/linux-mm/20251201174627.23295-3-npache@redhat.com/
>
> >   mm/khugepaged.c | 106 +++++++++++++++++++++++++++---------------------
> >   1 file changed, 60 insertions(+), 46 deletions(-)
> >
> > diff --git a/mm/khugepaged.c b/mm/khugepaged.c
> > index fefcbdca4510..59e5a5588d85 100644
> > --- a/mm/khugepaged.c
> > +++ b/mm/khugepaged.c
> > @@ -2394,6 +2394,54 @@ static enum scan_result collapse_scan_file(struct mm_struct *mm, unsigned long a
> >   	return result;
> >   }
> > +/*
> > + * Try to collapse a single PMD starting at a PMD aligned addr, and return
> > + * the results.
> > + */
> > +static enum scan_result collapse_single_pmd(unsigned long addr,
> > +		struct vm_area_struct *vma, bool *mmap_locked,
> > +		struct collapse_control *cc)
> > +{
> > +	struct mm_struct *mm = vma->vm_mm;
> > +	enum scan_result result;
> > +	struct file *file;
> > +	pgoff_t pgoff;
> > +
> > +	if (vma_is_anonymous(vma)) {
> > +		result = collapse_scan_pmd(mm, vma, addr, mmap_locked, cc);
> > +		goto end;
> > +	}
> > +
> > +	file = get_file(vma->vm_file);
> > +	pgoff = linear_page_index(vma, addr);
> > +
> > +	mmap_read_unlock(mm);
> > +	*mmap_locked = false;
> > +	result = collapse_scan_file(mm, addr, file, pgoff, cc);
> > +	fput(file);
> > +
> > +	if (result != SCAN_PTE_MAPPED_HUGEPAGE)
> > +		goto end;
> > +
> > +	mmap_read_lock(mm);
> > +	*mmap_locked = true;
> > +	if (collapse_test_exit_or_disable(mm)) {
> > +		mmap_read_unlock(mm);
> > +		*mmap_locked = false;
> > +		return SCAN_ANY_PROCESS;
> > +	}
> > +	result = try_collapse_pte_mapped_thp(mm, addr, !cc->is_khugepaged);
> > +	if (result == SCAN_PMD_MAPPED)
> > +		result = SCAN_SUCCEED;
> > +	mmap_read_unlock(mm);
> > +	*mmap_locked = false;
> > +
> > +end:
> > +	if (cc->is_khugepaged && result == SCAN_SUCCEED)
> > +		++khugepaged_pages_collapsed;
> > +	return result;
> > +}
> > +
> >   static unsigned int collapse_scan_mm_slot(unsigned int pages, enum scan_result *result,
> >   					    struct collapse_control *cc)
> >   	__releases(&khugepaged_mm_lock)
> > @@ -2466,34 +2514,9 @@ static unsigned int collapse_scan_mm_slot(unsigned int pages, enum scan_result *
> >   			VM_BUG_ON(khugepaged_scan.address < hstart ||
> >   				  khugepaged_scan.address + HPAGE_PMD_SIZE >
> >   				  hend);
> > -			if (!vma_is_anonymous(vma)) {
> > -				struct file *file = get_file(vma->vm_file);
> > -				pgoff_t pgoff = linear_page_index(vma,
> > -						khugepaged_scan.address);
> > -
> > -				mmap_read_unlock(mm);
> > -				mmap_locked = false;
> > -				*result = collapse_scan_file(mm,
> > -					khugepaged_scan.address, file, pgoff, cc);
> > -				fput(file);
> > -				if (*result == SCAN_PTE_MAPPED_HUGEPAGE) {
> > -					mmap_read_lock(mm);
> > -					if (collapse_test_exit_or_disable(mm))
> > -						goto breakouterloop;
> > -					*result = try_collapse_pte_mapped_thp(mm,
> > -						khugepaged_scan.address, false);
> > -					if (*result == SCAN_PMD_MAPPED)
> > -						*result = SCAN_SUCCEED;
> > -					mmap_read_unlock(mm);
> > -				}
> > -			} else {
> > -				*result = collapse_scan_pmd(mm, vma,
> > -					khugepaged_scan.address, &mmap_locked, cc);
> > -			}
> > -
> > -			if (*result == SCAN_SUCCEED)
> > -				++khugepaged_pages_collapsed;
> > +			*result = collapse_single_pmd(khugepaged_scan.address,
> > +						      vma, &mmap_locked, cc);
> >   			/* move to next address */
> >   			khugepaged_scan.address += HPAGE_PMD_SIZE;
> >   			progress += HPAGE_PMD_NR;
> > @@ -2799,6 +2822,7 @@ int madvise_collapse(struct vm_area_struct *vma, unsigned long start,
> >   			cond_resched();
> >   			mmap_read_lock(mm);
> >   			mmap_locked = true;
> > +			*lock_dropped = true;
> >   			result = hugepage_vma_revalidate(mm, addr, false, &vma,
> >   							 cc);
> >   			if (result  != SCAN_SUCCEED) {
> > @@ -2809,17 +2833,17 @@ int madvise_collapse(struct vm_area_struct *vma, unsigned long start,
> >   			hend = min(hend, vma->vm_end & HPAGE_PMD_MASK);
> >   		}
> >   		mmap_assert_locked(mm);
> > -		if (!vma_is_anonymous(vma)) {
> > -			struct file *file = get_file(vma->vm_file);
> > -			pgoff_t pgoff = linear_page_index(vma, addr);
> > -			mmap_read_unlock(mm);
> > -			mmap_locked = false;
> > +		result = collapse_single_pmd(addr, vma, &mmap_locked, cc);
> > +
> > +		if (!mmap_locked)
> >   			*lock_dropped = true;
> > -			result = collapse_scan_file(mm, addr, file, pgoff, cc);
> > -			if (result == SCAN_PAGE_DIRTY_OR_WRITEBACK && !triggered_wb &&
> > -			    mapping_can_writeback(file->f_mapping)) {
> > +		if (result == SCAN_PAGE_DIRTY_OR_WRITEBACK && !triggered_wb) {
> > +			struct file *file = get_file(vma->vm_file);
> > +			pgoff_t pgoff = linear_page_index(vma, addr);
>
>
> After collapse_single_pmd() returns, mmap_lock might have been released.
> Between
> that unlock and here, another thread could unmap/remap the VMA, making the
> vma
> pointer stale when we access vma->vm_file?

Yeah, yikes.

The locking logic around this code is horrifying... but that's one for future
series I guess.

>
> Would it be safer to get the file reference before calling
> collapse_single_pmd()?
> Or we need to revalidate the VMA after getting the lock back?

Also obviously the pgoff.

I know Nico suggested a patch in a response, will check.

Cheers, Lorenzo

^ permalink raw reply

* Re: [PATCH mm-unstable v14 03/16] introduce collapse_single_pmd to unify khugepaged and madvise_collapse
From: Lorenzo Stoakes @ 2026-01-26 12:25 UTC (permalink / raw)
  To: Nico Pache
  Cc: Lance Yang, Garg, Shivank, akpm, david, ziy, baolin.wang,
	Liam.Howlett, ryan.roberts, dev.jain, baohua, vbabka, rppt,
	surenb, mhocko, linux-trace-kernel, linux-doc, corbet, rostedt,
	mhiramat, mathieu.desnoyers, linux-kernel, matthew.brost,
	joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, apopple,
	jannh, pfalcato, jackmanb, hannes, willy, peterx, wangkefeng.wang,
	usamaarif642, sunnanyong, vishal.moola, thomas.hellstrom, yang,
	kas, aarcange, raquini, anshuman.khandual, catalin.marinas, tiwai,
	will, dave.hansen, jack, cl, jglisse, zokeefe, rientjes, rdunlap,
	hughd, richard.weiyang, David Hildenbrand, linux-mm
In-Reply-To: <CAA1CXcDm75=hM_g0x7ox05nGrGykE8ry_+NbryYu=T+TY114MQ@mail.gmail.com>

On Fri, Jan 23, 2026 at 04:26:09PM -0700, Nico Pache wrote:
> On Thu, Jan 22, 2026 at 10:08 PM Lance Yang <lance.yang@linux.dev> wrote:
> >
> >
> >
> > On 2026/1/23 03:28, Nico Pache wrote:
> > > The khugepaged daemon and madvise_collapse have two different
> > > implementations that do almost the same thing.
> > >
> > > Create collapse_single_pmd to increase code reuse and create an entry
> > > point to these two users.
> > >
> > > Refactor madvise_collapse and collapse_scan_mm_slot to use the new
> > > collapse_single_pmd function. This introduces a minor behavioral change
> > > that is most likely an undiscovered bug. The current implementation of
> > > khugepaged tests collapse_test_exit_or_disable before calling
> > > collapse_pte_mapped_thp, but we weren't doing it in the madvise_collapse
> > > case. By unifying these two callers madvise_collapse now also performs
> > > this check. We also modify the return value to be SCAN_ANY_PROCESS which
> > > properly indicates that this process is no longer valid to operate on.
> > >
> > > We also guard the khugepaged_pages_collapsed variable to ensure its only
> > > incremented for khugepaged.
> > >
> > > Reviewed-by: Wei Yang <richard.weiyang@gmail.com>
> > > Reviewed-by: Lance Yang <lance.yang@linux.dev>
> > > Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
> > > Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
> > > Reviewed-by: Zi Yan <ziy@nvidia.com>
> > > Acked-by: David Hildenbrand <david@redhat.com>
> > > Signed-off-by: Nico Pache <npache@redhat.com>
> > > ---
> >
> > I think this patch introduces some functional changes compared to previous
> > version[1] ...
> >
> > Maybe we should drop the r-b tags and let folks take another look?
> >
> > There might be an issue with the vma access in madvise_collapse(). See
> > below:
> >
> > [1]
> > https://lore.kernel.org/linux-mm/20251201174627.23295-3-npache@redhat.com/
> >
> > >   mm/khugepaged.c | 106 +++++++++++++++++++++++++++---------------------
> > >   1 file changed, 60 insertions(+), 46 deletions(-)
> > >
> > > diff --git a/mm/khugepaged.c b/mm/khugepaged.c
> > > index fefcbdca4510..59e5a5588d85 100644
> > > --- a/mm/khugepaged.c
> > > +++ b/mm/khugepaged.c
> > > @@ -2394,6 +2394,54 @@ static enum scan_result collapse_scan_file(struct mm_struct *mm, unsigned long a
> > >       return result;
> > >   }
> > >
> > > +/*
> > > + * Try to collapse a single PMD starting at a PMD aligned addr, and return
> > > + * the results.
> > > + */
> > > +static enum scan_result collapse_single_pmd(unsigned long addr,
> > > +             struct vm_area_struct *vma, bool *mmap_locked,
> > > +             struct collapse_control *cc)
> > > +{
> > > +     struct mm_struct *mm = vma->vm_mm;
> > > +     enum scan_result result;
> > > +     struct file *file;
> > > +     pgoff_t pgoff;
> > > +
> > > +     if (vma_is_anonymous(vma)) {
> > > +             result = collapse_scan_pmd(mm, vma, addr, mmap_locked, cc);
> > > +             goto end;
> > > +     }
> > > +
> > > +     file = get_file(vma->vm_file);
> > > +     pgoff = linear_page_index(vma, addr);
> > > +
> > > +     mmap_read_unlock(mm);
> > > +     *mmap_locked = false;
> > > +     result = collapse_scan_file(mm, addr, file, pgoff, cc);
> > > +     fput(file);
> > > +
> > > +     if (result != SCAN_PTE_MAPPED_HUGEPAGE)
> > > +             goto end;
> > > +
> > > +     mmap_read_lock(mm);
> > > +     *mmap_locked = true;
> > > +     if (collapse_test_exit_or_disable(mm)) {
> > > +             mmap_read_unlock(mm);
> > > +             *mmap_locked = false;
> > > +             return SCAN_ANY_PROCESS;
> > > +     }
> > > +     result = try_collapse_pte_mapped_thp(mm, addr, !cc->is_khugepaged);
> > > +     if (result == SCAN_PMD_MAPPED)
> > > +             result = SCAN_SUCCEED;
> > > +     mmap_read_unlock(mm);
> > > +     *mmap_locked = false;
> > > +
> > > +end:
> > > +     if (cc->is_khugepaged && result == SCAN_SUCCEED)
> > > +             ++khugepaged_pages_collapsed;
> > > +     return result;
> > > +}
> > > +
> > >   static unsigned int collapse_scan_mm_slot(unsigned int pages, enum scan_result *result,
> > >                                           struct collapse_control *cc)
> > >       __releases(&khugepaged_mm_lock)
> > > @@ -2466,34 +2514,9 @@ static unsigned int collapse_scan_mm_slot(unsigned int pages, enum scan_result *
> > >                       VM_BUG_ON(khugepaged_scan.address < hstart ||
> > >                                 khugepaged_scan.address + HPAGE_PMD_SIZE >
> > >                                 hend);
> > > -                     if (!vma_is_anonymous(vma)) {
> > > -                             struct file *file = get_file(vma->vm_file);
> > > -                             pgoff_t pgoff = linear_page_index(vma,
> > > -                                             khugepaged_scan.address);
> > > -
> > > -                             mmap_read_unlock(mm);
> > > -                             mmap_locked = false;
> > > -                             *result = collapse_scan_file(mm,
> > > -                                     khugepaged_scan.address, file, pgoff, cc);
> > > -                             fput(file);
> > > -                             if (*result == SCAN_PTE_MAPPED_HUGEPAGE) {
> > > -                                     mmap_read_lock(mm);
> > > -                                     if (collapse_test_exit_or_disable(mm))
> > > -                                             goto breakouterloop;
> > > -                                     *result = try_collapse_pte_mapped_thp(mm,
> > > -                                             khugepaged_scan.address, false);
> > > -                                     if (*result == SCAN_PMD_MAPPED)
> > > -                                             *result = SCAN_SUCCEED;
> > > -                                     mmap_read_unlock(mm);
> > > -                             }
> > > -                     } else {
> > > -                             *result = collapse_scan_pmd(mm, vma,
> > > -                                     khugepaged_scan.address, &mmap_locked, cc);
> > > -                     }
> > > -
> > > -                     if (*result == SCAN_SUCCEED)
> > > -                             ++khugepaged_pages_collapsed;
> > >
> > > +                     *result = collapse_single_pmd(khugepaged_scan.address,
> > > +                                                   vma, &mmap_locked, cc);
> > >                       /* move to next address */
> > >                       khugepaged_scan.address += HPAGE_PMD_SIZE;
> > >                       progress += HPAGE_PMD_NR;
> > > @@ -2799,6 +2822,7 @@ int madvise_collapse(struct vm_area_struct *vma, unsigned long start,
> > >                       cond_resched();
> > >                       mmap_read_lock(mm);
> > >                       mmap_locked = true;
> > > +                     *lock_dropped = true;
> > >                       result = hugepage_vma_revalidate(mm, addr, false, &vma,
> > >                                                        cc);
> > >                       if (result  != SCAN_SUCCEED) {
> > > @@ -2809,17 +2833,17 @@ int madvise_collapse(struct vm_area_struct *vma, unsigned long start,
> > >                       hend = min(hend, vma->vm_end & HPAGE_PMD_MASK);
> > >               }
> > >               mmap_assert_locked(mm);
> > > -             if (!vma_is_anonymous(vma)) {
> > > -                     struct file *file = get_file(vma->vm_file);
> > > -                     pgoff_t pgoff = linear_page_index(vma, addr);
> > >
> > > -                     mmap_read_unlock(mm);
> > > -                     mmap_locked = false;
> > > +             result = collapse_single_pmd(addr, vma, &mmap_locked, cc);
> > > +
> > > +             if (!mmap_locked)
> > >                       *lock_dropped = true;
> > > -                     result = collapse_scan_file(mm, addr, file, pgoff, cc);
> > >
> > > -                     if (result == SCAN_PAGE_DIRTY_OR_WRITEBACK && !triggered_wb &&
> > > -                         mapping_can_writeback(file->f_mapping)) {
> > > +             if (result == SCAN_PAGE_DIRTY_OR_WRITEBACK && !triggered_wb) {
> > > +                     struct file *file = get_file(vma->vm_file);
> > > +                     pgoff_t pgoff = linear_page_index(vma, addr);
> >
> >
> > After collapse_single_pmd() returns, mmap_lock might have been released.
> > Between
> > that unlock and here, another thread could unmap/remap the VMA, making
> > the vma
> > pointer stale when we access vma->vm_file?
>
> + Shivank, I thought they were on the CC list.
>
> Hey! I thought of this case, but then figured it was no different than
> what is currently implemented for the writeback-retry logic, since the
> mmap lock is dropped and not revalidated. BUT I failed to consider
> that the file reference is held throughout that time.

You obviously can't manipulate or reference a pointer to a VMA in any way
if is no longer stabilised, that'd be a potential UAF.

>
> I thought of moving the functionality into collapse_single_pmd(), but
> figured I'd keep it in madvise_collapse() as it's the sole user of
> that functionality. Given the potential file ref issue, that may be
> the best solution, and I dont think it should be too difficult. I'll
> queue that up, and also drop the r-b tags as you suggested.
>
> Ok, here's my solution, does this look like the right approach?:
> diff --git a/mm/khugepaged.c b/mm/khugepaged.c
> index 59e5a5588d85..dda9fdc35767 100644
> --- a/mm/khugepaged.c
> +++ b/mm/khugepaged.c
> @@ -2418,6 +2418,14 @@ static enum scan_result
> collapse_single_pmd(unsigned long addr,
>         mmap_read_unlock(mm);
>         *mmap_locked = false;
>         result = collapse_scan_file(mm, addr, file, pgoff, cc);
> +
> +       if (!cc->is_khugepaged && result == SCAN_PAGE_DIRTY_OR_WRITEBACK &&
> +           mapping_can_writeback(file->f_mapping)) {
> +               loff_t lstart = (loff_t)pgoff << PAGE_SHIFT;
> +               loff_t lend = lstart + HPAGE_PMD_SIZE - 1;

NIT, but Let's const-ify these.

Also credit to Baolin for having suggested taking the approach of putting
here! :)


> +
> +               filemap_write_and_wait_range(file->f_mapping, lstart, lend);
> +       }
>         fput(file);
>
>         if (result != SCAN_PTE_MAPPED_HUGEPAGE)
> @@ -2840,19 +2848,8 @@ int madvise_collapse(struct vm_area_struct
> *vma, unsigned long start,
>                         *lock_dropped = true;
>
>                 if (result == SCAN_PAGE_DIRTY_OR_WRITEBACK && !triggered_wb) {
> -                       struct file *file = get_file(vma->vm_file);
> -                       pgoff_t pgoff = linear_page_index(vma, addr);
> -
> -                       if (mapping_can_writeback(file->f_mapping)) {
> -                               loff_t lstart = (loff_t)pgoff << PAGE_SHIFT;
> -                               loff_t lend = lstart + HPAGE_PMD_SIZE - 1;
> -
> -
> filemap_write_and_wait_range(file->f_mapping, lstart, lend);
> -                               triggered_wb = true;
> -                               fput(file);
> -                               goto retry;
> -                       }
> -                       fput(file);
> +                       triggered_wb = true;
> +                       goto retry;

OK this looks correct I agree with Lance.

Could you send this in reply to the parent, i.e. [0], as a fix-patch and
ask Andrew to apply it?

Can then review that there.

[0]:https://lore.kernel.org/all/20260122192841.128719-4-npache@redhat.com/


>                 }
>
>                 switch (result) {
>
>
>
> -- Nico
>

Cheers, Lorenzo

^ permalink raw reply

* Re: [PATCH] MAINTAINERS: add Rust files to STATIC BRANCH/CALL and TRACING
From: Alice Ryhl @ 2026-01-26 12:27 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Miguel Ojeda, Masami Hiramatsu, Mathieu Desnoyers, Peter Zijlstra,
	Josh Poimboeuf, Jason Baron, Ard Biesheuvel, linux-kernel,
	linux-trace-kernel, rust-for-linux
In-Reply-To: <20260112115408.48ed4d35@gandalf.local.home>

On Mon, Jan 12, 2026 at 11:54:08AM -0500, Steven Rostedt wrote:
> On Mon, 12 Jan 2026 15:10:31 +0000
> Alice Ryhl <aliceryhl@google.com> wrote:
> 
> > > And have the M of the other sections be R here?  
> > 
> > Sure, we can do that.
> > 
> > Are you still willing to pick up the patches? I think that is simpler in
> > case there are any series that touch both the C and Rust parts. (Such as
> > the initial tracepoint series did.)
> 
> Yes. So I guess you can still add me with a 'M:'. But I wanted a separate
> section so that all the Rust expertise is still included.

What about the STATIC BRANCH/CALL subsystem? Should I also leave you or
someone else as 'M:' there? It's unclear to me who usually picks up
patches for STATIC BRANCH/CALL when they are not a dependency to a patch
for somewhere else.

Alice

^ permalink raw reply

* Re: [PATCH mm-unstable v14 03/16] introduce collapse_single_pmd to unify khugepaged and madvise_collapse
From: Lorenzo Stoakes @ 2026-01-26 12:25 UTC (permalink / raw)
  To: Baolin Wang
  Cc: Lance Yang, Nico Pache, akpm, david, ziy, Liam.Howlett,
	ryan.roberts, dev.jain, baohua, vbabka, rppt, surenb, mhocko,
	linux-trace-kernel, linux-doc, corbet, rostedt, mhiramat,
	mathieu.desnoyers, linux-kernel, matthew.brost, joshua.hahnjy,
	rakie.kim, byungchul, gourry, ying.huang, apopple, jannh,
	pfalcato, jackmanb, hannes, willy, peterx, wangkefeng.wang,
	usamaarif642, sunnanyong, vishal.moola, thomas.hellstrom, yang,
	kas, aarcange, raquini, anshuman.khandual, catalin.marinas, tiwai,
	will, dave.hansen, jack, cl, jglisse, zokeefe, rientjes, rdunlap,
	hughd, richard.weiyang, David Hildenbrand, linux-mm
In-Reply-To: <b1747380-1f2e-4edd-81fe-f01b3fd01bad@linux.alibaba.com>

On Fri, Jan 23, 2026 at 05:31:17PM +0800, Baolin Wang wrote:
>
>
> On 1/23/26 1:07 PM, Lance Yang wrote:
> >
> >
> > After collapse_single_pmd() returns, mmap_lock might have been released.
> > Between
> > that unlock and here, another thread could unmap/remap the VMA, making
> > the vma
> > pointer stale when we access vma->vm_file?
> >
> > Would it be safer to get the file reference before calling
> > collapse_single_pmd()?
> > Or we need to revalidate the VMA after getting the lock back?
> Good catch. I think we can move the filemap_write_and_wait_range() related
> logic into collapse_single_pmd(), after we get a file reference.

Good suggestion, is what Nico did in the suggested patch :) Agreed better there.

Thanks, Lorenzo

^ permalink raw reply

* Re: [PATCH v2 1/3] tracing: Rename `eval_map_wq` and export it for asynchronous use by other modules
From: Steven Rostedt @ 2026-01-26 14:36 UTC (permalink / raw)
  To: Yaxiong Tian
  Cc: axboe, mhiramat, mathieu.desnoyers, linux-block, linux-kernel,
	linux-trace-kernel
In-Reply-To: <20260126024316.297178-1-tianyaxiong@kylinos.cn>

On Mon, 26 Jan 2026 10:43:16 +0800
Yaxiong Tian <tianyaxiong@kylinos.cn> wrote:

Hi,

Some of your terminology is a little confusing. The subject says "modules"
but no module will use it (the term module means loadable code at runtime
into the Linux kernel). A better subject would be:


  tracing: Rename `eval_map_wq` and allow other parts of tracing use it


> The eval_map_work_func() function, though queued in eval_map_wq,
> holds the trace_event_sem read-write lock for a long time during
> kernel boot. This causes blocking issues for other functions.
> 
> Rename eval_map_wq to trace_init_wq and export it, thereby allowing

Also saying "export" for a function means something like "EXPORT_SYMBOLE()"
which again deals with Linux modules. A better term is "make it global".

> other modules to schedule work on this queue asynchronously and

 .. other parts of tracing ..

> avoiding blockage of the main boot thread.
> 
> Signed-off-by: Yaxiong Tian <tianyaxiong@kylinos.cn>

Other than that, this patch looks good.

-- Steve

> ---
>  kernel/trace/trace.c | 18 +++++++++---------
>  kernel/trace/trace.h |  2 ++
>  2 files changed, 11 insertions(+), 9 deletions(-)
> 
> diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
> index e18005807395..c61e30cb7339 100644
> --- a/kernel/trace/trace.c
> +++ b/kernel/trace/trace.c
> @@ -10774,7 +10774,7 @@ int tracing_init_dentry(void)
>  extern struct trace_eval_map *__start_ftrace_eval_maps[];
>  extern struct trace_eval_map *__stop_ftrace_eval_maps[];
>  
> -static struct workqueue_struct *eval_map_wq __initdata;
> +struct workqueue_struct *trace_init_wq __initdata;
>  static struct work_struct eval_map_work __initdata;
>  static struct work_struct tracerfs_init_work __initdata;
>  
> @@ -10790,15 +10790,15 @@ static int __init trace_eval_init(void)
>  {
>  	INIT_WORK(&eval_map_work, eval_map_work_func);
>  
> -	eval_map_wq = alloc_workqueue("eval_map_wq", WQ_UNBOUND, 0);
> -	if (!eval_map_wq) {
> -		pr_err("Unable to allocate eval_map_wq\n");
> +	trace_init_wq = alloc_workqueue("trace_init_wq", WQ_UNBOUND, 0);
> +	if (!trace_init_wq) {
> +		pr_err("Unable to allocate trace_init_wq\n");
>  		/* Do work here */
>  		eval_map_work_func(&eval_map_work);
>  		return -ENOMEM;
>  	}
>  
> -	queue_work(eval_map_wq, &eval_map_work);
> +	queue_work(trace_init_wq, &eval_map_work);
>  	return 0;
>  }
>  
> @@ -10807,8 +10807,8 @@ subsys_initcall(trace_eval_init);
>  static int __init trace_eval_sync(void)
>  {
>  	/* Make sure the eval map updates are finished */
> -	if (eval_map_wq)
> -		destroy_workqueue(eval_map_wq);
> +	if (trace_init_wq)
> +		destroy_workqueue(trace_init_wq);
>  	return 0;
>  }
>  
> @@ -10969,9 +10969,9 @@ static __init int tracer_init_tracefs(void)
>  	if (ret)
>  		return 0;
>  
> -	if (eval_map_wq) {
> +	if (trace_init_wq) {
>  		INIT_WORK(&tracerfs_init_work, tracer_init_tracefs_work_func);
> -		queue_work(eval_map_wq, &tracerfs_init_work);
> +		queue_work(trace_init_wq, &tracerfs_init_work);
>  	} else {
>  		tracer_init_tracefs_work_func(NULL);
>  	}
> diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
> index de4e6713b84e..e52f259f8945 100644
> --- a/kernel/trace/trace.h
> +++ b/kernel/trace/trace.h
> @@ -770,6 +770,8 @@ extern unsigned long nsecs_to_usecs(unsigned long nsecs);
>  
>  extern unsigned long tracing_thresh;
>  
> +extern struct workqueue_struct *trace_init_wq __initdata;
> +
>  /* PID filtering */
>  
>  bool trace_find_filtered_pid(struct trace_pid_list *filtered_pids,


^ permalink raw reply

* Re: [PATCH] tracing: kprobe-event: Return directly when dyn_event_list is empty
From: Steven Rostedt @ 2026-01-26 14:38 UTC (permalink / raw)
  To: sunliming
  Cc: mhiramat, mathieu.desnoyers, linux-kernel, linux-trace-kernel,
	sunliming
In-Reply-To: <78dbbd83-8de3-2031-6db7-036d0d8c11c5@linux.dev>

On Mon, 26 Jan 2026 15:17:28 +0800
sunliming <sunliming@linux.dev> wrote:

> Alternatively, could both optimization solutions coexist (as lock 
> contention may

Yes, the two are orthogonal to each other, and can go in on their own merit.

-- Steve

^ permalink raw reply

* Re: [PATCH mm-unstable v14 03/16] introduce collapse_single_pmd to unify khugepaged and madvise_collapse
From: Andrew Morton @ 2026-01-26 15:09 UTC (permalink / raw)
  To: Lorenzo Stoakes
  Cc: Lance Yang, Nico Pache, david, ziy, baolin.wang, Liam.Howlett,
	ryan.roberts, dev.jain, baohua, vbabka, rppt, surenb, mhocko,
	linux-trace-kernel, linux-doc, corbet, rostedt, mhiramat,
	mathieu.desnoyers, linux-kernel, matthew.brost, joshua.hahnjy,
	rakie.kim, byungchul, gourry, ying.huang, apopple, jannh,
	pfalcato, jackmanb, hannes, willy, peterx, wangkefeng.wang,
	usamaarif642, sunnanyong, vishal.moola, thomas.hellstrom, yang,
	kas, aarcange, raquini, anshuman.khandual, catalin.marinas, tiwai,
	will, dave.hansen, jack, cl, jglisse, zokeefe, rientjes, rdunlap,
	hughd, richard.weiyang, David Hildenbrand, linux-mm
In-Reply-To: <0e79a766-811d-477c-83ee-389db29d41bb@lucifer.local>

On Mon, 26 Jan 2026 11:40:21 +0000 Lorenzo Stoakes <lorenzo.stoakes@oracle.com> wrote:

> Andrew - when this goes into mm-new if there isn't a respin between, please
> drop all tags except any obviously sent re: the fix-patch.
> 

I've been believing this is next -rc1 material.  Was that mistaken?

^ permalink raw reply

* Re: [PATCH mm-unstable v14 03/16] introduce collapse_single_pmd to unify khugepaged and madvise_collapse
From: Lorenzo Stoakes @ 2026-01-26 15:18 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Lance Yang, Nico Pache, david, ziy, baolin.wang, Liam.Howlett,
	ryan.roberts, dev.jain, baohua, vbabka, rppt, surenb, mhocko,
	linux-trace-kernel, linux-doc, corbet, rostedt, mhiramat,
	mathieu.desnoyers, linux-kernel, matthew.brost, joshua.hahnjy,
	rakie.kim, byungchul, gourry, ying.huang, apopple, jannh,
	pfalcato, jackmanb, hannes, willy, peterx, wangkefeng.wang,
	usamaarif642, sunnanyong, vishal.moola, thomas.hellstrom, yang,
	kas, aarcange, raquini, anshuman.khandual, catalin.marinas, tiwai,
	will, dave.hansen, jack, cl, jglisse, zokeefe, rientjes, rdunlap,
	hughd, richard.weiyang, David Hildenbrand, linux-mm
In-Reply-To: <20260126070918.cbbd532f4a8813e8a188108a@linux-foundation.org>

On Mon, Jan 26, 2026 at 07:09:18AM -0800, Andrew Morton wrote:
> On Mon, 26 Jan 2026 11:40:21 +0000 Lorenzo Stoakes <lorenzo.stoakes@oracle.com> wrote:
>
> > Andrew - when this goes into mm-new if there isn't a respin between, please
> > drop all tags except any obviously sent re: the fix-patch.
> >
>
> I've been believing this is next -rc1 material.  Was that mistaken?

Yeah this isn't ready yet sorry. I did hope we could get this in this cycle but
there's too much to check (esp. given this change for isntance0 and we need more
time to stabilise it, so please keep this out of mm-(un)stable for now.

It's a really huge change to THP so we need to take our time with it.

So we're aiming for 6.21-rc1 / 7.1-rc1 or whatever deems it to be :)
i.e. next+1-rc1.

Cheers, Lorenzo

^ permalink raw reply

* Re: [PATCH v16 1/3] lib: Introduce hierarchical per-cpu counters
From: Mathieu Desnoyers @ 2026-01-26 16:34 UTC (permalink / raw)
  To: Michal Hocko
  Cc: Andrew Morton, linux-kernel, Paul E. McKenney, Steven Rostedt,
	Masami Hiramatsu, Dennis Zhou, Tejun Heo, Christoph Lameter,
	Martin Liu, David Rientjes, christian.koenig, Shakeel Butt,
	SeongJae Park, Johannes Weiner, Sweet Tea Dorminy,
	Lorenzo Stoakes, Liam R . Howlett, Mike Rapoport,
	Suren Baghdasaryan, Vlastimil Babka, Christian Brauner, Wei Yang,
	David Hildenbrand, Miaohe Lin, Al Viro, linux-mm,
	linux-trace-kernel, Yu Zhao, Roman Gushchin, Mateusz Guzik,
	Matthew Wilcox, Baolin Wang, Aboorva Devarajan
In-Reply-To: <aWped4MIi5i0Y7-R@tiehlicka>

On 2026-01-16 16:51, Michal Hocko wrote:
> On Wed 14-01-26 14:19:38, Mathieu Desnoyers wrote:
>> On 2026-01-14 11:41, Michal Hocko wrote:
>>>
>>> One thing you should probably mention here is the memory consumption of
>>> the structure.
>> Good point.
>>
>> The most important parts are the per-cpu counters and the tree items
>> which propagate the carry.
>>
>> In the proposed implementation, the per-cpu counters are allocated
>> within per-cpu data structures, so they end up using:
>>
>>    nr_possible_cpus * sizeof(unsigned long)
>>
>> In addition, the tree items are appended at the end of the mm_struct.
>> The size of those items is defined by the per_nr_cpu_order_config
>> table "nr_items" field.
>>
>> Each item is aligned on cacheline size (typically 64 bytes) to minimize
>> false sharing.
>>
>> Here is the footprint for a few nr_cpus on a 64-bit arch:
>>
>> nr_cpus     percpu counters (bytes)     nr_items       items size (bytes)     total (bytes)
>>    2                 16                     1                 64                    80
>>    4                 32                     3                192                   224
>>    8                 64                     7                448                   512
>>   64                 512                   21               1344                  1856
>> 128                1024                   21               1344                  2368
>> 256                2048                   37               2368                  4416
>> 512                4096                   73               4672                  8768
> 
> I assume this is nr_possible_cpus not NR_CPUS, right?

More precisely, this is nr_cpu_ids, at least for the nr_items.

percpu counters are effectively allocated for nr_possible_cpus, but we
need to allocate the internal items for nr_cpu_ids (based on the max
limits a cpumask would need). For the sake of keeping the table
easy to understand, I will use nr_cpu_ids for the first column.

I'll update the commit message.

> 
>> There are of course various trade offs we can make here. We can:
>>
>> * Increase the n-arity of the intermediate items to shrink the nr_items
>>    required for a given nr_cpus. This will increase contention of carry
>>    propagation across more cores.
>>
>> * Remove cacheline alignment of intermediate tree items. This will
>>    shrink the memory needed for tree items, but will increase false
>>    sharing.
>>
>> * Represent intermediate tree items on a byte rather than long.
>>    This further reduces the memory required for intermediate tree
>>    items, but further increases false sharing.
>>
>> * Represent per-cpu counters on bytes rather than long. This makes
>>    the "sum" operation trickier, because it needs to iterate on the
>>    intermediate carry propagation nodes as well and synchronize with
>>    ongoing "tree add" operations. It further reduces memory use.
>>
>> * Implement a custom strided allocator for intermediate items carry
>>    propagation bytes. This shares cachelines across different tree
>>    instances, keeping good locality. This ensures that all accesses
>>    from a given location in the machine topology touch the same
>>    cacheline for the various tree instances. This adds complexity,
>>    but provides compactness as well as minimal false-sharing.
>>
>> Compared to this, the upstream percpu counters use a 32-bit integer per-cpu
>> (4 bytes), and accumulate within a 64-bit global value.
>>
>> So yes, there is an extra memory footprint added by the current hpcc
>> implementation, but if it's an issue we have various options to consider
>> to reduce its footprint.
>>
>> Is it OK if I add this discussion to the commit message, or should it
>> be also added into the high level design doc within
>> Documentation/core-api/percpu-counter-tree.rst ?
> 
> I would mention them in both changelog and the documentation.
> 

OK, will do for v17.

Thanks,

Mathieu


-- 
Mathieu Desnoyers
EfficiOS Inc.
https://www.efficios.com

^ permalink raw reply

* Re: [PATCH v16 3/3] mm: Reduce latency of OOM killer task selection with 2-pass algorithm
From: Mathieu Desnoyers @ 2026-01-26 16:39 UTC (permalink / raw)
  To: Michal Hocko
  Cc: Andrew Morton, linux-kernel, Paul E. McKenney, Steven Rostedt,
	Masami Hiramatsu, Dennis Zhou, Tejun Heo, Christoph Lameter,
	Martin Liu, David Rientjes, christian.koenig, Shakeel Butt,
	SeongJae Park, Johannes Weiner, Sweet Tea Dorminy,
	Lorenzo Stoakes, Liam R . Howlett, Mike Rapoport,
	Suren Baghdasaryan, Vlastimil Babka, Christian Brauner, Wei Yang,
	David Hildenbrand, Miaohe Lin, Al Viro, linux-mm,
	linux-trace-kernel, Yu Zhao, Roman Gushchin, Mateusz Guzik,
	Matthew Wilcox, Baolin Wang, Aboorva Devarajan
In-Reply-To: <aWpfbSJe5vREzzyd@tiehlicka>

On 2026-01-16 16:55, Michal Hocko wrote:
> On Wed 14-01-26 14:36:44, Mathieu Desnoyers wrote:
>> On 2026-01-14 12:06, Michal Hocko wrote:
>>> On Wed 14-01-26 09:59:15, Mathieu Desnoyers wrote:
> [...]
> Thanks to those clarifications
>   
>>> My overall impression is that the implementation is really involved and
>>> at this moment I do not really see a big benefit of all the complexity.
>>
>> Note that we can get the proc ABI RSS accuracy improvements with the
>> previous 2 patches without this 2-pass algo. Do you see more value in
>> the RSS accuracy improvements than in the oom killer latency reduction ?
> 
> Yes, TBH I do not see oom latency as a big problem. As already mention
> this is a slow path and we are not talking about a huge latency anyway.
> proc numbers are much more sensitive to latency as they are regularly
> read by user space tools and accuracy for those matters as well (being
> off by 100s MB or GBs is simply making those numbers completely bogus).

It makes sense.

>   
>>> It would help to explicitly mention what is the the overall imprecision
>>> of the oom victim selection with the new data structure (maybe this is
>>> good enough[*]). What if we go with exact precision with the new data
>>> structure comparing to the original pcp counters.
>>
>> Do you mean comparing using approximate sums with the new data
>> structure (which has a bounded accuracy of O(nr_cpus*log(nr_cpus)))
>> compared to the old data structure which had an inaccuracy of
>> O(nr_cpus^2) ? So if the inaccuracy provided by the new data structure
>> is good enough for OOM task selection, we could go from precise sum
>> back to an approximation and just use that with the new data
>> structure.
> 
> Exactly!
OK, so based on your feedback, I plan to remove this 2-pass algo
from the series, and simply keep using the precise sum for the OOM
killer. If people complain about its latency, then we can eventually
use the approximation provided by the hierarchical counters. But let's
wait until someone asks for it rather than add this complexity when
there is no need.

The hierarchical counters are still useful as they increase the
accuracy of approximations exported through /proc.

How does that sound ?

Thanks,

Mathieu


-- 
Mathieu Desnoyers
EfficiOS Inc.
https://www.efficios.com

^ permalink raw reply

* Re: [RESEND][PATCH 3/5] perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
From: Steven Rostedt @ 2026-01-26 16:50 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: linux-kernel, linux-trace-kernel, linux-perf-users,
	Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Namhyung Kim, Alexander Shishkin, Jiri Olsa, Ian Rogers,
	Adrian Hunter, Liang, Kan, Thomas Gleixner
In-Reply-To: <0d877e6f-41a7-4724-875d-0b0a27b8a545@roeck-us.net>

On Wed, 12 Nov 2025 19:11:15 -0800
Guenter Roeck <linux@roeck-us.net> wrote:

> Hi Steven,

Hi Guenter,

Somehow this got filed away in my archive without me seeing it.

> 
> On Wed, Aug 20, 2025 at 02:03:41PM -0400, Steven Rostedt wrote:
> > From: Steven Rostedt <rostedt@goodmis.org>
> > 
> > To determine if a task is a kernel thread or not, it is more reliable to
> > use (current->flags & (PF_KTHREAD|PF_USER_WORKERi)) than to rely on
> > current->mm being NULL.  That is because some kernel tasks (io_uring
> > helpers) may have a mm field.
> > 
> > Link: https://lore.kernel.org/linux-trace-kernel/20250424163607.GE18306@noisy.programming.kicks-ass.net/
> > Link: https://lore.kernel.org/all/20250624130744.602c5b5f@batman.local.home/
> > 
> > Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
> > ---
> >  kernel/events/callchain.c | 6 +++---
> >  kernel/events/core.c      | 4 ++--
> >  2 files changed, 5 insertions(+), 5 deletions(-)
> > 
> > diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
> > index cd0e3fc7ed05..5982d18f169b 100644
> > --- a/kernel/events/callchain.c
> > +++ b/kernel/events/callchain.c
> > @@ -246,10 +246,10 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,
> >  
> >  	if (user && !crosstask) {
> >  		if (!user_mode(regs)) {
> > -			if  (current->mm)
> > -				regs = task_pt_regs(current);
> > -			else
> > +			if (current->flags & (PF_KTHREAD | PF_USER_WORKER))
> >  				regs = NULL;
> > +			else
> > +				regs = task_pt_regs(current);
> >  		}
> >  
> >  		if (regs) {
> > diff --git a/kernel/events/core.c b/kernel/events/core.c
> > index bade8e0fced7..f880cec0c980 100644
> > --- a/kernel/events/core.c
> > +++ b/kernel/events/core.c
> > @@ -7446,7 +7446,7 @@ static void perf_sample_regs_user(struct perf_regs *regs_user,
> >  	if (user_mode(regs)) {
> >  		regs_user->abi = perf_reg_abi(current);
> >  		regs_user->regs = regs;
> > -	} else if (!(current->flags & PF_KTHREAD)) {
> > +	} else if (!(current->flags & (PF_KTHREAD | PF_USER_WORKER))) {
> >  		perf_get_regs_user(regs_user, regs);
> >  	} else {
> >  		regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
> > @@ -8086,7 +8086,7 @@ static u64 perf_virt_to_phys(u64 virt)
> >  		 * Try IRQ-safe get_user_page_fast_only first.
> >  		 * If failed, leave phys_addr as 0.
> >  		 */
> > -		if (current->mm != NULL) {
> > +		if (!(current->flags & (PF_KTHREAD | PF_USER_WORKER))) {  
> 
> Subsequent code uses current->mm. This triggers a crash when running a page
> table stress test. See below for details. I have seen the crash in 6.12.57
> and 6.18-rc5.

Hmm, that should not happen. But obvious it is. Can you add this:

diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
index 1f6589578703..ff201098e5e5 100644
--- a/kernel/events/callchain.c
+++ b/kernel/events/callchain.c
@@ -248,6 +248,8 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,
 		if (!user_mode(regs)) {
 			if (current->flags & (PF_KTHREAD | PF_USER_WORKER))
 				goto exit_put;
+			if (WARN_ONCE(!current->mm, "Bad flags %x", current->flags))
+				goto exit_put;
 			regs = task_pt_regs(current);
 		}
 

I'd like to see what current->flags are when ->mm is NULL.

Thanks!

-- Steve

^ permalink raw reply related

* Re: [RESEND][PATCH 3/5] perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
From: Steven Rostedt @ 2026-01-26 17:05 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: linux-kernel, linux-trace-kernel, linux-perf-users,
	Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Namhyung Kim, Alexander Shishkin, Jiri Olsa, Ian Rogers,
	Adrian Hunter, Liang, Kan, Thomas Gleixner
In-Reply-To: <0d877e6f-41a7-4724-875d-0b0a27b8a545@roeck-us.net>

On Wed, 12 Nov 2025 19:11:15 -0800
Guenter Roeck <linux@roeck-us.net> wrote:

> [  120.334908] BUG: kernel NULL pointer dereference, address: 0000000000000078
> [  120.341901] #PF: supervisor read access in kernel mode
> [  120.347055] #PF: error_code(0x0000) - not-present page
> [  120.352208] PGD 0 P4D 0
> [  120.354750] Oops: Oops: 0000 [#1] SMP NOPTI
> [  120.358946] CPU: 36 UID: 0 PID: 14127 Comm: page_table_stre Tainted: G S         O        6.18.0-smp-DEV #2 NONE
> [  120.369242] Tainted: [S]=CPU_OUT_OF_SPEC, [O]=OOT_MODULE
> [  120.374568] Hardware name: Google LLC Indus/Indus_QC_03, BIOS 30.116.4 08/29/2025
> [  120.382075] RIP: 0010:gup_fast_fallback+0x150/0xb60
> [  120.386977] Code: d0 c9 8b 48 89 84 24 a0 00 00 00 48 8b 80 30 05 00 00 0f b6 0d 0d 6b 1a 01 49 89 f8 49 d3 e8 41 81 e0 ff 01 00 00 41 c1 e0
>  03 <4c> 03 40 78 4c 8d 5b ff 44 89 c8 83 e0 01 48 8d 04 45 05 00 00 00
> [  120.405809] RSP: 0018:ffffa32be5f9b7a0 EFLAGS: 00010006
> [  120.411051] RAX: 0000000000000000 RBX: 00007f0f57dfd000 RCX: 0000000000000027
> [  120.418210] RDX: 0000000000000046 RSI: 0000000000000001 RDI: 00007f0f57dfc000
> [  120.425368] RBP: 0000000000000000 R08: 00000000000007f0 R09: 0000000000100002
> [  120.432526] R10: ffffa32be5f9b8c8 R11: 0000000000000000 R12: 00007f0f57dfc6c0
> [  120.439683] R13: ffff99b44dd7c800 R14: 00000000fffffff2 R15: 00000000000800c3
> [  120.446842] FS:  0000000000000000(0000) GS:ffff9a127357b000(0000) knlGS:0000000000000000
> [  120.454956] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [  120.460721] CR2: 0000000000000078 CR3: 000000512d03e006 CR4: 00000000007706f0
> [  120.467879] PKRU: 55555554
> [  120.470592] Call Trace:
> [  120.473045]  <TASK>
> [  120.475152]  perf_prepare_sample+0x77b/0x910
> [  120.479445]  perf_event_output+0x35/0x100
> [  120.483467]  intel_pmu_drain_pebs_nhm+0x570/0x750
> [  120.488198]  intel_pmu_pebs_sched_task+0x74/0x80
> [  120.492839]  ? __put_partials+0xd6/0x130
> [  120.496775]  ? __mt_destroy+0x3f/0x80
> [  120.500451]  ? put_cpu_partial+0x9b/0xc0
> [  120.504384]  ? __slab_free+0x249/0x320
> [  120.508144]  ? refill_obj_stock+0x120/0x1a0
> [  120.512341]  ? __mt_destroy+0x3f/0x80
> [  120.516013]  ? kfree+0x2ca/0x390
> [  120.519254]  ? update_load_avg+0x1c8/0x7d0
> [  120.523364]  ? update_entity_lag+0xf6/0x110
> [  120.527560]  intel_pmu_sched_task+0x1d/0x30
> [  120.531755]  perf_pmu_sched_task+0xf2/0x1a0
> [  120.535952]  __perf_event_task_sched_out+0x3f/0x1f0
> [  120.540844]  ? pick_next_task_fair+0x3e/0x2a0
> [  120.545214]  __schedule+0xad0/0xb40
> [  120.548715]  do_task_dead+0x48/0xa0

Ah, this is called at do_task_dead()

I guess we need to also test for !current->mm because the flags set for an
exiting task is done when we can still do callchains. Thus, the only way to
know if it is safe to do a callchain when a task is exiting is via task->mm
and not task->flags :-/

-- Steve



> [  120.552215]  do_exit+0x734/0x920
> [  120.555463]  ? do_exit+0x9/0x920
> [  120.558699]  do_group_exit+0x85/0x90
> [  120.562284]  __x64_sys_exit_group+0x17/0x20
> [  120.566478]  x64_sys_call+0x21f7/0x2200
> [  120.570327]  do_syscall_64+0x6f/0x940
> [  120.574001]  ? clear_bhb_loop+0x50/0xa0
> [  120.577849]  entry_SYSCALL_64_after_hwframe+0x76/0x7e
> [  120.582915] RIP: 0033:0x7f0f5a0d2c48
> [  120.586501] Code: Unable to access opcode bytes at 0x7f0f5a0d2c1e.
> [  120.592700] RSP: 002b:00007f0f57dfcec8 EFLAGS: 00000207 ORIG_RAX: 00000000000000e7
> [  120.600294] RAX: ffffffffffffffda RBX: 00007f0f57dfd700 RCX: 00007f0f5a0d2c48
> [  120.607452] RDX: 00007f0f57dfd660 RSI: 0000000000000000 RDI: 0000000000000000
> [  120.614607] RBP: 00007f0f57dfcef0 R08: 00007f0f57dfd700 R09: 00007f0f57dfd700
> [  120.621765] R10: 00007f0f5a17a6c0 R11: 0000000000000207 R12: 00007f0f57dfd9d0
> [  120.628923] R13: 00007ffc64840aa6 R14: 00007f0f57dfdd1c R15: 00007f0f57dfcfc0
> [  120.636081]  </TASK>
> [  120.638272] Modules linked in: vfat fat i2c_mux_pca954x i2c_mux spidev cdc_acm xhci_pci xhci_hcd gq(O) sha3_generic
> [  120.649976] gsmi: Log Shutdown Reason 0x03
> [  120.654086] CR2: 0000000000000078
> [  120.657409] ---[ end trace 0000000000000000 ]---

^ permalink raw reply

* Re: [RESEND][PATCH 3/5] perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
From: Steven Rostedt @ 2026-01-26 17:18 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: linux-kernel, linux-trace-kernel, linux-perf-users,
	Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Namhyung Kim, Alexander Shishkin, Jiri Olsa, Ian Rogers,
	Adrian Hunter, Thomas Gleixner
In-Reply-To: <20260126120553.2fa79048@gandalf.local.home>

On Mon, 26 Jan 2026 12:05:53 -0500
Steven Rostedt <rostedt@kernel.org> wrote:

> I guess we need to also test for !current->mm because the flags set for an
> exiting task is done when we can still do callchains. Thus, the only way to
> know if it is safe to do a callchain when a task is exiting is via task->mm
> and not task->flags :-/

Can you test this patch?

-- Steve

diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
index 1f6589578703..c82d61d73bd8 100644
--- a/kernel/events/callchain.c
+++ b/kernel/events/callchain.c
@@ -246,7 +246,14 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,
 
 	if (user && !crosstask) {
 		if (!user_mode(regs)) {
-			if (current->flags & (PF_KTHREAD | PF_USER_WORKER))
+			/*
+			 * Testing current->mm is not enough as some kernel threads
+			 * may have one set. But testing the flags is not enough
+			 * either as this can be called after a user task
+			 * frees its mm just before it exits.
+			 */
+			if (!current->mm ||
+			    (current->flags & (PF_KTHREAD | PF_USER_WORKER)))
 				goto exit_put;
 			regs = task_pt_regs(current);
 		}

^ permalink raw reply related

* Re: [RESEND][PATCH 3/5] perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
From: Guenter Roeck @ 2026-01-26 17:29 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, linux-trace-kernel, linux-perf-users,
	Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Namhyung Kim, Alexander Shishkin, Jiri Olsa, Ian Rogers,
	Adrian Hunter, Thomas Gleixner
In-Reply-To: <20260126121803.4a90c959@gandalf.local.home>

On 1/26/26 09:18, Steven Rostedt wrote:
> On Mon, 26 Jan 2026 12:05:53 -0500
> Steven Rostedt <rostedt@kernel.org> wrote:
> 
>> I guess we need to also test for !current->mm because the flags set for an
>> exiting task is done when we can still do callchains. Thus, the only way to
>> know if it is safe to do a callchain when a task is exiting is via task->mm
>> and not task->flags :-/
> 
> Can you test this patch?
> 

Sure, though we had dropped the offending patch from the LTS backport, so that
will take a bit.

Guenter

> -- Steve
> 
> diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
> index 1f6589578703..c82d61d73bd8 100644
> --- a/kernel/events/callchain.c
> +++ b/kernel/events/callchain.c
> @@ -246,7 +246,14 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,
>   
>   	if (user && !crosstask) {
>   		if (!user_mode(regs)) {
> -			if (current->flags & (PF_KTHREAD | PF_USER_WORKER))
> +			/*
> +			 * Testing current->mm is not enough as some kernel threads
> +			 * may have one set. But testing the flags is not enough
> +			 * either as this can be called after a user task
> +			 * frees its mm just before it exits.
> +			 */
> +			if (!current->mm ||
> +			    (current->flags & (PF_KTHREAD | PF_USER_WORKER)))
>   				goto exit_put;
>   			regs = task_pt_regs(current);
>   		}


^ permalink raw reply

* Re: [PATCH v16 3/3] mm: Reduce latency of OOM killer task selection with 2-pass algorithm
From: Michal Hocko @ 2026-01-26 17:47 UTC (permalink / raw)
  To: Mathieu Desnoyers
  Cc: Andrew Morton, linux-kernel, Paul E. McKenney, Steven Rostedt,
	Masami Hiramatsu, Dennis Zhou, Tejun Heo, Christoph Lameter,
	Martin Liu, David Rientjes, christian.koenig, Shakeel Butt,
	SeongJae Park, Johannes Weiner, Sweet Tea Dorminy,
	Lorenzo Stoakes, Liam R . Howlett, Mike Rapoport,
	Suren Baghdasaryan, Vlastimil Babka, Christian Brauner, Wei Yang,
	David Hildenbrand, Miaohe Lin, Al Viro, linux-mm,
	linux-trace-kernel, Yu Zhao, Roman Gushchin, Mateusz Guzik,
	Matthew Wilcox, Baolin Wang, Aboorva Devarajan
In-Reply-To: <0079bc61-5655-4677-a421-1a61f4c52d59@efficios.com>

On Mon 26-01-26 11:39:33, Mathieu Desnoyers wrote:
> On 2026-01-16 16:55, Michal Hocko wrote:
> > On Wed 14-01-26 14:36:44, Mathieu Desnoyers wrote:
> > > On 2026-01-14 12:06, Michal Hocko wrote:
> > > > On Wed 14-01-26 09:59:15, Mathieu Desnoyers wrote:
> > [...]
> > Thanks to those clarifications
> > > > My overall impression is that the implementation is really involved and
> > > > at this moment I do not really see a big benefit of all the complexity.
> > > 
> > > Note that we can get the proc ABI RSS accuracy improvements with the
> > > previous 2 patches without this 2-pass algo. Do you see more value in
> > > the RSS accuracy improvements than in the oom killer latency reduction ?
> > 
> > Yes, TBH I do not see oom latency as a big problem. As already mention
> > this is a slow path and we are not talking about a huge latency anyway.
> > proc numbers are much more sensitive to latency as they are regularly
> > read by user space tools and accuracy for those matters as well (being
> > off by 100s MB or GBs is simply making those numbers completely bogus).
> 
> It makes sense.
> 
> > > > It would help to explicitly mention what is the the overall imprecision
> > > > of the oom victim selection with the new data structure (maybe this is
> > > > good enough[*]). What if we go with exact precision with the new data
> > > > structure comparing to the original pcp counters.
> > > 
> > > Do you mean comparing using approximate sums with the new data
> > > structure (which has a bounded accuracy of O(nr_cpus*log(nr_cpus)))
> > > compared to the old data structure which had an inaccuracy of
> > > O(nr_cpus^2) ? So if the inaccuracy provided by the new data structure
> > > is good enough for OOM task selection, we could go from precise sum
> > > back to an approximation and just use that with the new data
> > > structure.
> > 
> > Exactly!
> OK, so based on your feedback, I plan to remove this 2-pass algo
> from the series, and simply keep using the precise sum for the OOM
> killer. If people complain about its latency, then we can eventually
> use the approximation provided by the hierarchical counters. But let's
> wait until someone asks for it rather than add this complexity when
> there is no need.
> 
> The hierarchical counters are still useful as they increase the
> accuracy of approximations exported through /proc.
> 
> How does that sound ?

Works for me.

Thanks!
-- 
Michal Hocko
SUSE Labs

^ permalink raw reply

* [PATCH] tracing: Remove duplicate ENABLE_EVENT_STR and  DISABLE_EVENT_STR macros
From: Steven Rostedt @ 2026-01-26 18:00 UTC (permalink / raw)
  To: LKML, Linux Trace Kernel; +Cc: Masami Hiramatsu, Mathieu Desnoyers, Tom Zanussi

From: Steven Rostedt <rostedt@goodmis.org>

The macros ENABLE_EVENT_STR and DISABLE_EVENT_STR were added to trace.h so
that more than one file can have access to them, but was never removed
from their original location. Remove the duplicates.

Fixes: d0bad49bb0a09 ("tracing: Add enable_hist/disable_hist triggers")
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
 kernel/trace/trace_events.c | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 166b0d59be3d..af6d1fe5cab7 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -4113,11 +4113,6 @@ void trace_put_event_file(struct trace_event_file *file)
 EXPORT_SYMBOL_GPL(trace_put_event_file);
 
 #ifdef CONFIG_DYNAMIC_FTRACE
-
-/* Avoid typos */
-#define ENABLE_EVENT_STR	"enable_event"
-#define DISABLE_EVENT_STR	"disable_event"
-
 struct event_probe_data {
 	struct trace_event_file	*file;
 	unsigned long			count;
-- 
2.51.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox