* [PATCH] rtla: Also link in ctype.c
From: Bastian Blank @ 2026-07-05 10:49 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, linux-trace-kernel, linux-kernel
rtla started to only link parts of the tools library. It now misses the
ctype information used by all the related string operations. Just add
another single file to make it build again.
Signed-off-by: Bastian Blank <waldi@debian.org>
---
tools/tracing/rtla/Makefile | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/tools/tracing/rtla/Makefile b/tools/tracing/rtla/Makefile
index 60a102538988..387bc6cc18f0 100644
--- a/tools/tracing/rtla/Makefile
+++ b/tools/tracing/rtla/Makefile
@@ -45,6 +45,9 @@ else
LIB_OUTPUT = $(CURDIR)/lib
endif
+LIB_CTYPE = $(LIB_OUTPUT)/ctype.o
+LIB_CTYPE_SRC = $(srctree)/tools/lib/ctype.c
+
LIB_STRING = $(LIB_OUTPUT)/string.o
LIB_STRING_SRC = $(srctree)/tools/lib/string.c
@@ -117,12 +120,12 @@ tests/bpf/bpf_action_map.o: tests/bpf/bpf_action_map.c
$(Q)echo "BPF skeleton support is disabled, skipping tests/bpf/bpf_action_map.o"
endif
-$(RTLA): $(RTLA_IN) $(LIBSUBCMD) $(LIB_STRING) $(LIB_STR_ERROR_R)
- $(QUIET_LINK)$(CC) $(LDFLAGS) -o $(RTLA) $(RTLA_IN) $(LIBSUBCMD) $(LIB_STRING) $(LIB_STR_ERROR_R) $(EXTLIBS)
+$(RTLA): $(RTLA_IN) $(LIBSUBCMD) $(LIB_CTYPE) $(LIB_STRING) $(LIB_STR_ERROR_R)
+ $(QUIET_LINK)$(CC) $(LDFLAGS) -o $(RTLA) $(RTLA_IN) $(LIBSUBCMD) $(LIB_CTYPE) $(LIB_STRING) $(LIB_STR_ERROR_R) $(EXTLIBS)
-static: $(RTLA_IN) $(LIBSUBCMD) $(LIB_STRING) $(LIB_STR_ERROR_R)
+static: $(RTLA_IN) $(LIBSUBCMD) $(LIB_CTYPE) $(LIB_STRING) $(LIB_STR_ERROR_R)
$(eval LDFLAGS += -static)
- $(QUIET_LINK)$(CC) -static $(LDFLAGS) -o $(RTLA)-static $(RTLA_IN) $(LIBSUBCMD) $(LIB_STRING) $(LIB_STR_ERROR_R) $(EXTLIBS)
+ $(QUIET_LINK)$(CC) -static $(LDFLAGS) -o $(RTLA)-static $(RTLA_IN) $(LIBSUBCMD) $(LIB_CTYPE) $(LIB_STRING) $(LIB_STR_ERROR_R) $(EXTLIBS)
rtla.%: fixdep FORCE
make -f $(srctree)/tools/build/Makefile.build dir=. $@
@@ -150,6 +153,9 @@ $(LIB_STR_ERROR_R): $(LIB_STR_ERROR_R_SRC) | $(LIB_OUTPUT)
$(LIB_STRING): $(LIB_STRING_SRC) | $(LIB_OUTPUT)
$(QUIET_CC)$(CC) $(CFLAGS) -c -o $@ $<
+$(LIB_CTYPE): $(LIB_CTYPE_SRC) | $(LIB_OUTPUT)
+ $(QUIET_CC)$(CC) $(CFLAGS) -c -o $@ $<
+
libsubcmd-clean:
$(call QUIET_CLEAN, libsubcmd)
$(Q)$(RM) -r -- $(LIBSUBCMD_OUTPUT)
--
2.53.0
^ permalink raw reply related
* Re: [RFC] xdp: add device context to bpf_xdp_link_attach_failed tracepoint
From: Masashi Honma @ 2026-07-05 2:11 UTC (permalink / raw)
To: Leon Hwang
Cc: netdev, bpf, linux-trace-kernel, ast, daniel, kuba, hawk, andrii,
rostedt, mhiramat, edumazet, pabeni, linux-kernel
In-Reply-To: <216969a9-3584-4dc8-9e23-50fc18b31725@linux.dev>
2026年7月4日(土) 22:28 Leon Hwang <leon.hwang@linux.dev>:
> Probably, you can get the 'extack->_msg' by tracing dev_xdp_attach using
> kprobe+kretprobe or kprobe.session, if the extack is not NULL.
Thanks, that's a nice pointer -- dev_xdp_attach() has both the net_device
(so the ifindex, which lets us correlate a failure to a specific attach)
and the extack, and it avoids depending on the tracepoint you want to
retire.
The tradeoff is that dev_xdp_attach() is a static internal function, so a
probe on it can break across kernels (inlining/signature changes). For a
best-effort error message that's tolerable with a graceful fallback, but
it's a maintenance cost on our side.
Since this is ultimately just an error-message improvement, and your
in-band BPF_LINK_CREATE work would solve it cleanly for all link types, I
think we'd lean toward waiting for that rather than adding an internal
kprobe to Cilium. Do you have a rough timeline for the BPF_LINK_CREATE
series? That would help us decide whether a stopgap is worth it.
Regards,
Masashi Honma.
^ permalink raw reply
* [PATCH 4/4] kunit: add test for ref_trace_final_put
From: Eugene Mavick via B4 Relay @ 2026-07-05 1:20 UTC (permalink / raw)
To: Will Deacon, Peter Zijlstra, Boqun Feng, Mark Rutland, Gary Guo,
Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Andrew Morton, Dennis Zhou, Tejun Heo, Christoph Lameter
Cc: linux-kernel, linux-trace-kernel, linux-mm, Eugene Mavick
In-Reply-To: <20260705-refcount-final-put-trace-v1-0-0ae936edb750@mavick.dev>
From: Eugene Mavick <m@mavick.dev>
Add a KUnit test suite for the ref_trace_final_put tracepoint.
The test registers a probe function and triggers both refcount_t and
percpu_ref final put paths, verifying that the tracepoint fires
correctly and that the recorded fields match expected values.
Signed-off-by: Eugene Mavick <m@mavick.dev>
---
MAINTAINERS | 1 +
lib/Kconfig | 10 ++++
lib/tests/Makefile | 1 +
lib/tests/ref_trace_kunit.c | 138 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 150 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 8dab37726b9d..7c387ed746ee 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4213,6 +4213,7 @@ F: include/*/atomic*.h
F: include/linux/ref_trace.h
F: include/linux/refcount.h
F: lib/ref_trace.h
+F: lib/tests/ref_trace_kunit.c
F: scripts/atomic/
F: rust/kernel/sync/atomic.rs
F: rust/kernel/sync/atomic/
diff --git a/lib/Kconfig b/lib/Kconfig
index 00a9509636c1..c29b2ccb3c31 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -52,6 +52,16 @@ config PACKING_KUNIT_TEST
When in doubt, say N.
+config REF_TRACE_KUNIT_TEST
+ bool "ref_trace kunit test" if !KUNIT_ALL_TESTS
+ depends on KUNIT && FTRACE
+ default KUNIT_ALL_TESTS
+ help
+ This option enables the KUnit test suite for the ref_trace_final_put
+ tracepoint.
+
+ If unsure, say N
+
config BITREVERSE
tristate
diff --git a/lib/tests/Makefile b/lib/tests/Makefile
index 7e9c2fa52e35..828a030ad8c7 100644
--- a/lib/tests/Makefile
+++ b/lib/tests/Makefile
@@ -57,5 +57,6 @@ obj-$(CONFIG_USERCOPY_KUNIT_TEST) += usercopy_kunit.o
obj-$(CONFIG_UTIL_MACROS_KUNIT) += util_macros_kunit.o
obj-$(CONFIG_RATELIMIT_KUNIT_TEST) += test_ratelimit.o
obj-$(CONFIG_UUID_KUNIT_TEST) += uuid_kunit.o
+obj-$(CONFIG_REF_TRACE_KUNIT_TEST) += ref_trace_kunit.o
obj-$(CONFIG_TEST_RUNTIME_MODULE) += module/
diff --git a/lib/tests/ref_trace_kunit.c b/lib/tests/ref_trace_kunit.c
new file mode 100644
index 000000000000..2ece6c840fe0
--- /dev/null
+++ b/lib/tests/ref_trace_kunit.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <kunit/test.h>
+#include <linux/wait_bit.h>
+#include <linux/instruction_pointer.h>
+#include <linux/kallsyms.h>
+#include <linux/percpu-refcount.h>
+#include <linux/refcount.h>
+#include <trace/events/ref_trace.h>
+
+struct data {
+ unsigned long caller;
+ const char *fn;
+ const void *obj;
+ int *flag;
+ struct kunit *test;
+};
+
+struct data refc_chk;
+struct data pcpu_chk;
+
+//called when tracepoint fires
+static void probe(
+ void *ignore,
+ unsigned long caller,
+ const char *fn,
+ const void *obj)
+{
+ struct data *chk_val;
+
+ char func_name[KSYM_SYMBOL_LEN];
+
+ sprint_symbol_no_offset(func_name, caller);
+
+ if (!strcmp(func_name, "test_refcount")) {
+ chk_val = &refc_chk;
+ KUNIT_EXPECT_FALSE(chk_val->test, memcmp(obj, chk_val->obj, sizeof(refcount_t)));
+ } else if (!strcmp(func_name, "test_percpu")) {
+ chk_val = &pcpu_chk;
+ KUNIT_EXPECT_FALSE(chk_val->test, memcmp(
+ obj, chk_val->obj, sizeof(struct percpu_ref)));
+ } else {
+ //non test function origin trace events
+ return;
+ }
+
+ struct kunit *test = chk_val->test;
+ int *flag = chk_val->flag;
+
+ //ensure past flag writes are done before reading
+ KUNIT_EXPECT_EQ(test, 1, smp_load_acquire(flag));
+ KUNIT_EXPECT_EQ(test, caller, chk_val->caller);
+
+ smp_store_release(flag, 0); //signal probe completion
+}
+
+
+
+static void test_refcount(struct kunit *test)
+{
+ refcount_t refc;
+ int flag_addr = 0;
+
+ refc_chk.caller = (unsigned long)&test_refcount;
+ refc_chk.fn = "__refcount_sub_and_test";
+ refc_chk.obj = &refc;
+ refc_chk.flag = &flag_addr;
+ refc_chk.test = test;
+
+ int *flag = refc_chk.flag;
+
+ KUNIT_EXPECT_FALSE(test, register_trace_ref_trace_final_put(probe, NULL));
+
+ refcount_set(&refc, 2);
+
+ KUNIT_EXPECT_FALSE(test, refcount_dec_and_test(&refc));
+
+ smp_store_release(flag, 1); //signal final put can happen
+
+ KUNIT_EXPECT_TRUE(test, refcount_dec_and_test(&refc));
+
+ wait_var_event(flag, smp_load_acquire(flag)); //wait for probe completion
+ unregister_trace_ref_trace_final_put(probe, NULL);
+}
+
+static void dummy_release(struct percpu_ref *ref) {}
+
+static void test_percpu(struct kunit *test)
+{
+ struct percpu_ref pcpu_ref;
+
+ int flag_addr = 1;
+
+ pcpu_chk.caller = (unsigned long)&test_percpu;
+ pcpu_chk.fn = "percpu_ref_put_many";
+ pcpu_chk.obj = &pcpu_ref;
+ pcpu_chk.flag = &flag_addr;
+ pcpu_chk.test = test;
+
+ int *flag = pcpu_chk.flag;
+
+ KUNIT_EXPECT_FALSE(test, register_trace_ref_trace_final_put(probe, NULL));
+
+ KUNIT_EXPECT_FALSE(test, percpu_ref_init(&pcpu_ref, dummy_release, 0, GFP_KERNEL));
+
+ percpu_ref_get(&pcpu_ref);
+ percpu_ref_get(&pcpu_ref);
+
+ percpu_ref_put(&pcpu_ref);
+ percpu_ref_put(&pcpu_ref);
+
+ percpu_ref_switch_to_atomic_sync(&pcpu_ref);
+
+ smp_store_release(flag, 1); //signal final put can happen
+
+ percpu_ref_put(&pcpu_ref);
+
+ wait_var_event(flag, smp_load_acquire(flag)); //wait for probe completion
+ unregister_trace_ref_trace_final_put(probe, NULL);
+ percpu_ref_exit(&pcpu_ref);
+}
+
+static struct kunit_case __refdata ref_trace_test_cases[] = {
+ KUNIT_CASE(test_refcount),
+ KUNIT_CASE(test_percpu),
+ {}
+};
+
+static struct kunit_suite ref_trace_test_suite = {
+ .name = "ref-trace",
+ .test_cases = ref_trace_test_cases,
+};
+
+kunit_test_suites(&ref_trace_test_suite);
+
+MODULE_AUTHOR("Eugene Mavick <m@mavick.dev>");
+MODULE_DESCRIPTION("KUnit test for ref_trace");
+MODULE_LICENSE("GPL");
--
2.51.2
^ permalink raw reply related
* [PATCH 0/4] tracing: add ref_trace_final_put tracing
From: Eugene Mavick via B4 Relay @ 2026-07-05 1:20 UTC (permalink / raw)
To: Will Deacon, Peter Zijlstra, Boqun Feng, Mark Rutland, Gary Guo,
Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Andrew Morton, Dennis Zhou, Tejun Heo, Christoph Lameter
Cc: linux-kernel, linux-trace-kernel, linux-mm, Eugene Mavick
When debugging use-after-free(UAF) bugs, knowing when the object reaches
0 references and enters final release can significantly aide the
debugging process.
There is currently no universal way to trace this information.
This patches traces the final puts in the most widely used refcounting
implementations, refcount_t(and thus kref which uses it), and
percpu-ref.
The tracepoint records three fields:
- caller: function that called the refcounting
function(refcount_sub_and_test, percpu_ref_put_many)
- fn: refcounting function(eg refcount_sub_and_test)
- obj: refcount object(struct percpu_ref, refcount_t)
Signed-off-by: Eugene Mavick <m@mavick.dev>
---
Eugene Mavick (4):
tracing: add ref_trace_final_put tracepoint
refcount: add ref_trace_final_put tracepoint
percpu-refcount: add ref_trace_final_put trace
kunit: add test for ref_trace_final_put
MAINTAINERS | 3 +
include/linux/percpu-refcount.h | 5 +-
include/linux/ref_trace.h | 26 ++++++++
include/linux/refcount.h | 2 +
include/trace/events/ref_trace.h | 46 +++++++++++++
lib/Kconfig | 10 +++
lib/Makefile | 2 +
lib/ref_trace.c | 12 ++++
lib/tests/Makefile | 1 +
lib/tests/ref_trace_kunit.c | 138 +++++++++++++++++++++++++++++++++++++++
10 files changed, 244 insertions(+), 1 deletion(-)
---
base-commit: df685633c3dbc67441cc86f1c3fee58de4652ba2
change-id: 20260624-refcount-final-put-trace-49bd7c39bd5a
Best regards,
--
Eugene Mavick <m@mavick.dev>
^ permalink raw reply
* [PATCH 1/4] tracing: add ref_trace_final_put tracepoint
From: Eugene Mavick via B4 Relay @ 2026-07-05 1:20 UTC (permalink / raw)
To: Will Deacon, Peter Zijlstra, Boqun Feng, Mark Rutland, Gary Guo,
Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Andrew Morton, Dennis Zhou, Tejun Heo, Christoph Lameter
Cc: linux-kernel, linux-trace-kernel, linux-mm, Eugene Mavick
In-Reply-To: <20260705-refcount-final-put-trace-v1-0-0ae936edb750@mavick.dev>
From: Eugene Mavick <m@mavick.dev>
Add ref_trace_final_put tracepoint and related core infrastructure
ref_trace_final_put fires when a reference
count reaches zero and the object enters its final release path.
The tracepoint records three fields:
- caller: function that called the refcounting
function(refcount_sub_and_test, percpu_ref_put_many)
- fn: refcounting function(eg refcount_sub_and_test)
- obj: refcount object(struct percpu_ref, refcount_t)
Signed-off-by: Eugene Mavick <m@mavick.dev>
---
MAINTAINERS | 2 ++
include/linux/ref_trace.h | 26 +++++++++++++++++++++++
include/trace/events/ref_trace.h | 46 ++++++++++++++++++++++++++++++++++++++++
lib/Makefile | 2 ++
lib/ref_trace.c | 12 +++++++++++
5 files changed, 88 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 10e8253181d3..8dab37726b9d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4210,7 +4210,9 @@ S: Maintained
F: Documentation/atomic_*.txt
F: arch/*/include/asm/atomic*.h
F: include/*/atomic*.h
+F: include/linux/ref_trace.h
F: include/linux/refcount.h
+F: lib/ref_trace.h
F: scripts/atomic/
F: rust/kernel/sync/atomic.rs
F: rust/kernel/sync/atomic/
diff --git a/include/linux/ref_trace.h b/include/linux/ref_trace.h
new file mode 100644
index 000000000000..54e9fba9e3e9
--- /dev/null
+++ b/include/linux/ref_trace.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_REF_TRACE_H
+#define _LINUX_REF_TRACE_H
+
+#include <linux/tracepoint-defs.h>
+#include <linux/instruction_pointer.h>
+
+/* Declare the tracepoint so tracepoint_enabled() can be used */
+DECLARE_TRACEPOINT(ref_trace_final_put);
+
+#ifdef CONFIG_TRACEPOINTS
+/* Wrapper function implemented in lib/ref_trace.c */
+extern void do_ref_trace_final_put(unsigned long caller, const char *fn, const void *obj);
+
+#define trace_ref_final_put(obj) \
+ do { \
+ if (tracepoint_enabled(ref_trace_final_put)) \
+ do_ref_trace_final_put(_RET_IP_, __func__, obj); \
+ } while (0)
+
+#else /* !CONFIG_TRACEPOINTS */
+static inline void do_ref_trace_final_put(unsigned long caller, const char *fn, const void *obj) { }
+#define trace_ref_final_put(obj) do { } while (0)
+#endif
+
+#endif /* _LINUX_REF_TRACE_H */
diff --git a/include/trace/events/ref_trace.h b/include/trace/events/ref_trace.h
new file mode 100644
index 000000000000..e6037a325be2
--- /dev/null
+++ b/include/trace/events/ref_trace.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM ref_trace
+
+#if !defined(_TRACE_REF_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_REF_TRACE_H
+
+#include <linux/tracepoint.h>
+
+/**
+ * ref_trace_final_put - trace when a reference count reaches zero
+ * @caller: function that called the refcounting
+ * function(refcount_sub_and_test, percpu_ref_put_many)
+ * @fn: refcounting function(eg refcount_sub_and_test)
+ * @obj: refcount object(struct percpu_ref, refcount_t)
+ *
+ * Tracepoint instrumentation can be added using the ref_trace_final_put
+ * macro defined in include/linux/ref_trace.h
+ * which uses _RET_IP_ and __func__ for caller and fn arguments respectively,
+ * thus only requiring obj arg to be supplied
+ */
+TRACE_EVENT(ref_trace_final_put,
+
+ TP_PROTO(unsigned long caller, const char *fn, const void *obj),
+
+ TP_ARGS(caller, fn, obj),
+
+ TP_STRUCT__entry(
+ __field(unsigned long, caller)
+ __string(fn, fn)
+ __field(const void *, obj)
+ ),
+
+ TP_fast_assign(
+ __entry->caller = caller;
+ __assign_str(fn);
+ __entry->obj = obj;
+ ),
+
+ TP_printk("caller=%pS fn=%s obj=%p", (void *)__entry->caller, __get_str(fn), __entry->obj)
+);
+
+#endif /* _TRACE_REF_TRACE_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/lib/Makefile b/lib/Makefile
index f33a24bf1c19..41737090a95d 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -335,3 +335,5 @@ CONTEXT_ANALYSIS_test_context-analysis.o := y
obj-$(CONFIG_CONTEXT_ANALYSIS_TEST) += test_context-analysis.o
subdir-$(CONFIG_FORTIFY_SOURCE) += test_fortify
+
+obj-$(CONFIG_TRACEPOINTS) += ref_trace.o
diff --git a/lib/ref_trace.c b/lib/ref_trace.c
new file mode 100644
index 000000000000..25f7c17c7c47
--- /dev/null
+++ b/lib/ref_trace.c
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+#define CREATE_TRACE_POINTS
+#include <trace/events/ref_trace.h>
+
+//Wrapper function for functions defined entirely in header files
+void do_ref_trace_final_put(unsigned long caller, const char *fn, const void *obj)
+{
+ trace_ref_trace_final_put(caller, fn, obj);
+}
+EXPORT_SYMBOL_GPL(do_ref_trace_final_put);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(ref_trace_final_put);
--
2.51.2
^ permalink raw reply related
* [PATCH 2/4] refcount: add ref_trace_final_put tracepoint
From: Eugene Mavick via B4 Relay @ 2026-07-05 1:20 UTC (permalink / raw)
To: Will Deacon, Peter Zijlstra, Boqun Feng, Mark Rutland, Gary Guo,
Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Andrew Morton, Dennis Zhou, Tejun Heo, Christoph Lameter
Cc: linux-kernel, linux-trace-kernel, linux-mm, Eugene Mavick
In-Reply-To: <20260705-refcount-final-put-trace-v1-0-0ae936edb750@mavick.dev>
From: Eugene Mavick <m@mavick.dev>
Add the ref_trace_final_put tracepoint to __refcount_sub_and_test().
This fires when a refcount_t reaches zero, capturing the caller
address, the function name, and the refcount_t address.
Signed-off-by: Eugene Mavick <m@mavick.dev>
---
include/linux/refcount.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/linux/refcount.h b/include/linux/refcount.h
index ba7657ced281..7b1fbf326a21 100644
--- a/include/linux/refcount.h
+++ b/include/linux/refcount.h
@@ -107,6 +107,7 @@
#include <linux/limits.h>
#include <linux/refcount_types.h>
#include <linux/spinlock_types.h>
+#include <linux/ref_trace.h>
struct mutex;
@@ -393,6 +394,7 @@ bool __refcount_sub_and_test(int i, refcount_t *r, int *oldp)
if (old > 0 && old == i) {
smp_acquire__after_ctrl_dep();
+ trace_ref_final_put(r);
return true;
}
--
2.51.2
^ permalink raw reply related
* [PATCH 3/4] percpu-refcount: add ref_trace_final_put trace
From: Eugene Mavick via B4 Relay @ 2026-07-05 1:20 UTC (permalink / raw)
To: Will Deacon, Peter Zijlstra, Boqun Feng, Mark Rutland, Gary Guo,
Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Andrew Morton, Dennis Zhou, Tejun Heo, Christoph Lameter
Cc: linux-kernel, linux-trace-kernel, linux-mm, Eugene Mavick
In-Reply-To: <20260705-refcount-final-put-trace-v1-0-0ae936edb750@mavick.dev>
From: Eugene Mavick <m@mavick.dev>
Add the ref_trace_final_put tracepoint to percpu_ref_put_many().
The tracepoint fires when the atomic counter reaches zero in the
atomic fallback path (after percpu_ref_kill() has been called).
Signed-off-by: Eugene Mavick <m@mavick.dev>
---
include/linux/percpu-refcount.h | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/include/linux/percpu-refcount.h b/include/linux/percpu-refcount.h
index d73a1c08c3e3..55543ecdf60c 100644
--- a/include/linux/percpu-refcount.h
+++ b/include/linux/percpu-refcount.h
@@ -55,6 +55,7 @@
#include <linux/rcupdate.h>
#include <linux/types.h>
#include <linux/gfp.h>
+#include <linux/ref_trace.h>
struct percpu_ref;
typedef void (percpu_ref_func_t)(struct percpu_ref *);
@@ -331,8 +332,10 @@ static inline void percpu_ref_put_many(struct percpu_ref *ref, unsigned long nr)
if (__ref_is_percpu(ref, &percpu_count))
this_cpu_sub(*percpu_count, nr);
- else if (unlikely(atomic_long_sub_and_test(nr, &ref->data->count)))
+ else if (unlikely(atomic_long_sub_and_test(nr, &ref->data->count))) {
+ trace_ref_final_put(ref);
ref->data->release(ref);
+ }
rcu_read_unlock();
}
--
2.51.2
^ permalink raw reply related
* Re: [PATCH v8 13/46] KVM: guest_memfd: Add base support for KVM_SET_MEMORY_ATTRIBUTES2
From: Suzuki K Poulose @ 2026-07-04 23:38 UTC (permalink / raw)
To: ackerleytng, aik, andrew.jones, binbin.wu, brauner, chao.p.peng,
david, jmattson, jthoughton, michael.roth, oupton, pankaj.gupta,
qperret, rick.p.edgecombe, rientjes, shivankg, steven.price,
tabba, willy, wyihan, yan.y.zhao, forkloop, pratyush,
aneesh.kumar, liam, Paolo Bonzini, Sean Christopherson,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, Jonathan Corbet, Shuah Khan, Shuah Khan,
Vishal Annapurve, Andrew Morton, Chris Li, Kairui Song,
Kemeng Shi, Nhat Pham, Barry Song, Axel Rasmussen, Yuanchu Xie,
Wei Xu, Youngjun Park, Qi Zheng, Shakeel Butt, Kiryl Shutsemau,
Baoquan He, Jason Gunthorpe, Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
linux-mm, linux-coco
In-Reply-To: <20260618-gmem-inplace-conversion-v8-13-9d2959357853@google.com>
Hi
On 19/06/2026 01:31, Ackerley Tng via B4 Relay wrote:
> From: Ackerley Tng <ackerleytng@google.com>
>
> Introduce base support for KVM_SET_MEMORY_ATTRIBUTES2 in guest_memfd, which
> just updates attributes tracked by guest_memfd.
>
> Validate input fields in general. Guard usage of KVM_SET_MEMORY_ATTRIBUTES2
> by making sure requested attributes are supported for this instance of kvm.
>
> A new KVM_SET_MEMORY_ATTRIBUTES2 is defined to support writes (unlike
> KVM_SET_MEMORY_ATTRIBUTES) in addition to reads so it can provide error
> details to userspace. This will be used in a later patch.
>
> The two ioctls use their corresponding structs with no overlap, but
> backward compatibility is baked in for future support of
> KVM_SET_MEMORY_ATTRIBUTES2 and struct kvm_memory_attributes2 in the VM
> ioctl.
>
> The process of setting memory attributes is set up such that the later half
> will not fail due to allocation. Any necessary checks are performed before
> the point of no return.
>
> Co-developed-by: Vishal Annapurve <vannapurve@google.com>
> Signed-off-by: Vishal Annapurve <vannapurve@google.com>
> Co-developed-by: Sean Christoperson <seanjc@google.com>
> Signed-off-by: Sean Christoperson <seanjc@google.com>
> Reviewed-by: Fuad Tabba <tabba@google.com>
> Signed-off-by: Ackerley Tng <ackerleytng@google.com>
> ---
...
> diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
> index 65ce795c090d9..0d14548c1ed22 100644
> --- a/virt/kvm/guest_memfd.c
> +++ b/virt/kvm/guest_memfd.c
> @@ -541,11 +541,127 @@ bool kvm_gmem_is_private(struct kvm *kvm, gfn_t gfn)
...
> +static int __kvm_gmem_set_attributes(struct inode *inode, pgoff_t start,
> + size_t nr_pages, uint64_t attrs)
> +{
> + struct address_space *mapping = inode->i_mapping;
> + struct gmem_inode *gi = GMEM_I(inode);
> + pgoff_t end = start + nr_pages;
> + struct maple_tree *mt;
> + struct ma_state mas;
> + int r;
> +
> + mt = &gi->attributes;
> +
> + filemap_invalidate_lock(mapping);
> +
> + mas_init(&mas, mt, start);
> + r = kvm_gmem_mas_preallocate(&mas, attrs, start, nr_pages);
> + if (r)
> + goto out;
> +
> + /*
> + * From this point on guest_memfd has performed necessary
> + * checks and can proceed to do guest-breaking changes.
> + */
> +
> + kvm_gmem_invalidate_start(inode, start, end);
I added support for Arm CCA KVM patches with the inplace conversion and
I am hitting the following issue.
1. I am supporting INIT_SHARED + MMAP flags.
2. VMM creates the Gmem_fd with both the flags above.
3. Uses the shared gmem-mmap to load the initial payloads (kernel, dtb).
4. At the VM finalization time, Populate the loaded regions one by one
by
a) copying the images to a temparory buffer - Since CCA can't really
load the contents in-place.
b) Set the "region" to Private in the gmem_fd (via
SET_MEMORY_ATTRIBUTES2)
c) Invoke CCA backend to populate the private memory via
ioctl(KVM_ARM_RMI_POPULATE,..) [0]
[0]
https://lore.kernel.org/all/20260513131757.116630-27-steven.price@arm.com/
5. Additionally, VMM can mark the entire RAM to be private before the VM
starts running, again via SET_MEMORY_ATTRIBUTES2. On CCA, this
action is measured and doesn't require the Host to "commit" memory to
the VM.
Instead the host can lazily donate memory on a fault.
But step (5) triggers the invalidation of both private and shared
mappings of the gmem area, from the kvm_gmem_invalidate_start()
above.
This is because, the entire DRAM now has, some portions PRIVATE (the
loaded regions) and the rest are SHARED (from the Gmem_fd creation).
Thus, kvm_gmem_get_invalidate_filter(Dram_start, Dram_end) causes the
invalidation of both "PRIVATE" and "SHARED" regions, which results
in the destruction of the already loaded data and things go south.
When we know that the kvm_gmem_invalidate_xx is triggered by a
conversion, we don't need to invalidate the existing pages that
are in the requested state. i.e., the following patch on top of
this series does the trick for me :
diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index a97fcac34a0e..62e0427a49f4 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -250,16 +250,23 @@ static void __kvm_gmem_invalidate_start(struct
gmem_file *f, pgoff_t start,
KVM_MMU_UNLOCK(kvm);
}
+static void kvm_gmem_invalidate_start_filter(struct inode *inode,
pgoff_t start,
+ pgoff_t end,
+ enum kvm_gfn_range_filter
attr_filter)
+{
+ struct gmem_file *f;
+
+ kvm_gmem_for_each_file(f, inode)
+ __kvm_gmem_invalidate_start(f, start, end, attr_filter);
+}
+
static void kvm_gmem_invalidate_start(struct inode *inode, pgoff_t start,
pgoff_t end)
{
enum kvm_gfn_range_filter attr_filter;
- struct gmem_file *f;
-
attr_filter = kvm_gmem_get_invalidate_filter(inode, start, end);
- kvm_gmem_for_each_file(f, inode)
- __kvm_gmem_invalidate_start(f, start, end, attr_filter);
+ kvm_gmem_invalidate_start_filter(inode, start, end, attr_filter);
}
static void __kvm_gmem_invalidate_end(struct gmem_file *f, pgoff_t start,
@@ -724,9 +731,14 @@ static int __kvm_gmem_set_attributes(struct inode
*inode, pgoff_t start,
/*
* From this point on guest_memfd has performed necessary
* checks and can proceed to do guest-breaking changes.
+ * Also, we don't have to invalidate the regions that
+ * may already be in the requested state. Hence, we could
+ * explicitly filter the invalidations to the opposite
+ * state.
*/
- kvm_gmem_invalidate_start(inode, start, end);
+ kvm_gmem_invalidate_start_filter(inode, start, end,
+ to_private ? KVM_FILTER_SHARED :
KVM_FILTER_PRIVATE);
if (!to_private)
kvm_gmem_invalidate(inode, start, end);
Thoughts ?
Suzuki
> + mas_store_prealloc(&mas, xa_mk_value(attrs));
> + kvm_gmem_invalidate_end(inode, start, end);
> +out:
> + filemap_invalidate_unlock(mapping);
> + return r;
> +}
> +
> +static long kvm_gmem_set_attributes(struct file *file, void __user *argp)
> +{
> + struct gmem_file *f = file->private_data;
> + struct inode *inode = file_inode(file);
> + struct kvm_memory_attributes2 attrs;
> + size_t nr_pages;
> + pgoff_t index;
> + int i;
> +
> + if (copy_from_user(&attrs, argp, sizeof(attrs)))
> + return -EFAULT;
> +
> + if (attrs.flags)
> + return -EINVAL;
> + for (i = 0; i < ARRAY_SIZE(attrs.reserved); i++) {
> + if (attrs.reserved[i])
> + return -EINVAL;
> + }
> + if (!kvm_arch_has_private_mem(f->kvm))
> + return -EINVAL;
> + if (attrs.attributes & ~KVM_MEMORY_ATTRIBUTE_PRIVATE)
> + return -EINVAL;
> + if (attrs.size == 0 || attrs.offset + attrs.size < attrs.offset)
> + return -EINVAL;
> + if (!PAGE_ALIGNED(attrs.offset) || !PAGE_ALIGNED(attrs.size))
> + return -EINVAL;
> +
> + if (attrs.offset >= i_size_read(inode) ||
> + attrs.offset + attrs.size > i_size_read(inode))
> + return -EINVAL;
> +
> + nr_pages = attrs.size >> PAGE_SHIFT;
> + index = attrs.offset >> PAGE_SHIFT;
> + return __kvm_gmem_set_attributes(inode, index, nr_pages,
> + attrs.attributes);
> +}
> +
> +static long kvm_gmem_ioctl(struct file *file, unsigned int ioctl,
> + unsigned long arg)
> +{
> + switch (ioctl) {
> + case KVM_SET_MEMORY_ATTRIBUTES2:
> + if (!gmem_in_place_conversion)
> + return -ENOTTY;
> +
> + return kvm_gmem_set_attributes(file, (void __user *)arg);
> + default:
> + return -ENOTTY;
> + }
> +}
> +
> static struct file_operations kvm_gmem_fops = {
> .mmap = kvm_gmem_mmap,
> .open = generic_file_open,
> .release = kvm_gmem_release,
> .fallocate = kvm_gmem_fallocate,
> + .unlocked_ioctl = kvm_gmem_ioctl,
> };
>
> static int kvm_gmem_migrate_folio(struct address_space *mapping,
> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index 01761f6e25d25..a08b518cdb175 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -105,6 +105,18 @@ module_param(allow_unsafe_mappings, bool, 0444);
> bool __ro_after_init gmem_in_place_conversion = false;
> #endif
>
> +#define MEMORY_ATTRIBUTES_MATCH(one, two) \
> + static_assert(offsetof(struct kvm_memory_attributes, one) == \
> + offsetof(struct kvm_memory_attributes2, two)); \
> + static_assert(sizeof_field(struct kvm_memory_attributes, one) ==\
> + sizeof_field(struct kvm_memory_attributes2, two))
> +
> +/* Ensure the common parts of the two structs are identical. */
> +MEMORY_ATTRIBUTES_MATCH(address, address);
> +MEMORY_ATTRIBUTES_MATCH(size, size);
> +MEMORY_ATTRIBUTES_MATCH(attributes, attributes);
> +MEMORY_ATTRIBUTES_MATCH(flags, flags);
> +
> /*
> * Ordering of locks:
> *
>
^ permalink raw reply related
* Re: [RFC 0/2] arm64: kprobes: Fix single-step fault and reentry handling
From: Masami Hiramatsu @ 2026-07-04 14:47 UTC (permalink / raw)
To: Pu Hu
Cc: catalin.marinas@arm.com, will@kernel.org, naveen@kernel.org,
davem@davemloft.net, yang@os.amperecomputing.com, Hongyan Xia,
Jiazi Li, ada.coupriediaz@arm.com,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org
In-Reply-To: <89c389ad-7e80-463b-9c1a-31a2e7dae814@transsion.com>
Hi Pu Hu,
Can you update this by rebasing on top of arm64 tree
(git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git)
and update your signed-off-by with your name.
Thank you,
On Thu, 2 Jul 2026 10:09:51 +0000
Pu Hu <hupu@transsion.com> wrote:
> On 7/2/2026 6:07 PM, hupu wrote:
> > On 7/1/2026 9:56 PM, Pu Hu wrote:
> >> On 7/1/2026 9:43 PM, Masami Hiramatsu wrote:
> >>> On Wed, 1 Jul 2026 12:14:54 +0000
> >>> Pu Hu <hupu@transsion.com> wrote:
> >>>
> >>>> From: hupu <hupu@transsion.com>
> >>>>
> ...
> ...>
> > I will send the complete test case in a follow-up email.
> >
> > Thanks,
> > hupu
> >
>
> Hi maintainers,
>
> As mentioned in my previous email, below is the complete test case I
> used to reproduce the arm64 kprobe crash on mainline.
>
> It contains:
>
> - a small kprobe module that probes folio_wait_bit_common()
> - a userspace program that repeatedly triggers file-backed page faults
> - a Makefile to build both parts
>
> Depending on the local build environment, the following variables in the
> Makefile may need to be adjusted:
>
> CROSS_COMPILE
> KERN_DIR
> DEST_PATH
>
> Thanks,
> Pu Hu
>
> ---
>
>
> diff --git a/misc/kprobe/Makefile b/misc/kprobe/Makefile
> new file mode 100755
> index 0000000..14c00c0
> --- /dev/null
> +++ b/misc/kprobe/Makefile
> @@ -0,0 +1,36 @@
> +PWD := $(shell pwd)
> +ARCH ?= arm64
> +CROSS_COMPILE ?= aarch64-dumpstack-linux-gnu-
> +KERN_DIR ?= $(PWD)/../../output/build-mainline
> +DEST_PATH ?= $(PWD)/../../output
> +Q := @
> +
> +UNIT_TEST := fault_stress
> +UNIT_TEST_SRC := fault_stress.c
> +
> +KP_MOD := kp_folio
> +obj-m := $(KP_MOD).o
> +
> +USER_CFLAGS := -static -g -O0 -fno-omit-frame-pointer
> -fasynchronous-unwind-tables
> +USER_LIBS := -lm -lpthread
> +EXTRA_CFLAGS += -I$(KERN_DIR)
> +
> +.PHONY: all modules user clean
> +
> +all: modules user install
> +
> +modules:
> + $(Q)$(MAKE) -C $(KERN_DIR) M=$(PWD)
> EXTRA_CFLAGS="$(EXTRA_CFLAGS)" ARCH=$(ARCH)
> CROSS_COMPILE=$(CROSS_COMPILE) modules
> +
> +user:
> + $(Q)$(CROSS_COMPILE)gcc $(USER_CFLAGS) $(UNIT_TEST_SRC) -o
> $(UNIT_TEST) $(USER_LIBS)
> +
> +install:
> + $(Q)mkdir -p $(DEST_PATH)
> + $(Q)cp -f *.ko $(DEST_PATH)/
> + $(Q)cp -f $(UNIT_TEST) $(DEST_PATH)/
> +
> +clean:
> + $(Q)$(MAKE) -C $(KERN_DIR) M=$(PWD) clean
> + $(Q)rm -f $(UNIT_TEST)
> + $(Q)rm -f $(DEST_PATH)/$(UNIT_TEST) $(DEST_PATH)/*.ko
> diff --git a/misc/kprobe/fault_stress.c b/misc/kprobe/fault_stress.c
> new file mode 100755
> index 0000000..10150ff
> --- /dev/null
> +++ b/misc/kprobe/fault_stress.c
> @@ -0,0 +1,96 @@
> +#define _GNU_SOURCE
> +#include <fcntl.h>
> +#include <pthread.h>
> +#include <sched.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/mman.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +#include <unistd.h>
> +
> +#define FILE_SIZE (256UL * 1024 * 1024)
> +#define NR_THREADS 8
> +
> +static void deep_call(int n)
> +{
> + volatile char buf[4096];
> +
> + memset((void *)buf, n, sizeof(buf));
> +
> + if (n > 0)
> + deep_call(n - 1);
> + else
> + sched_yield();
> +}
> +
> +static void *worker(void *arg)
> +{
> + const char *path = arg;
> + int fd;
> + char *map;
> + unsigned long i;
> + volatile unsigned long sum = 0;
> +
> + fd = open(path, O_RDONLY);
> + if (fd < 0) {
> + perror("open");
> + return NULL;
> + }
> +
> + map = mmap(NULL, FILE_SIZE, PROT_READ, MAP_PRIVATE, fd, 0);
> + if (map == MAP_FAILED) {
> + perror("mmap");
> + close(fd);
> + return NULL;
> + }
> +
> + for (;;) {
> + /*
> + * Drop the pages backing this mapping from the current
> process.
> + * Subsequent accesses are more likely to trigger
> file-backed
> + * page faults again.
> + */
> + madvise(map, FILE_SIZE, MADV_DONTNEED);
> +
> + for (i = 0; i < FILE_SIZE; i += 4096 * 17) {
> + sum += map[i];
> + deep_call(64);
> + }
> + }
> +
> + munmap(map, FILE_SIZE);
> + close(fd);
> + return NULL;
> +}
> +
> +int main(void)
> +{
> + pthread_t th[NR_THREADS];
> + const char *path = "/tmp/fault_stress_file";
> + int fd;
> + int i;
> +
> + fd = open(path, O_CREAT | O_RDWR, 0644);
> + if (fd < 0) {
> + perror("open file");
> + return 1;
> + }
> +
> + if (ftruncate(fd, FILE_SIZE) < 0) {
> + perror("ftruncate");
> + return 1;
> + }
> +
> + close(fd);
> +
> + for (i = 0; i < NR_THREADS; i++)
> + pthread_create(&th[i], NULL, worker, (void *)path);
> +
> + for (i = 0; i < NR_THREADS; i++)
> + pthread_join(th[i], NULL);
> +
> + return 0;
> +}
> +
> diff --git a/misc/kprobe/kp_folio.c b/misc/kprobe/kp_folio.c
> new file mode 100755
> index 0000000..c8f3e1d
> --- /dev/null
> +++ b/misc/kprobe/kp_folio.c
> @@ -0,0 +1,60 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/kprobes.h>
> +#include <linux/sched.h>
> +#include <linux/atomic.h>
> +#include <linux/ratelimit.h>
> +
> +static atomic64_t kp_hit_count = ATOMIC64_INIT(0);
> +
> +static int folio_wait_bit_common_handler(
> + struct kprobe *p,^M
> + struct pt_regs *regs)
> +{
> + unsigned long hit;
> +
> + hit = atomic64_inc_return(&kp_hit_count);
> +
> + pr_info("kp_folio: hit=%lu comm=%s tgid=%d tid=%d\n",
> + hit, current->comm, current->tgid, current->pid);
> +
> + return 0;
> +}
> +
> +static struct kprobe kp_folio_wait_bit_common = {
> + .symbol_name = "folio_wait_bit_common",
> + .pre_handler = folio_wait_bit_common_handler,
> +};
> +
> +static int __init kp_folio_init(void)
> +{
> + int ret;
> +
> + ret = register_kprobe(&kp_folio_wait_bit_common);
> + if (ret < 0) {
> + pr_err("kp_folio: register_kprobe failed, ret=%d\n", ret);
> + return ret;
> + }
> +
> + pr_info("kp_folio: kprobe registered at %pS, addr=%px\n",
> + kp_folio_wait_bit_common.addr,
> + kp_folio_wait_bit_common.addr);
> +
> + return 0;
> +}
> +
> +static void __exit kp_folio_exit(void)
> +{
> + unregister_kprobe(&kp_folio_wait_bit_common);
> +
> + pr_info("kp_folio: kprobe unregistered, total hits=%lld\n",
> + atomic64_read(&kp_hit_count));
> +}
> +
> +module_init(kp_folio_init);
> +module_exit(kp_folio_exit);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("hupu <hupu@transsion.com>");
> +MODULE_DESCRIPTION("simple kprobe reproducer for folio_wait_bit_common");
>
>
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply
* Re: [RFC] xdp: add device context to bpf_xdp_link_attach_failed tracepoint
From: Leon Hwang @ 2026-07-04 13:28 UTC (permalink / raw)
To: Masashi Honma
Cc: netdev, bpf, linux-trace-kernel, ast, daniel, kuba, hawk, andrii,
rostedt, mhiramat, edumazet, pabeni, linux-kernel
In-Reply-To: <CAFk-A4n9U0r07tn6XHHqmOZ++-bmM4bSd-SwdpEU-88gjKts7Q@mail.gmail.com>
Pls do not top-post.
See
https://docs.kernel.org/process/submitting-patches.html#use-trimmed-interleaved-replies-in-email-discussions.
On 2026/7/4 13:50, Masashi Honma wrote:
> Thank you Leon. I think this is a much better direction than my RFC, so I'll
> drop my tracepoint proposal and support your approach instead.
>
> Since a user-space dependency on the existing tracepoint would make it hard
> for you to retire it, I'll make sure the Cilium PR doesn't rely on the
> tracepoint either.
Probably, you can get the 'extack->_msg' by tracing dev_xdp_attach using
kprobe+kretprobe or kprobe.session, if the extack is not NULL.
>
> Is there anything I can help with on the new approach?
You are welcome to review the series in the future.
Thanks,
Leon
[...]
^ permalink raw reply
* Re: [PATCH v10 6/6] selftests/mm: add hwpoison-panic destructive test
From: Mike Rapoport @ 2026-07-04 9:31 UTC (permalink / raw)
To: Breno Leitao
Cc: Miaohe Lin, Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Vlastimil Babka, Suren Baghdasaryan, Michal Hocko, Shuah Khan,
Naoya Horiguchi, Jonathan Corbet, Shuah Khan, Liam R. Howlett,
lance.yang, Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
linux-mm, linux-kernel, linux-doc, linux-kselftest,
linux-trace-kernel, kernel-team
In-Reply-To: <20260630-ecc_panic-v10-6-c6ed5b62eea2@debian.org>
Hi Breno,
On Tue, Jun 30, 2026 at 05:46:09AM -0700, Breno Leitao wrote:
> Add a destructive selftest that verifies
> vm.panic_on_unrecoverable_memory_failure actually panics when a
> hwpoison error hits a kernel-owned page.
>
> Three "kinds" of kernel-owned page can be targeted, selectable via
> the script's first positional argument (default: rodata):
>
> rodata - a PG_reserved page in the kernel rodata range, sourced
> from the "Kernel rodata" sub-resource of "System RAM" in
> /proc/iomem. That entry is reported on every major
> architecture and guarantees the chosen PFN is backed by
> struct page (an online System RAM range, not a firmware
> hole), is PG_reserved, and is read-only -- so even if
> the panic fails to fire for some reason, the resulting
> PG_hwpoison marker on rodata does not corrupt writable
> kernel state.
>
> slab - a slab page found by walking /proc/kpageflags for the
> first PFN with KPF_SLAB set (and KPF_HWPOISON / KPF_NOPAGE
> / KPF_COMPOUND_TAIL clear). Exercises the get_any_page()
> path on a non PG_reserved kernel-owned page and so
> catches regressions where get_any_page() collapses
> kernel-owned pages into a transient -EIO instead of
> -ENOTRECOVERABLE.
>
> pgtable - same as slab, but the PFN is selected via KPF_PGTABLE.
>
> PageLargeKmalloc, the fourth page type matched by
> is_kernel_owned_page(), is intentionally not covered: it is a
> PAGE_TYPE_OPS flag with no /proc/kpageflags bit, so selecting such
> a PFN from userspace is not feasible. The slab and pgtable
> variants already exercise the same get_any_page() positive-check
> branch.
>
> The script enables the sysctl and writes the selected physical
> address to /sys/devices/system/memory/hard_offline_page. A
> successful run crashes the kernel with
>
> Memory failure: <pfn>: unrecoverable page
>
> A return from the inject means no panic fired. Before reporting, the
> script restores the sysctl and best-effort unpoisons the target PFN
> through the hwpoison debugfs interface (hard_offline_page() injects
> with MF_SW_SIMULATED, so the page stays unpoisonable), then re-reads
> /proc/kpageflags: a PFN that is still the kernel-owned type it selected
> is a genuine failure, while one that raced to a different type before
> the inject is skipped as inconclusive. Test outcome is therefore
> observed externally (serial console, kdump) rather than from the
> script's own exit code.
>
> The script is intentionally NOT wired into run_vmtests.sh: every
> successful run panics the kernel, which is incompatible with the
> sequential "run each category in the same VM" model that
> run_vmtests.sh assumes. It is also not registered as a TEST_PROGS /
> ksft_* wrapper so a default kselftest run does not opt itself into
> a panic. The script is meant to be executed manually inside a
> disposable VM (e.g. virtme-ng), one variant per VM boot, and
> requires RUN_DESTRUCTIVE=1 in the environment as a safety net.
>
> Signed-off-by: Breno Leitao <leitao@debian.org>
> ---
> tools/testing/selftests/mm/Makefile | 4 +
> tools/testing/selftests/mm/hwpoison-panic.sh | 255 +++++++++++++++++++++++++++
> 2 files changed, 259 insertions(+)
>
> diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile
> index e6df968f0971c..ed321ae709dac 100644
> --- a/tools/testing/selftests/mm/Makefile
> +++ b/tools/testing/selftests/mm/Makefile
> @@ -174,6 +174,10 @@ TEST_PROGS += ksft_userfaultfd.sh
> TEST_PROGS += ksft_vma_merge.sh
> TEST_PROGS += ksft_vmalloc.sh
>
> +# Destructive: every successful run panics the kernel. Installed and
> +# kept executable, but not run from a default kselftest invocation.
> +TEST_PROGS_EXTENDED += hwpoison-panic.sh
> +
> TEST_FILES := test_vmalloc.sh
> TEST_FILES += test_hmm.sh
> TEST_FILES += va_high_addr_switch.sh
> diff --git a/tools/testing/selftests/mm/hwpoison-panic.sh b/tools/testing/selftests/mm/hwpoison-panic.sh
> new file mode 100755
> index 0000000000000..d953d13673324
> --- /dev/null
> +++ b/tools/testing/selftests/mm/hwpoison-panic.sh
> @@ -0,0 +1,255 @@
> +#!/bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Verify vm.panic_on_unrecoverable_memory_failure by injecting a hwpoison
> +# error on a kernel-owned page and confirming the kernel panics.
> +#
> +# Three "kinds" of kernel-owned page can be targeted, selectable via the
> +# first positional argument (default: rodata):
> +#
> +# rodata - a PG_reserved page in the kernel rodata range
> +# (sourced from /proc/iomem "Kernel rodata"). Exercises
> +# memory_failure() -> get_any_page() on a PageReserved page.
> +#
> +# slab - a slab page found via /proc/kpageflags (KPF_SLAB).
> +# Exercises memory_failure() -> get_any_page() on a non
> +# PG_reserved kernel-owned page. This path is what catches
> +# regressions where get_any_page() collapses kernel-owned
> +# pages into a transient -EIO instead of -ENOTRECOVERABLE.
> +#
> +# pgtable - a page-table page found via /proc/kpageflags (KPF_PGTABLE).
> +# Same path as slab, different page type.
> +#
> +# This test is DESTRUCTIVE: a successful run crashes the kernel. It is
> +# meant to be executed inside a disposable VM (e.g. virtme-ng) with a
> +# serial console captured by the harness. It is skipped unless the
> +# caller opts in via RUN_DESTRUCTIVE=1.
> +#
> +# Test passes externally: the kernel must panic with
> +# "Memory failure: <pfn>: unrecoverable page"
> +# A return from the inject means no panic fired: that is a failure,
> +# unless the target PFN raced to a different page type before injection,
> +# in which case the run is inconclusive and is skipped.
> +#
> +# Author: Breno Leitao <leitao@debian.org>
> +
> +set -u
> +
> +# KTAP output helpers (ktap_print_msg, ktap_skip_all, ktap_exit_fail_msg, ...).
> +DIR="$(dirname "$(readlink -f "$0")")"
> +# shellcheck source=../kselftest/ktap_helpers.sh
> +source "${DIR}"/../kselftest/ktap_helpers.sh
> +
> +sysctl_path=/proc/sys/vm/panic_on_unrecoverable_memory_failure
> +inject_path=/sys/devices/system/memory/hard_offline_page
> +kpageflags_path=/proc/kpageflags
> +unpoison_path=/sys/kernel/debug/hwpoison/unpoison-pfn
> +
> +# /proc/kpageflags bit positions (see include/uapi/linux/kernel-page-flags.h)
> +KPF_SLAB=7
> +KPF_COMPOUND_TAIL=16
> +KPF_HWPOISON=19
> +KPF_NOPAGE=20
> +KPF_PGTABLE=26
> +KPF_RESERVED=32
> +
> +pagesize=$(getconf PAGE_SIZE)
> +
> +kind=${1:-rodata}
> +
> +if [ "$(id -u)" -ne 0 ]; then
> + ktap_skip_all "must run as root"
> + exit "$KSFT_SKIP"
> +fi
> +
> +if [ ! -w "$sysctl_path" ]; then
> + ktap_skip_all "$sysctl_path not present (kernel without the sysctl?)"
> + exit "$KSFT_SKIP"
> +fi
> +
> +if [ ! -w "$inject_path" ]; then
> + ktap_skip_all "$inject_path not present (no MEMORY_HOTPLUG?)"
> + exit "$KSFT_SKIP"
> +fi
> +
> +if [ "${RUN_DESTRUCTIVE:-0}" != "1" ]; then
> + ktap_skip_all "destructive test; re-run with RUN_DESTRUCTIVE=1 inside a disposable VM"
> + exit "$KSFT_SKIP"
> +fi
> +
> +# Pick a PFN inside the kernel image rodata region of /proc/iomem.
> +# This is preferred over a top-level "Reserved" entry because top-level
> +# Reserved ranges are often firmware holes that have no backing struct
> +# page; pfn_to_online_page() returns NULL on those and memory_failure()
> +# bails out with -ENXIO before reaching the panic path.
> +#
> +# "Kernel rodata" is reported as a sub-resource of "System RAM" on every
> +# major architecture, which guarantees:
> +# - the PFN is backed by struct page (within an online memory range);
> +# - PG_reserved is set on the page (kernel image area);
> +# - the memory is read-only, so setting PG_hwpoison on it does not
> +# corrupt writable kernel state if the panic somehow does not fire.
> +#
> +# /proc/iomem entries look like (indented for sub-resources):
> +# " 02500000-02ffffff : Kernel rodata"
> +pick_rodata_phys_addr() {
> + awk -v pagesize="$(getconf PAGE_SIZE)" '
> + # Convert a hex string to a number without relying on the gawk-only
> + # strtonum(). mawk lacks it and would otherwise spuriously skip
> + # this test on distros that ship mawk as /usr/bin/awk.
> + function hex2num(s, n, i, c, v) {
> + n = 0
> + for (i = 1; i <= length(s); i++) {
> + c = tolower(substr(s, i, 1))
> + v = index("0123456789abcdef", c) - 1
> + if (v < 0)
> + return -1
> + n = n * 16 + v
> + }
> + return n
> + }
> + /: Kernel rodata[[:space:]]*$/ {
> + sub(/^[[:space:]]+/, "")
> + n = split($0, a, /[- ]/)
> + start = hex2num(a[1])
> + end = hex2num(a[2])
> + if (end <= start)
> + next
> + # Page-align upward and emit the first byte of that page.
> + pfn = int((start + pagesize - 1) / pagesize)
> + printf "0x%x\n", pfn * pagesize
> + exit 0
> + }
> + ' /proc/iomem
> +}
> +
> +# Walk /proc/kpageflags and return the phys addr of the first PFN that
> +# has bit $1 set, with KPF_HWPOISON, KPF_NOPAGE and KPF_COMPOUND_TAIL
> +# all clear (so we attack a real, non-tail, not-already-poisoned page).
> +#
> +# We skip the first 16 MiB of PFNs to step past low-memory special
> +# ranges (BIOS/EFI/ACPI/etc.) that often are PG_reserved and would not
> +# exhibit the slab/pgtable type we are looking for.
> +pick_kpageflags_phys_addr() {
> + local want_bit=$1
> + local pagesize skip_pfn
> +
> + [ -r "$kpageflags_path" ] || return
> +
> + pagesize=$(getconf PAGE_SIZE)
> + skip_pfn=$(((16 * 1024 * 1024) / pagesize))
> +
> + od -An -tx8 -v -w8 -j "$((skip_pfn * 8))" "$kpageflags_path" 2>/dev/null | \
> + awk -v want_bit="$want_bit" \
> + -v hwp_bit="$KPF_HWPOISON" \
> + -v nopage_bit="$KPF_NOPAGE" \
> + -v tail_bit="$KPF_COMPOUND_TAIL" \
> + -v base_pfn="$skip_pfn" \
> + -v pagesize="$pagesize" '
> + # Test whether bit "b" is set in the 16-hex-digit value "hex".
> + # Done with substring + per-digit lookup so we never rely on awk
> + # bitwise operators (mawk lacks them), 64-bit FP precision or the
> + # gawk-only strtonum().
> + function bit_set(hex, b, di, bi, c, v) {
> + di = int(b / 4)
> + bi = b - di * 4
> + c = substr(hex, length(hex) - di, 1)
> + v = index("0123456789abcdef", tolower(c)) - 1
> + if (bi == 0) return (v % 2) == 1
> + if (bi == 1) return int(v / 2) % 2 == 1
> + if (bi == 2) return int(v / 4) % 2 == 1
> + return int(v / 8) % 2 == 1
> + }
> + {
> + gsub(/^[[:space:]]+/, "")
> + h = $1
> + if (bit_set(h, want_bit) &&
> + !bit_set(h, hwp_bit) &&
> + !bit_set(h, nopage_bit) &&
> + !bit_set(h, tail_bit)) {
> + pfn = base_pfn + NR - 1
> + printf "0x%x\n", pfn * pagesize
> + exit 0
> + }
> + }
I'm looking at these awk scripts and od encodings and I wonder if wasn't it
simpler to write the test in C.
We have a bunch of helpers in tools/testing/selftests/mm/vm_utils.h for
accessing /proc files and there is already /proc/iomem parser in
tools/testing/selftests/mm/pfnmap.c that also could be lifter to vm_util
--
Sincerely yours,
Mike.
^ permalink raw reply
* Re: [RFC] xdp: add device context to bpf_xdp_link_attach_failed tracepoint
From: Masashi Honma @ 2026-07-04 5:50 UTC (permalink / raw)
To: Leon Hwang
Cc: netdev, bpf, linux-trace-kernel, ast, daniel, kuba, hawk, andrii,
rostedt, mhiramat, edumazet, pabeni, linux-kernel
In-Reply-To: <29129c40-4010-4862-9b4b-3bafad874568@linux.dev>
Thank you Leon. I think this is a much better direction than my RFC, so I'll
drop my tracepoint proposal and support your approach instead.
Since a user-space dependency on the existing tracepoint would make it hard
for you to retire it, I'll make sure the Cilium PR doesn't rely on the
tracepoint either.
Is there anything I can help with on the new approach?
Regards,
Masashi Honma
2026年6月29日(月) 0:26 Leon Hwang <leon.hwang@linux.dev>:
>
> On 2026/6/28 19:39, Masashi Honma wrote:
> > Hello, I am re-posting this mail because I forget to add [RFC].
> >
> > The bpf_xdp_link_attach_failed tracepoint (added in commit bf4ea1d0b2cb
> > "xdp: Add tracepoint for xdp attaching failure") exposes the netlink
> > extack message produced when attaching an XDP program via BPF_LINK_CREATE
> > fails. This is useful because, unlike the netlink attach path, the
>
> I really appreciate that the XDP tracepoint helped someone.
>
> > bpf_link attach path does not return the extack to userspace -- the caller
> > only gets an errno (e.g. EINVAL/ERANGE).
> >
> > We would like to use this in Cilium [1][2]: when attaching the XDP
> > datapath program fails, surface the kernel's reason (e.g. "single-buffer
> > XDP requires MTU less than ...") in the agent logs instead of an opaque
> > errno, so operators don't have to inspect dmesg on the host.
> >
> > The limitation we hit is that the tracepoint only carries the message
> > string, so a consumer cannot tell which device a failure belongs to.
> > This matters for two reasons:
> >
> > 1. Correlation: with only the message, a consumer cannot reliably
> > attribute a failure to a specific attach, particularly if multiple
> > XDP attaches happen concurrently.
> > 2. Scoping: a consumer watching this tracepoint sees XDP attach
> > failures system-wide and cannot limit them to the devices it
> > manages.
> >
> > At the call site (bpf_xdp_link_attach() in net/core/dev.c) the net_device
> > is in scope, so exposing it looks straightforward:
> >
> > TRACE_EVENT(bpf_xdp_link_attach_failed,
> > TP_PROTO(const char *msg, const struct net_device *dev),
> > TP_ARGS(msg, dev),
> > TP_STRUCT__entry(
> > __string(msg, msg)
> > __field(int, ifindex)
> > ),
> > TP_fast_assign(
> > __assign_str(msg);
> > __entry->ifindex = dev->ifindex;
> > ),
> > TP_printk("ifindex=%d errmsg=%s", __entry->ifindex, __get_str(msg))
> > );
> >
> > - trace_bpf_xdp_link_attach_failed(extack._msg);
> > + trace_bpf_xdp_link_attach_failed(extack._msg, dev);
> >
> > Before sending a formal patch I'd appreciate guidance on a few points:
> >
> > - Should the tracepoint take const struct net_device *dev (consistent
> > with the other tracepoints in this file, and lets TP_printk show the
> > device), or just the ifindex as an int (simpler for raw_tp BPF
> > consumers, which otherwise read dev->ifindex via CO-RE)?
> >
> > - For raw_tp consumers the argument order is effectively ABI: prepending
> > dev would shift the existing msg argument. I've appended dev above to
> > keep msg at args[0]. Is preserving the existing argument position the
> > right call, or is reordering acceptable given how new and rarely
> > consumed this tracepoint is?
> >
>
> Good concerns. I'm not sure about these parts.
>
> > - Is extending the existing tracepoint preferred, or would you rather
> > keep it as-is and expose the device context some other way?
> >
>
> I'm planning to retire this tracepoint. But I think I cannot do it, if
> there's user space application relied on the tracepoint.
>
> I'm planning to add BPF syscall common attributes support for
> BPF_LINK_CREATE, including XDP link. By that way, the kernel will be
> able to back-propagate the 'extack._msg' to user space, when fail to
> create XDP link. Thereafter, the user space library will be able to get
> the error message alongside the errno.
>
> Thanks,
> Leon
>
> > This would be my first XDP/BPF tracepoint change, so any direction is
> > welcome. I'm happy to send a proper patch once the shape is agreed.
> >
> > Regards,
> > Masashi Honma
> >
> > [1] https://github.com/cilium/cilium/issues/40777
> > [2] https://github.com/cilium/cilium/pull/46546
>
^ permalink raw reply
* Re: tracing: Cleanup event_enable_trigger_parse() by using __free()
From: Steven Rostedt @ 2026-07-03 19:33 UTC (permalink / raw)
To: Markus Elfring
Cc: linux-trace-kernel, kernel-janitors, Krzysztof Kozlowski,
Masami Hiramatsu, Mathieu Desnoyers, LKML
In-Reply-To: <bc9627b8-90fe-42f4-82f1-541bd96866aa@web.de>
On Fri, 3 Jul 2026 21:20:46 +0200
Markus Elfring <Markus.Elfring@web.de> wrote:
> > That example uses the variable in a specific block whereas this variable is
> > used in most of the function, which makes it appropriate where it lies.
>
> What does hinder you to apply scope reductions for selected local variables
> more often?
>
OK, now you are just talking like Eliza.
-- Steve
^ permalink raw reply
* Re: tracing: Cleanup event_enable_trigger_parse() by using __free()
From: Markus Elfring @ 2026-07-03 19:20 UTC (permalink / raw)
To: Steven Rostedt, linux-trace-kernel, kernel-janitors
Cc: Krzysztof Kozlowski, Masami Hiramatsu, Mathieu Desnoyers, LKML
In-Reply-To: <20260703150933.3ce014b0@gandalf.local.home>
> That example uses the variable in a specific block whereas this variable is
> used in most of the function, which makes it appropriate where it lies.
What does hinder you to apply scope reductions for selected local variables
more often?
Regards,
Markus
^ permalink raw reply
* Re: [PATCH] tracing: Cleanup event_enable_trigger_parse() by using __free()
From: Steven Rostedt @ 2026-07-03 19:09 UTC (permalink / raw)
To: Markus Elfring
Cc: linux-trace-kernel, kernel-janitors, Krzysztof Kozlowski,
Masami Hiramatsu, Mathieu Desnoyers, LKML
In-Reply-To: <360ba00d-352b-4fc1-9bfc-56d29b317f61@web.de>
On Fri, 3 Jul 2026 20:37:09 +0200
Markus Elfring <Markus.Elfring@web.de> wrote:
> Do any contributors care a bit more for involved technical details?
> https://lore.kernel.org/arm-scmi/20251208020907.5476-4-krzysztof.kozlowski@oss.qualcomm.com/
That example uses the variable in a specific block whereas this variable is
used in most of the function, which makes it appropriate where it lies.
-- Steve
^ permalink raw reply
* Re: [PATCH] tracing: Cleanup event_enable_trigger_parse() by using __free()
From: Markus Elfring @ 2026-07-03 18:37 UTC (permalink / raw)
To: Steven Rostedt, linux-trace-kernel, kernel-janitors
Cc: Krzysztof Kozlowski, Masami Hiramatsu, Mathieu Desnoyers, LKML
In-Reply-To: <20260703114233.56f0c864@gandalf.local.home>
>> * Given that the "__free(...) = NULL" pattern for variables defined at
>> * the top of the function poses this potential interdependency problem
>> * the recommendation is to always define and assign variables in one
>> * statement and not group variable definitions at the top of the
>> * function when __free() is used.
>
> This is really just a guideline.
Do any contributors care a bit more for involved technical details?
https://lore.kernel.org/arm-scmi/20251208020907.5476-4-krzysztof.kozlowski@oss.qualcomm.com/
Regards,
Markus
^ permalink raw reply
* Re: [PATCH v3 06/11] mm/cma: Allow dynamically creating CMA areas
From: David Hildenbrand (Arm) @ 2026-07-03 18:29 UTC (permalink / raw)
To: Thierry Reding, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Jonathan Hunter, David Airlie, Simona Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Sowjanya Komatineni,
Luca Ceresoli, Mikko Perttunen, Yury Norov, Rasmus Villemoes,
Russell King, Alexander Gordeev, Gerald Schaefer, Heiko Carstens,
Vasily Gorbik, Christian Borntraeger, Sven Schnelle,
Andrew Morton, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Marek Szyprowski,
Robin Murphy, Sumit Semwal, Benjamin Gaignard, Brian Starkey,
John Stultz, T.J. Mercier, Christian König, Steven Rostedt,
Masami Hiramatsu, Mathieu Desnoyers, Catalin Marinas, Will Deacon
Cc: Thierry Reding, devicetree, linux-tegra, linux-kernel, dri-devel,
linux-media, linux-arm-kernel, linux-s390, linux-mm, iommu,
linaro-mm-sig, linux-trace-kernel, Thierry Reding
In-Reply-To: <20260701-tegra-vpr-v3-6-d80f7b871bb4@nvidia.com>
On 7/1/26 18:08, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
>
> There is no technical reason why there should be a limited number of CMA
> regions, so extract some code into helpers and use them to create extra
> functions (cma_create() and cma_free()) that allow creating and freeing,
> respectively, CMA regions dynamically at runtime.
>
> The static array of CMA areas cannot be replaced by dynamically created
> areas because for many of them, allocation must not fail and some cases
> may need to initialize them before the slab allocator is even available.
> To account for this, keep these "early" areas in a separate list and
> track the dynamic areas in a separate list.
I want MM maintainers to review/ack this before this gets merged.
I'm putting it on my todo list for next week (please ping me if it falls down
the cracks and nobody else ends up reviewing it in the meantime).
--
Cheers,
David
^ permalink raw reply
* Re: [PATCH v3 04/11] arm64/mm: Add set_memory_device() and set_memory_normal()
From: Will Deacon @ 2026-07-03 17:13 UTC (permalink / raw)
To: Thierry Reding
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jonathan Hunter,
David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Sowjanya Komatineni, Luca Ceresoli,
Mikko Perttunen, Yury Norov, Rasmus Villemoes, Russell King,
Alexander Gordeev, Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
Christian Borntraeger, Sven Schnelle, Andrew Morton,
David Hildenbrand, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Marek Szyprowski, Robin Murphy, Sumit Semwal, Benjamin Gaignard,
Brian Starkey, John Stultz, T.J. Mercier, Christian König,
Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Catalin Marinas, Thierry Reding, devicetree, linux-tegra,
linux-kernel, dri-devel, linux-media, linux-arm-kernel,
linux-s390, linux-mm, iommu, linaro-mm-sig, linux-trace-kernel,
Thierry Reding, Chun Ng
In-Reply-To: <akaSJ5D98w2cHqb6@orome>
On Thu, Jul 02, 2026 at 06:41:23PM +0200, Thierry Reding wrote:
> On Thu, Jul 02, 2026 at 03:46:44PM +0200, Thierry Reding wrote:
> > On Thu, Jul 02, 2026 at 10:18:47AM +0100, Will Deacon wrote:
> > > On Wed, Jul 01, 2026 at 06:08:15PM +0200, Thierry Reding wrote:
> > > > From: Chun Ng <chunn@nvidia.com>
> > > >
> > > > Add helpers to swap PROT_NORMAL and PROT_DEVICE_nGnRnE protection bits
> > > > on a kernel-linear-map range.
> > >
> > > That sounds like a really terrible idea. Why is this necessary and how
> > > does it interact with things like load_unaligned_zeropad()?
> >
> > This is necessary because once the memory controller has walled off the
> > new memory region the CPU must not access it under any circumstances or
> > it'll cause the CPU to lock up (I think technically it'll hit an SError
> > but in practice that just means it'll freeze, as far as I can tell).
> >
> > Probably doesn't interact well at all with load_unaligned_zeropad().
> >
> > > I think you should unmap the memory from the linear map and memremap()
> > > it instead.
> >
> > Given that the memory can never be accessed by the CPU after the memory
> > controller locks it down, I don't think we'll even need memremap(). The
> > only thing we really need is the sg_table we hand out via the DMA BUFs
> > so that they can be used by device drivers to program their DMA engines
> > internally.
> >
> > Looking through some of the architecture code around this, shouldn't we
> > simply be using set_memory_encrypted() and set_memory_decrypted() for
> > this? While they might've been created for slightly other use-cases,
> > they seem to be doing exactly what we want (i.e. remove the page range
> > from the linear mapping and flushing it, or restoring the valid bit and
> > standard permissions, respectively).
>
> Ah... I guess we can't do it because we're not in a realm world and so
> the early checks in __set_memory_enc_dec() would return early and turn
> it into a no-op.
>
> How about if I extract a common helper and provide set_memory_p() and
> set_memory_np() in terms of those. Those are available on x86 and
> PowerPC as well, so fairly standard. I suppose at that point we're
> closer to set_memory_valid().
Why not just call set_direct_map_invalid_noflush() +
flush_tlb_kernel_range() for each page? We already have APIs for this.
The big challenge I see with any linear map manipulation, however, is
that it will rely on can_set_direct_map() which likely means you need to
give up some performance and/or security to make this work. Does memory
become inaccesible dynamically at runtime? If not, the best bet would
be to describe it as a carveout in the DT and mark it as "no-map" so
we avoid mapping it in the first place.
Will
^ permalink raw reply
* Re: [syzbot] [trace?] [usb?] general protection fault in mas_start (2)
From: Oleg Nesterov @ 2026-07-03 16:30 UTC (permalink / raw)
To: syzbot
Cc: bp, dave.hansen, hpa, linux-kernel, linux-trace-kernel, linux-usb,
mhiramat, mingo, peterz, syzkaller-bugs, tglx, x86
In-Reply-To: <6a47dd16.6912059f.e0473.000e.GAE@google.com>
On 07/03, syzbot wrote:
>
> Hello,
>
> syzbot found the following issue on:
>
> HEAD commit: dc59e4fea9d8 Linux 7.2-rc1
> git tree: upstream
> console output: https://syzkaller.appspot.com/x/log.txt?x=12610e1c580000
> kernel config: https://syzkaller.appspot.com/x/.config?x=3c3d59be33cf7e9a
> dashboard link: https://syzkaller.appspot.com/bug?extid=0255c92c72505dcacba6
> compiler: Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8
> syz repro: https://syzkaller.appspot.com/x/repro.syz?x=143f8261580000
>
> Downloadable assets:
> disk image (non-bootable): https://storage.googleapis.com/syzbot-assets/d900f083ada3/non_bootable_disk-dc59e4fe.raw.xz
> vmlinux: https://storage.googleapis.com/syzbot-assets/9ee1f0ea24f2/vmlinux-dc59e4fe.xz
> kernel image: https://storage.googleapis.com/syzbot-assets/729e963a1370/bzImage-dc59e4fe.xz
>
> IMPORTANT: if you fix the issue, please add the following tag to the commit:
> Reported-by: syzbot+0255c92c72505dcacba6@syzkaller.appspotmail.com
...
> If the report is a duplicate of another one, reply with:
> #syz dup: exact-subject-of-another-report
#syz dup: [syzbot] [trace?] general protection fault in mtree_load
Oleg.
^ permalink raw reply
* Re: [PATCH] tracing: make tracepoint_printk static as not exported
From: Ben Dooks @ 2026-07-03 16:24 UTC (permalink / raw)
To: Steven Rostedt
Cc: Masami Hiramatsu, Mathieu Desnoyers, linux-kernel,
linux-trace-kernel
In-Reply-To: <20260702184658.0e0ffb02@gandalf.local.home>
On 02/07/2026 23:46, Steven Rostedt wrote:
> On Wed, 17 Jun 2026 11:58:22 +0100
> Ben Dooks <ben.dooks@codethink.co.uk> wrote:
>
>> The tracepoint_printk symbol is not exported, so make it
>> static to remove the following sparse warning:
>>
>> kernel/trace/trace.c:90:5: warning: symbol 'tracepoint_printk' was not declared. Should it be static?
>>
>> Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
>
> Thanks, this became only used by this file via commit dd293df6395a2
> ("tracing: Move trace sysctls into trace.c")
>
> I may add a Fixes tag to that commit.
>
> -- Steve
ok, thanks.
--
Ben Dooks http://www.codethink.co.uk/
Senior Engineer Codethink - Providing Genius
https://www.codethink.co.uk/privacy.html
^ permalink raw reply
* [syzbot] [trace?] [usb?] general protection fault in mas_start (2)
From: syzbot @ 2026-07-03 16:02 UTC (permalink / raw)
To: bp, dave.hansen, hpa, linux-kernel, linux-trace-kernel, linux-usb,
mhiramat, mingo, oleg, peterz, syzkaller-bugs, tglx, x86
Hello,
syzbot found the following issue on:
HEAD commit: dc59e4fea9d8 Linux 7.2-rc1
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=12610e1c580000
kernel config: https://syzkaller.appspot.com/x/.config?x=3c3d59be33cf7e9a
dashboard link: https://syzkaller.appspot.com/bug?extid=0255c92c72505dcacba6
compiler: Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=143f8261580000
Downloadable assets:
disk image (non-bootable): https://storage.googleapis.com/syzbot-assets/d900f083ada3/non_bootable_disk-dc59e4fe.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/9ee1f0ea24f2/vmlinux-dc59e4fe.xz
kernel image: https://storage.googleapis.com/syzbot-assets/729e963a1370/bzImage-dc59e4fe.xz
IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+0255c92c72505dcacba6@syzkaller.appspotmail.com
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000011: 0000 [#1] SMP KASAN NOPTI
KASAN: null-ptr-deref in range [0x0000000000000088-0x000000000000008f]
CPU: 0 UID: 0 PID: 5746 Comm: syz.3.20 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
RIP: 0010:mas_root lib/maple_tree.c:759 [inline]
RIP: 0010:mas_start+0xfe/0x550 lib/maple_tree.c:1179
Code: 4c 02 00 00 c6 43 4c 00 48 8b 44 24 28 42 80 3c 30 00 74 08 48 89 df e8 70 61 87 f6 4c 8b 23 49 83 c4 48 4c 89 e0 48 c1 e8 03 <42> 80 3c 30 00 74 08 4c 89 e7 e8 53 61 87 f6 4d 8b 24 24 e8 aa 9b
RSP: 0000:ffffc900034ff898 EFLAGS: 00010206
RAX: 0000000000000011 RBX: ffffc900034ff960 RCX: 1ffff9200069ff35
RDX: 1ffff9200069ff2c RSI: 0000000000000001 RDI: ffffc900034ff988
RBP: 0000000000000001 R08: ffffffff8baf8bfa R09: 0000000000000000
R10: 0000000000000000 R11: ffffffff8e959c20 R12: 0000000000000088
R13: ffffc900034ff960 R14: dffffc0000000000 R15: 1ffff9200069ff35
FS: 0000000000000000(0000) GS:ffff88808c815000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f53e2bc58d2 CR3: 000000000e746000 CR4: 0000000000352ef0
Call Trace:
<TASK>
mtree_load+0x1f5/0x780 lib/maple_tree.c:5657
vma_lookup include/linux/mm.h:4238 [inline]
__in_uprobe_trampoline arch/x86/kernel/uprobes.c:766 [inline]
__is_optimized arch/x86/kernel/uprobes.c:1056 [inline]
is_optimized arch/x86/kernel/uprobes.c:1067 [inline]
set_orig_insn+0x226/0x310 arch/x86/kernel/uprobes.c:1098
register_for_each_vma+0xa0e/0xb80 kernel/events/uprobes.c:1318
uprobe_unregister_nosync+0x118/0x1b0 kernel/events/uprobes.c:1343
bpf_uprobe_unregister kernel/trace/bpf_trace.c:2982 [inline]
bpf_uprobe_multi_link_release+0x99/0x1a0 kernel/trace/bpf_trace.c:2993
bpf_link_free+0xdd/0x3e0 kernel/bpf/syscall.c:3395
bpf_link_put_direct kernel/bpf/syscall.c:3448 [inline]
bpf_link_release+0x6b/0x80 kernel/bpf/syscall.c:3455
__fput+0x418/0xa50 fs/file_table.c:512
task_work_run+0x1d9/0x270 kernel/task_work.c:233
exit_task_work include/linux/task_work.h:40 [inline]
do_exit+0x73a/0x2360 kernel/exit.c:1004
__do_sys_exit kernel/exit.c:1114 [inline]
__se_sys_exit kernel/exit.c:1112 [inline]
__x64_sys_exit+0x40/0x40 kernel/exit.c:1112
x64_sys_call+0x2231/0x2240 arch/x86/include/generated/asm/syscalls_64.h:61
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7fd88699ce59
Code: Unable to access opcode bytes at 0x7fd88699ce2f.
RSP: 002b:00007fffde6e40f8 EFLAGS: 00000246 ORIG_RAX: 000000000000003c
RAX: ffffffffffffffda RBX: 00007fd886c15fa0 RCX: 00007fd88699ce59
RDX: 0000555576db0808 RSI: 0000000000000000 RDI: 0000000000000000
RBP: 00007fd886a32e6f R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007fd886c15fac R14: 00007fd886c15fa0 R15: 00007fd886c15fa0
</TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:mas_root lib/maple_tree.c:759 [inline]
RIP: 0010:mas_start+0xfe/0x550 lib/maple_tree.c:1179
Code: 4c 02 00 00 c6 43 4c 00 48 8b 44 24 28 42 80 3c 30 00 74 08 48 89 df e8 70 61 87 f6 4c 8b 23 49 83 c4 48 4c 89 e0 48 c1 e8 03 <42> 80 3c 30 00 74 08 4c 89 e7 e8 53 61 87 f6 4d 8b 24 24 e8 aa 9b
RSP: 0000:ffffc900034ff898 EFLAGS: 00010206
RAX: 0000000000000011 RBX: ffffc900034ff960 RCX: 1ffff9200069ff35
RDX: 1ffff9200069ff2c RSI: 0000000000000001 RDI: ffffc900034ff988
RBP: 0000000000000001 R08: ffffffff8baf8bfa R09: 0000000000000000
R10: 0000000000000000 R11: ffffffff8e959c20 R12: 0000000000000088
R13: ffffc900034ff960 R14: dffffc0000000000 R15: 1ffff9200069ff35
FS: 0000000000000000(0000) GS:ffff88808c815000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007fa41db45000 CR3: 0000000012fed000 CR4: 0000000000352ef0
----------------
Code disassembly (best guess):
0: 4c 02 00 rex.WR add (%rax),%r8b
3: 00 c6 add %al,%dh
5: 43 rex.XB
6: 4c 00 48 8b rex.WR add %r9b,-0x75(%rax)
a: 44 24 28 rex.R and $0x28,%al
d: 42 80 3c 30 00 cmpb $0x0,(%rax,%r14,1)
12: 74 08 je 0x1c
14: 48 89 df mov %rbx,%rdi
17: e8 70 61 87 f6 call 0xf687618c
1c: 4c 8b 23 mov (%rbx),%r12
1f: 49 83 c4 48 add $0x48,%r12
23: 4c 89 e0 mov %r12,%rax
26: 48 c1 e8 03 shr $0x3,%rax
* 2a: 42 80 3c 30 00 cmpb $0x0,(%rax,%r14,1) <-- trapping instruction
2f: 74 08 je 0x39
31: 4c 89 e7 mov %r12,%rdi
34: e8 53 61 87 f6 call 0xf687618c
39: 4d 8b 24 24 mov (%r12),%r12
3d: e8 .byte 0xe8
3e: aa stos %al,%es:(%rdi)
3f: 9b fwait
---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.
syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.
If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title
If you want syzbot to run the reproducer, reply with:
#syz test: git://repo/address.git branch-or-commit-hash
If you attach or paste a git patch, syzbot will apply it before testing.
If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)
If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report
If you want to undo deduplication, reply with:
#syz undup
^ permalink raw reply
* Re: [PATCH] tracing: Cleanup event_enable_trigger_parse() by using __free()
From: Steven Rostedt @ 2026-07-03 15:42 UTC (permalink / raw)
To: Markus Elfring
Cc: linux-trace-kernel, kernel-janitors, Masami Hiramatsu,
Mathieu Desnoyers, LKML
In-Reply-To: <d8f33e0a-b378-4dad-92b1-9ce2098c04f3@web.de>
On Fri, 3 Jul 2026 07:00:10 +0200
Markus Elfring <Markus.Elfring@web.de> wrote:
> > No, it's fine as is.
> Does this feedback mean that you disagree to an essential development requirement
> according to such a programming interface?
> https://elixir.bootlin.com/linux/v7.1.2/source/include/linux/cleanup.h#L142-L153
> * Given that the "__free(...) = NULL" pattern for variables defined at
> * the top of the function poses this potential interdependency problem
> * the recommendation is to always define and assign variables in one
> * statement and not group variable definitions at the top of the
> * function when __free() is used.
This is really just a guideline.
> *
> * Lastly, given that the benefit of cleanup helpers is removal of
> * "goto", and that the "goto" statement can jump between scopes, the
> * expectation is that usage of "goto" and cleanup helpers is never
> * mixed in the same function. I.e. for a given routine, convert all
> * resources that need a "goto" cleanup to scope-based cleanup, or
> * convert none of them.
The above has more to do with guard()s and not so much with a __free() at
the top of the function. The reason is because things get broken if a goto
jumps over a guard().
In other words, if you don't know what you are doing, don't mix them.
-- Steve
^ permalink raw reply
* Re: [RFC PATCH 1/1] psi: Introduce in-kernel PSI auto monitor feature
From: Pintu Kumar Agarwal @ 2026-07-03 15:32 UTC (permalink / raw)
To: K Prateek Nayak
Cc: linux-kernel, linux-trace-kernel, hannes, surenb, rostedt,
mhiramat, peterz, mathieu.desnoyers, mingo, juri.lelli,
vincent.guittot, dietmar.eggemann, bsegall, mgorman, vschneid,
pintu.ping, nathan, ojeda, nsc, gary, tglx, thomas.weissschuh,
aliceryhl, dianders, linux.amoon, rdunlap, akpm, shuah
In-Reply-To: <6c190305-4137-411f-ba25-e0a2d8484db7@amd.com>
Hi Prateek,
Thank you so much for your review feedback and comments.
Please find my response below.
On Fri, Jul 3, 2026 at 1:21 AM K Prateek Nayak <kprateek.nayak@amd.com> wrote:
>
> Hello Pintu,
>
> On 7/2/2026 10:46 PM, Pintu Kumar Agarwal wrote:
> > diff --git a/kernel/sched/build_utility.c b/kernel/sched/build_utility.c
> > index e2cf3b08d4e9..30e9800ce947 100644
> > --- a/kernel/sched/build_utility.c
> > +++ b/kernel/sched/build_utility.c
> > @@ -104,3 +104,7 @@
> > #ifdef CONFIG_SCHED_AUTOGROUP
> > # include "autogroup.c"
> > #endif
> > +
> > +#ifdef CONFIG_PSI_AUTO_MONITOR
> > +# include "psi_monitor.c"
> > +#endif
>
> Isn't this a module? Why is this being included as a scheduler file?
> Based on a quick glance, nothing in this module needs scheduler internal
> APIs (and nor it should) so tools/sched/ would probabaly be a better
> place to put it in if there is interest for this feature.
>
The scheduler placement was chosen because the feature currently
operates on PSI internals
and was developed as an extension to kernel/sched/psi.c.
I am open to alternative placement if another location is more appropriate.
> > diff --git a/kernel/sched/psi_monitor.c b/kernel/sched/psi_monitor.c
> > new file mode 100644
> > index 000000000000..e929a0c05494
> > --- /dev/null
> > +++ b/kernel/sched/psi_monitor.c
> > @@ -0,0 +1,307 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * PSI Automatic Monitor with Weighted Task Ranking + Tracepoints
> > + *
> > + * Periodically samples system PSI (CPU, memory, IO) and, when any
> > + * configured threshold is exceeded, ranks tasks using a composite
> > + * score based on RSS, I/O activity and CPU time, then logs the
> > + * top-N tasks via printk and a tracepoint.
> > + *
> > + * Sysfs interface:
> > + * /sys/kernel/psi_monitor/cpu_thresh (percentage)
> > + * /sys/kernel/psi_monitor/mem_thresh (percentage)
> > + * /sys/kernel/psi_monitor/io_thresh (percentage)
> > + * /sys/kernel/psi_monitor/monitor_interval_ms (milliseconds)
> > + * /sys/kernel/psi_monitor/rss_weight
> > + * /sys/kernel/psi_monitor/io_weight
> > + * /sys/kernel/psi_monitor/cpu_weight
> > + *
> > + * Author: Pintu Kumar Agarwal
> > + */
> > +
> > +#include <linux/init.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/sched.h>
> > +#include <linux/sched/signal.h>
> > +#include <linux/sched/loadavg.h>
> > +#include <linux/mm.h>
> > +#include <linux/delay.h>
> > +#include <linux/workqueue.h>
> > +#include <linux/psi_types.h>
> > +#include <linux/kobject.h>
> > +#include <linux/sort.h>
> > +#include <linux/jiffies.h>
> > +#include <linux/time64.h>
> > +#include <linux/sched/cputime.h>
> > +
> > +/* Create tracepoints defined in include/trace/events/psi_monitor.h */
> > +#define CREATE_TRACE_POINTS
> > +#include <linux/psi.h>
> > +#include <trace/events/psi_monitor.h>
> > +
> > +
> > +/* Sysfs tunables */
> > +static unsigned int cpu_thresh = 80; /* in percent */
> > +static unsigned int mem_thresh = 80; /* in percent */
> > +static unsigned int io_thresh = 80; /* in percent */
> > +static unsigned int monitor_interval_ms = 10000;
> > +
> > +/* scoring weights */
> > +static unsigned int rss_weight = 2;
> > +static unsigned int io_weight = 1;
> > +static unsigned int cpu_weight = 5;
>
> Insanely configurable but what makes it easy for developers to know
> the right configurations under severe pressure as you put it?
>
This is one of the goal of RFC to decide what parameters should be
kept configurable
and to what default values. Currently it is at experimental stage and
gathering feedback.
As per my experiments (2 core, < 1GB RAM), 80% number is good enough as default.
This triggers only during extreme pressure, otherwise kept silent.
Based on the scenario and workload, users can configure it.
Run scenario => check workload => configure => rerun
Scoring weight values are optional and it depends on which load we
want to give priority.
These are open for discussions and only needed for sorting logic.
> > +
> > +static struct delayed_work psi_work;
> > +static struct kobject *psi_kobj;
> > +
> > +#define TOP_N 20
> > +
> > +struct task_info {
> > + struct task_struct *task;
> > + unsigned long rss; /* pages */
> > + unsigned long io_kb; /* kB */
> > + unsigned long cpu_ms; /* ms */
>
> Isn't the suffix selfexplanatory? Do you really need the comments?
>
oh yes, this can be removed if not needed.
> > + u64 score;
> > +};
> > +
> > +/*
> > + * psi_avg10_percent() - derive a rough integer percentage from avg10
> > + * for a given PSI state (e.g. PSI_CPU_SOME, PSI_MEM_SOME, PSI_IO_SOME).
> > + *
> > + * psi_group.avg[state][0] is the avg10 window in fixed-point notation.
> > + * The conversion here is approximate but monotonic, which is sufficient
> > + * for thresholding and ranking in this internal monitor.
> > + */
> > +static unsigned long psi_avg10_percent(int state)
> > +{
> > + u64 avg10;
> > +
> > + if (state < 0 || state >= NR_PSI_STATES)
> > + return 0;
> > +
> > + avg10 = READ_ONCE(psi_system.avg[state][0]);
> > + if (!avg10)
> > + return 0;
> > +
> > + /* Convert back from loadavg-style fixed-point to an approximate % */
> > + /* Just consider the integer value and ignore fraction */
>
> Why two single line comments?
>
ok I will merge it in the next version.
> > + return LOAD_INT(avg10);
> > +}
> > +
> > +static int compare_score_desc(const void *a, const void *b)
> > +{
> > + const struct task_info *ta = a;
> > + const struct task_info *tb = b;
> > +
> > + if (tb->score > ta->score)
> > + return 1;
> > + if (tb->score < ta->score)
> > + return -1;
> > + return 0;
> > +}
> > +
> > +static void log_top_tasks(void)
> > +{
> > + struct task_info tasks[TOP_N];
> > + struct task_struct *p, *t;
> > + int count = 0;
> > + int i;
> > +
> > + rcu_read_lock();
> > + for_each_process_thread(p, t) {
>
> Thats a ton of work every 10s.
>
This happens only when the threshold is breached and the system is
already under pressure.
Based on the feedback we can rate-limit this.
> > + struct mm_struct *mm;
> > + unsigned long rss = 0;
> > + unsigned long io_kb = 0;
> > + unsigned long cpu_ms = 0;
> > + u64 score;
> > +
> > + /* Ignore tasks that are not on run queue or idle */
> > + if (!t->on_rq && !is_idle_task(t))
>
> Condition doesn't match the comment. Tasks off rq that aren't idle will
> still go through.
>
Oh yes, good catch. I will fix the comment in the next version.
> > + continue;
> > +
> > + mm = get_task_mm(t);
> > +
> > + /* mm could be NULL for kernel threads */
> > + if (mm) {
> > + rss = mm ? get_mm_rss(mm) : 0;
> > + mmput_async(mm);
> > + }
> > +
> > + /*
> > + * Approximate I/O activity: sum of read + write bytes.
> > + * This uses the task_io_accounting fields in task_struct.
> > + * Values are best-effort and need not be perfectly accurate
> > + * for our ranking purpose.
> > + */
> > + io_kb = (t->ioac.read_bytes + t->ioac.write_bytes) >> 10;
> > +
> > + /*
> > + * Approximate CPU usage via task_sched_runtime(), converted
> > + * to milliseconds. This is cumulative since task start, but
> > + * is still useful for comparing hotspots at a given point.
> > + */
> > + cpu_ms = (unsigned long)(task_sched_runtime(t) / NSEC_PER_MSEC);
> > +
> > + score = (u64)rss_weight * (u64)rss +
> > + (u64)io_weight * (u64)io_kb +
> > + (u64)cpu_weight * (u64)cpu_ms;
> > +
> > + if (count < TOP_N) {
> > + tasks[count].task = t;
> > + tasks[count].rss = rss;
> > + tasks[count].io_kb = io_kb;
> > + tasks[count].cpu_ms = cpu_ms;
> > + tasks[count].score = score;
> > + count++;
> > + } else {
> > + /* Maintain a simple streaming top-N: replace smallest */
> > + int min_idx = 0;
> > + int j;
> > +
> > + for (j = 1; j < TOP_N; j++) {
> > + if (tasks[j].score < tasks[min_idx].score)
> > + min_idx = j;
> > + }
>
> Can't you just cache the min_idx and re-compute it when it changes
> instead of taking a O(20) iteration for every task?
>
ok will think about it and come back.
IMO the constant value may not affect the order.
Currently at RFC stage I wanted to keep things as simple.
> > +
> > + if (score > tasks[min_idx].score) {
> > + tasks[min_idx].task = t;
> > + tasks[min_idx].rss = rss;
> > + tasks[min_idx].io_kb = io_kb;
> > + tasks[min_idx].cpu_ms = cpu_ms;
> > + tasks[min_idx].score = score;
> > + }
> > + }
> > + }
> > + rcu_read_unlock();
> > +
> > + sort(tasks, count, sizeof(struct task_info), compare_score_desc, NULL);
> > +
> > + pr_info("psi_monitor: logging top %d tasks under pressure:\n", count);
> > +
> > + for (i = 0; i < count; i++) {
> > + struct task_struct *ts = tasks[i].task;
> > + unsigned long rss_kb = tasks[i].rss << (PAGE_SHIFT - 10);
> > + char name[128] = {0,};
> > +
> > + if (ts->flags & PF_WQ_WORKER)
> > + wq_worker_comm(name, sizeof(name), ts);
> > + else
> > + scnprintf(name, sizeof(name) - 1, ts->comm);
> > +
> > + trace_psi_monitor_top_task(ts->pid, name,
> > + tasks[i].cpu_ms,
> > + rss_kb,
> > + tasks[i].io_kb,
> > + tasks[i].score);
> > +
> > + pr_info("psi_monitor: pid=%d comm=%s psi_flag=%d oncpu=%d cputime(ms)=%lu rss(kB)=%lu io(kB)=%lu score=%llu\n",
> > + ts->pid, name, ts->psi_flags, task_cpu(ts),
> > + tasks[i].cpu_ms, rss_kb, tasks[i].io_kb,
> > + (unsigned long long)tasks[i].score);
>
> This will unnecessarily dump to dmesg even if you have tracevent
> enabled. Why?
>
This is also one point of discussion for RFC.
Currently have kept both the options available and open for suggestion.
The idea is to dump it like OOM message and only during pressure and
threshold breach when we really need it.
Once the pressure releases this will automatically stop.
We can also make it as pr_debug or ratelimit or even put it under
another CONFIG.
The idea is to automatically get the information in logs instead of
user intervention.
But I am open for suggestions.
> > + }
> > +}
> > +
> > +static void psi_monitor_fn(struct work_struct *work)
> > +{
> > + unsigned long cpu_pct, mem_pct, io_pct;
> > + bool trigger = false;
> > +
> > + cpu_pct = psi_avg10_percent(PSI_CPU_SOME);
> > + mem_pct = psi_avg10_percent(PSI_MEM_SOME);
> > + io_pct = psi_avg10_percent(PSI_IO_SOME);
> > +
> > + if (cpu_pct >= cpu_thresh || mem_pct >= mem_thresh ||
> > + io_pct >= io_thresh)
> > + trigger = true;
> > +
> > + if (trigger) {
> > + pr_info("psi_monitor: pressure high: cpu=%lu%% mem=%lu%% io=%lu%% (thresh cpu=%u mem=%u io=%u)\n",
> > + cpu_pct, mem_pct, io_pct,
> > + cpu_thresh, mem_thresh, io_thresh);
> > + log_top_tasks();
> > + }
> > +
> > + queue_delayed_work(system_wq, &psi_work,
> > + msecs_to_jiffies(monitor_interval_ms));
>
> If I set monitor_interval_ms to 6 hours, and then change it back to 10s,
> it'll only take effect after this callback has fired 6 hours later.
>
Oh yes, good catch, I will fix this in the next version.
So, it should override with the new request.
> > +}
> > +
> > +/* Sysfs helpers */
> > +#define PSI_ATTR_RW(_name) \
> > +static ssize_t _name##_show(struct kobject *kobj, \
> > + struct kobj_attribute *attr, char *buf) \
> > +{ \
> > + return sysfs_emit(buf, "%u\n", _name); \
> > +} \
> > +static ssize_t _name##_store(struct kobject *kobj, \
> > + struct kobj_attribute *attr, \
> > + const char *buf, size_t count) \
> > +{ \
> > + unsigned int val; \
> > + if (kstrtouint(buf, 10, &val)) \
> > + return -EINVAL; \
> > + _name = val; \
> > + return count; \
> > +} \
> > +static struct kobj_attribute _name##_attr = __ATTR_RW(_name)
> > +
> > +PSI_ATTR_RW(cpu_thresh);
> > +PSI_ATTR_RW(mem_thresh);
> > +PSI_ATTR_RW(io_thresh);
> > +PSI_ATTR_RW(monitor_interval_ms);
> > +PSI_ATTR_RW(rss_weight);
> > +PSI_ATTR_RW(io_weight);
> > +PSI_ATTR_RW(cpu_weight);
> > +
> > +static struct attribute *psi_attrs[] = {
> > + &cpu_thresh_attr.attr,
> > + &mem_thresh_attr.attr,
> > + &io_thresh_attr.attr,
> > + &monitor_interval_ms_attr.attr,
> > + &rss_weight_attr.attr,
> > + &io_weight_attr.attr,
> > + &cpu_weight_attr.attr,
> > + NULL,
> > +};
> > +
> > +static const struct attribute_group psi_attr_group = {
> > + .attrs = psi_attrs,
> > +};
> > +
> > +static int __init psi_monitor_init(void)
> > +{
> > + int ret;
> > +
> > + INIT_DELAYED_WORK(&psi_work, psi_monitor_fn);
> > + queue_delayed_work(system_wq, &psi_work,
> > + msecs_to_jiffies(monitor_interval_ms));
> > +
> > + psi_kobj = kobject_create_and_add("psi_monitor", kernel_kobj);
> > + if (!psi_kobj)
> > + return -ENOMEM;
> > +
> > + ret = sysfs_create_group(psi_kobj, &psi_attr_group);
> > + if (ret) {
> > + kobject_put(psi_kobj);
> > + cancel_delayed_work_sync(&psi_work);
> > + return ret;
> > + }
> > +
> > + pr_info("psi_monitor: in-kernel PSI auto monitor (weighted + tracepoints) loaded\n");
> > + return 0;
> > +}
> > +
> > +static void __exit psi_monitor_exit(void)
> > +{
> > + cancel_delayed_work_sync(&psi_work);
> > + if (psi_kobj)
> > + kobject_put(psi_kobj);
> > + pr_info("psi_monitor: unloaded\n");
> > +}
> > +
> > +module_init(psi_monitor_init);
> > +module_exit(psi_monitor_exit);
>
> There is nothing here that warrants putting this in kernel/sched.
The feature depends on sched/psi so I decided to keep it close.
But I am open for any location.
> Also this gets included by default when config is enabled and starts
> dumping a bunch of stats to dmesg without anyone asking. No?
>
This is included as a dependent feature of PSI.
If someone enables this CONFIG as part of PSI this indicates that they
are interested in getting auto-monitor stats.
Also, the dump will happen only if threshold is breached with high
default values.
However, for RFC stage I wanted to keep things simple.
Later, we can add an enable/disable flag in cmdline just like PSI.
> Afaict, almost all of the detail used here is also available from
> procfs and people can easily put together a userspace tool if they
> need it. Why do we need an in-kernel module?
>
This is the most fundamental aspect of this auto-monitor feature.
This point is already described in the cover letter.
Let me put it again:
- Get kernel stats early during boot_time before userspace comes up.
-> Set slightly lower threshold and boot stats (helps in analysing boot time)
- No user intervention or continuous polling or daemons needed
(Just enable config and start auto monitoring)
- userspace scheduling delays under high pressure
- risk of missing short-lived spikes
- capturing details as soon as pressure hits and at same timestamp
- useful for analysing real-time latency workload.
- useful for minimal environment like initramfs or busybox
The motivation is not to replace existing PSI interfaces or the ability
to build userspace monitoring tools.
The goal is attribution at the moment pressure thresholds are crossed.
A userspace implementation observes the system after being scheduled,
whereas the in-kernel implementation captures contributors at the point
where pressure is detected.
During LPC-2024 I have done significant changes to core psi module
to implement the similar logic.
But the feedback was not to disturb the core psi interface, instead
develop a separate interface and make it configurable.
So, I came up with this auto-monitor idea.
For more details please have a look at my OSS paper with data.
https://hosted-files.sched.co/ossindia2026/19/OSS-IND-26-PSI-Auto-Monitor.pdf
And also the reference data here:
https://github.com/pintuk/KERNEL/tree/master/PSI_WORK
I am also looking out for someone who can test this on a larger
workload and capture data.
This will help us to gather insights, how the feature behaves.
> > +
> > +MODULE_LICENSE("GPL");
> > +MODULE_AUTHOR("Pintu Kumar Agarwal");
> > +MODULE_DESCRIPTION("In-kernel PSI automatic monitor with sysfs, weighted scoring and tracepoints");
> > --
> > 2.34.1
> >
>
> --
> Thanks and Regards,
> Prateek
>
Thanks,
Pintu
^ permalink raw reply
* [PATCH v2 2/2] i2c: qcom-geni: Add trace events for Qualcomm GENI I2C driver
From: Praveen Talari @ 2026-07-03 15:08 UTC (permalink / raw)
To: Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Mukesh Kumar Savaliya, Viken Dadhaniya, Andi Shyti
Cc: linux-kernel, linux-trace-kernel, linux-arm-msm, linux-i2c,
aniket.randive, chandana.chiluveru, Praveen Talari, Konrad Dybcio
In-Reply-To: <20260703-add-tracepoints-for-qcom-geni-i2c-v2-0-e8bf8b178290@oss.qualcomm.com>
Add trace event definitions for the Qualcomm GENI (Generic Interface)
I2C driver. These trace events enable runtime debugging and performance
analysis of I2C operations.
The trace events capture I2C clock configuration, interrupt status and
error code and message.
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Praveen Talari <praveen.talari@oss.qualcomm.com>
---
drivers/i2c/busses/i2c-qcom-geni.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 96dbf04138be..3227fab6d76e 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -1,6 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+#define CREATE_TRACE_POINTS
+#include <trace/events/qcom_geni_i2c.h>
+
#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/dmaengine.h>
@@ -219,6 +222,9 @@ static int qcom_geni_i2c_conf(struct geni_se *se, unsigned long freq)
val |= itr->t_low_cnt << LOW_COUNTER_SHFT;
val |= itr->t_cycle_cnt;
writel_relaxed(val, gi2c->se.base + SE_I2C_SCL_COUNTERS);
+ trace_geni_i2c_bus_setup(gi2c->se.dev, gi2c->clk_freq_out,
+ itr->clk_div, itr->t_high_cnt,
+ itr->t_low_cnt, itr->t_cycle_cnt);
return 0;
}
@@ -252,6 +258,8 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
dev_dbg(gi2c->se.dev, "len:%d, slv-addr:0x%x, RD/WR:%d\n",
gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags);
+ trace_geni_i2c_err(gi2c->se.dev, gi2c_log[err].err, gi2c_log[err].msg);
+
switch (err) {
case GENI_ABORT_DONE:
gi2c->abort_done = true;
@@ -288,6 +296,8 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev)
dma = readl_relaxed(base + SE_GENI_DMA_MODE_EN);
cur = gi2c->cur;
+ trace_geni_i2c_irq(gi2c->se.dev, m_stat, rx_st, dm_tx_st, dm_rx_st);
+
if (!cur ||
m_stat & (M_CMD_FAILURE_EN | M_CMD_ABORT_EN) ||
dm_rx_st & (DM_I2C_CB_ERR)) {
@@ -788,6 +798,10 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i
peripheral.set_config = 1;
peripheral.multi_msg = false;
+ trace_geni_i2c_bus_setup(gi2c->se.dev, gi2c->clk_freq_out,
+ itr->clk_div, itr->t_high_cnt,
+ itr->t_low_cnt, itr->t_cycle_cnt);
+
gi2c->num_msgs = num;
gi2c->is_tx_multi_desc_xfer = false;
@@ -895,6 +909,7 @@ static int geni_i2c_fifo_xfer(struct geni_i2c_dev *gi2c,
m_param |= ((msgs[i].addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK);
gi2c->cur = &msgs[i];
+
if (msgs[i].flags & I2C_M_RD)
ret = geni_i2c_rx_one_msg(gi2c, &msgs[i], m_param);
else
--
2.34.1
^ permalink raw reply related
* [PATCH v2 1/2] i2c: qcom-geni: trace: Add trace events for Qualcomm GENI I2C
From: Praveen Talari @ 2026-07-03 15:08 UTC (permalink / raw)
To: Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Mukesh Kumar Savaliya, Viken Dadhaniya, Andi Shyti
Cc: linux-kernel, linux-trace-kernel, linux-arm-msm, linux-i2c,
aniket.randive, chandana.chiluveru, Praveen Talari
In-Reply-To: <20260703-add-tracepoints-for-qcom-geni-i2c-v2-0-e8bf8b178290@oss.qualcomm.com>
Add trace event support to the Qualcomm GENI I2C driver to enable
detailed runtime debugging and analysis.
The trace events capture I2C clock configuration, interrupt status
and error code and message.
Reviewed-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Praveen Talari <praveen.talari@oss.qualcomm.com>
---
include/trace/events/qcom_geni_i2c.h | 82 ++++++++++++++++++++++++++++++++++++
1 file changed, 82 insertions(+)
diff --git a/include/trace/events/qcom_geni_i2c.h b/include/trace/events/qcom_geni_i2c.h
new file mode 100644
index 000000000000..c7e7984f3620
--- /dev/null
+++ b/include/trace/events/qcom_geni_i2c.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM qcom_geni_i2c
+
+#if !defined(_TRACE_QCOM_GENI_I2C_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_QCOM_GENI_I2C_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(geni_i2c_bus_setup,
+ TP_PROTO(struct device *dev, u32 clk_freq, u8 clk_div,
+ u8 t_high_cnt, u8 t_low_cnt, u8 t_cycle_cnt),
+ TP_ARGS(dev, clk_freq, clk_div, t_high_cnt, t_low_cnt, t_cycle_cnt),
+
+ TP_STRUCT__entry(__string(name, dev_name(dev))
+ __field(u32, clk_freq)
+ __field(u8, clk_div)
+ __field(u8, t_high_cnt)
+ __field(u8, t_low_cnt)
+ __field(u8, t_cycle_cnt)
+ ),
+
+ TP_fast_assign(__assign_str(name);
+ __entry->clk_freq = clk_freq;
+ __entry->clk_div = clk_div;
+ __entry->t_high_cnt = t_high_cnt;
+ __entry->t_low_cnt = t_low_cnt;
+ __entry->t_cycle_cnt = t_cycle_cnt;
+ ),
+
+ TP_printk("%s: clk_freq=%u clk_div=%u t_high=%u t_low=%u t_cycle=%u",
+ __get_str(name), __entry->clk_freq, __entry->clk_div,
+ __entry->t_high_cnt, __entry->t_low_cnt,
+ __entry->t_cycle_cnt)
+);
+
+TRACE_EVENT(geni_i2c_irq,
+ TP_PROTO(struct device *dev, u32 m_stat, u32 rx_st,
+ u32 dm_tx_st, u32 dm_rx_st),
+ TP_ARGS(dev, m_stat, rx_st, dm_tx_st, dm_rx_st),
+
+ TP_STRUCT__entry(__string(name, dev_name(dev))
+ __field(u32, m_stat)
+ __field(u32, rx_st)
+ __field(u32, dm_tx_st)
+ __field(u32, dm_rx_st)
+ ),
+
+ TP_fast_assign(__assign_str(name);
+ __entry->m_stat = m_stat;
+ __entry->rx_st = rx_st;
+ __entry->dm_tx_st = dm_tx_st;
+ __entry->dm_rx_st = dm_rx_st;
+ ),
+
+ TP_printk("%s: m_stat=0x%08x rx_st=0x%08x dm_tx=0x%08x dm_rx=0x%08x",
+ __get_str(name), __entry->m_stat, __entry->rx_st,
+ __entry->dm_tx_st, __entry->dm_rx_st)
+);
+
+TRACE_EVENT(geni_i2c_err,
+ TP_PROTO(struct device *dev, int err, const char *msg),
+ TP_ARGS(dev, err, msg),
+
+ TP_STRUCT__entry(__string(name, dev_name(dev))
+ __field(int, err)
+ __string(msg, msg)
+ ),
+
+ TP_fast_assign(__assign_str(name);
+ __entry->err = err;
+ __assign_str(msg);
+ ),
+
+ TP_printk("%s: err=%d msg=%s",
+ __get_str(name), __entry->err, __get_str(msg))
+);
+
+#endif /* _TRACE_QCOM_GENI_I2C_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
--
2.34.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox