[PATCH 0/2] x86/fred: Fix stack depot exhaustion on FRED systems

2 views
Skip to first unread message

Yuanhe Shu

unread,
Aug 27, 2026, 11:00:45 AMAug 27
to tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, pet...@infradead.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, kasa...@googlegroups.com, linux-...@vger.kernel.org, Yuanhe Shu
FRED replaces the IDT event entry stubs with asm_fred_entrypoint_user and
asm_fred_entrypoint_kernel, which live in .noinstr.text. The IDT stubs
are the only code covered by __irqentry_text_start..__irqentry_text_end,
which in_irqentry_text() uses to find where an event entered the kernel.
With FRED the detection fails, filter_irq_stacks() no longer truncates
event stacks, and every trace saved from interrupt or exception context
by stack depot users (KASAN alloc/free tracking, SLUB object tracking,
...) becomes a unique combination of "event path x arbitrarily
interrupted context". The depot grows without bound until it is
exhausted.

What we saw: a FRED-capable dual-socket system with KASAN (generic,
inline) and SLUB object tracking enabled hit the limit on both sockets
roughly 80 minutes after boot,

Stack depot reached limit capacity
WARNING: CPU: 286 PID: 128614 at lib/stackdepot.c:271 depot_alloc_stack+0x158/0x170

after which KASAN and SLUB stack tracking silently stop recording (new
traces get handle 0) until reboot. The recorded traces confirmed the
mechanism: interrupt side traces ran through asm_fred_entrypoint_kernel
and continued into the frames of the interrupted task.

Patch 1 adds an optional arch_in_irqentry_text() hook to the generic
in_irqentry_text() check; no behavior change by itself. Patch 2
implements it for x86 by bracketing the FRED entry text with
__fred_entry_text_start/end, the same way the IDT stubs are bracketed,
and makes X86_FRED select the new Kconfig symbol.

Unlike arm64 and s390, which hit the same symptom and could fix it by
placing their interrupt entry code in .irqentry.text, x86 has no such
section: it emits the markers as labels around the sequentially laid out
IDT stubs and defines __irq_entry to __invalid_section so that nothing
can land in that section. The FRED entry points therefore cannot be
brought inside the existing range, and a second one has to be reported;
see patch 2 for the details.

Testing:

- Build-tested on mainline: full vmlinux builds and link with
CONFIG_X86_FRED=y, CONFIG_X86_KERNEL_IBT=y and KASAN (generic,
inline), with and without CONFIG_KVM_INTEL=y; objtool link stage
clean.
- Runtime-tested by backporting both patches to the affected kernel (a
6.6 based debug build) and rebooting that system with an unchanged
command line: traces recorded from FRED event context now end at
asm_fred_entrypoint_kernel instead of continuing into the
interrupted task, and the pool count levels off at ~1230 pools
within minutes of boot instead of reaching the 8192 pool limit.

Reproducing on current upstream:

- On FRED hardware, any KASAN or SLUB_DEBUG kernel; on v6.17 and
later, boot with stack_depot_max_pools=1024 to bring the
exhaustion warning up in minutes instead of hours, and watch the
pool count in /sys/kernel/debug/stackdepot/stats grow
monotonically without the fix and converge with it.
- Without FRED hardware, the KVM VMX interrupt forwarding path
(CONFIG_X86_FRED=y + CONFIG_KVM_INTEL) exercises the new filtering
as well, see patch 2.

Both patches are Cc'ed to stable and 2/2 depends on 1/2, so please pick
them up as a pair. Patch 1 touches kernel/stacktrace.c and lib/Kconfig;
routing the series through tip:x86/entry with an Acked-by from Andrew
for 1/2 is probably the smoothest path.

Yuanhe Shu (2):
stacktrace: Provide arch_in_irqentry_text() hook
x86/fred: Fix stack depot filtering of FRED event stacks

arch/x86/Kconfig | 1 +
arch/x86/entry/entry_64_fred.S | 14 ++++++++++++++
arch/x86/include/asm/sections.h | 1 +
arch/x86/kernel/stacktrace.c | 13 +++++++++++++
include/linux/stacktrace.h | 16 ++++++++++++++++
kernel/stacktrace.c | 3 ++-
lib/Kconfig | 3 +++
7 files changed, 50 insertions(+), 1 deletion(-)

base-commit: 45c13f3f9e3bb15fd89ff2864c6f627a3b4b4229
--
2.43.5

Yuanhe Shu

unread,
Aug 27, 2026, 11:00:47 AMAug 27
to tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, pet...@infradead.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, kasa...@googlegroups.com, linux-...@vger.kernel.org, Yuanhe Shu, sta...@vger.kernel.org
With FRED, events are delivered to asm_fred_entrypoint_user and
asm_fred_entrypoint_kernel in .noinstr.text, not to the IDT stubs, which
are the only code covered by __irqentry_text_start..__irqentry_text_end.
in_irqentry_text() therefore never recognizes the event entry point and
filter_irq_stacks() does not truncate FRED event stacks: every trace
saved from interrupt or exception context by stack depot users such as
KASAN alloc/free tracking or SLUB object tracking combines the event path
with the arbitrarily interrupted context. The number of unique stacks
grows with the product of both and the depot is exhausted.

Observed on a dual-socket FRED-capable system with KASAN (generic,
inline) and SLUB object tracking enabled, on both sockets roughly 80
minutes after boot, once the depot had reached its maximum of 8192 pools
(128 MiB):

Stack depot reached limit capacity
WARNING: CPU: 286 PID: 128614 at lib/stackdepot.c:271 depot_alloc_stack+0x158/0x170

The traces had the expected shape: an interrupt side trace ran through
asm_fred_entrypoint_kernel into the frames of the task it had
interrupted. New traces are dropped (handle 0) from then on and the
depot never shrinks, so tracking stays dead until reboot. (Splat from a
6.6 based kernel; filter_irq_stacks() and the FRED entry layout are
unchanged in mainline.)

The entry points cannot be brought inside that range. x86 has no
.irqentry.text: commit f0178fc01fe4 ("x86/entry: Unbreak
__irqentry_text_start/end magic") dropped it from the linker script and
emits the markers as labels around the sequentially laid out IDT stubs
instead, exactly because the entry rework had moved that code into
.noinstr.text and broken the function graph tracer and
filter_irq_stacks(); __irq_entry has been __invalid_section since.
Those labels live inside entry_64.S and wrap the IDT stubs which
asm/idtentry.h emits into .entry.text, so the linker cannot place
another translation unit between them, and the FRED entry points cannot
join that block without leaving .noinstr.text. Architectures which do
have the section fixed the same symptom locally, e.g.
commit f6794950f0e5 ("arm64: set __exception_irq_entry with __irq_entry
as a default") and commit 45c9f2b856a0 ("s390/entry: Mark IRQ entries
to fix stack depot warnings").

Every FRED event leaves a return address in the FRED entry text: the
return address of the call to fred_entry_from_user/kernel, or a frame of
asm_fred_entry_from_kvm(), which the core entry code uses to forward VMX
interrupts and NMIs acknowledged as part of the VM-Exit; see
commit 0701c9e17bd9 ("x86/kvm/vmx: Move IRQ/NMI dispatch from KVM
into x86 core"). So bracket it with __fred_entry_text_start/end, the
same way the IDT stubs are bracketed, and report that range from
arch_in_irqentry_text(). Verified on that system with the fix
backported: traces from FRED event context now end at
asm_fred_entrypoint_kernel (/sys/kernel/debug/slab/*/alloc_traces) and
the pool count levels off a few minutes after boot instead of climbing
to the limit.

Truncating synchronous exception stacks only restores parity with the IDT
range, which has always covered the exception stubs too. Syscalls enter
through asm_fred_entrypoint_user as well, but there the entry frame is
already the last trace entry, so filter_irq_stacks() returns the full
trace unchanged. The function graph tracer uses the same markers and has
the same gap; it can be converted separately.

This is not limited to FRED hardware: with CONFIG_X86_FRED=y the KVM
forwarding path above runs the FRED dispatch code even when the kernel
itself uses the IDT, so KVM host stacks take the same untruncated path
on non-FRED systems, albeit from a mostly fixed vcpu_run chain.

Fixes: 14619d912b65 ("x86/fred: FRED entry/exit and dispatch code")
Cc: sta...@vger.kernel.org # v6.9+
Signed-off-by: Yuanhe Shu <xian...@linux.alibaba.com>
---
Build tested with CONFIG_X86_FRED=y and CONFIG_X86_KERNEL_IBT=y, with
and without CONFIG_KVM_INTEL: __fred_entry_text_start lands on the
4K-aligned asm_fred_entrypoint_user and the new range stays inside
.noinstr.text.

Note for stable: depends on patch 1/2.

arch/x86/Kconfig | 1 +
arch/x86/entry/entry_64_fred.S | 14 ++++++++++++++
arch/x86/include/asm/sections.h | 1 +
arch/x86/kernel/stacktrace.c | 13 +++++++++++++
4 files changed, 29 insertions(+)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 15fd9ec5ecac..78b8eb4a925f 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -555,6 +555,7 @@ config X86_CPU_RESCTRL_INTEL_AET
config X86_FRED
bool "Flexible Return and Event Delivery"
depends on X86_64
+ select ARCH_HAS_IN_IRQENTRY_TEXT
help
When enabled, use Flexible Return and Event Delivery
instead of the legacy SYSCALL/SYSENTER/IDT architecture for
diff --git a/arch/x86/entry/entry_64_fred.S b/arch/x86/entry/entry_64_fred.S
index b98f8945dfff..620def9039a3 100644
--- a/arch/x86/entry/entry_64_fred.S
+++ b/arch/x86/entry/entry_64_fred.S
@@ -36,6 +36,17 @@
*/
.align 4096

+/*
+ * Bounds of the FRED event entry text. Every event delivered by FRED
+ * enters here, including events which the core entry code forwards
+ * through asm_fred_entry_from_kvm(). This is the FRED counterpart of
+ * __irqentry_text_start..__irqentry_text_end and lets
+ * in_irqentry_text() find the event entry point of a stack, see
+ * arch_in_irqentry_text().
+ */
+ .globl __fred_entry_text_start
+__fred_entry_text_start:
+
SYM_CODE_START_NOALIGN(asm_fred_entrypoint_user)
FRED_ENTER
call fred_entry_from_user
@@ -150,3 +161,6 @@ SYM_FUNC_START(asm_fred_entry_from_kvm)

SYM_FUNC_END(asm_fred_entry_from_kvm)
#endif
+
+ .globl __fred_entry_text_end
+__fred_entry_text_end:
diff --git a/arch/x86/include/asm/sections.h b/arch/x86/include/asm/sections.h
index 30e8ee7006f9..1b52239fcefd 100644
--- a/arch/x86/include/asm/sections.h
+++ b/arch/x86/include/asm/sections.h
@@ -5,6 +5,7 @@
#include <asm-generic/sections.h>
#include <asm/extable.h>

+extern char __fred_entry_text_start[], __fred_entry_text_end[];
extern char __relocate_kernel_start[], __relocate_kernel_end[];
extern char __brk_base[], __brk_limit[];
extern char __end_rodata_aligned[];
diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c
index ee117fcf46ed..4af7e52d9d97 100644
--- a/arch/x86/kernel/stacktrace.c
+++ b/arch/x86/kernel/stacktrace.c
@@ -9,6 +9,7 @@
#include <linux/stacktrace.h>
#include <linux/export.h>
#include <linux/uaccess.h>
+#include <asm/sections.h>
#include <asm/stacktrace.h>
#include <asm/unwind.h>

@@ -128,3 +129,15 @@ void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie,
}
}

+#ifdef CONFIG_X86_FRED
+bool arch_in_irqentry_text(unsigned long addr)
+{
+ /*
+ * FRED delivers events to entry points in .noinstr.text, which
+ * __irqentry_text_start..__irqentry_text_end does not cover. See
+ * __fred_entry_text_start in entry_64_fred.S.
+ */
+ return addr >= (unsigned long)__fred_entry_text_start &&
+ addr < (unsigned long)__fred_entry_text_end;
+}
+#endif
--
2.43.5

Yuanhe Shu

unread,
Aug 27, 2026, 11:00:49 AMAug 27
to tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, pet...@infradead.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, kasa...@googlegroups.com, linux-...@vger.kernel.org, Yuanhe Shu, sta...@vger.kernel.org
in_irqentry_text() decides whether a stack address belongs to interrupt
entry code by checking the .irqentry.text and .softirqentry.text section
ranges. filter_irq_stacks() uses it to truncate interrupt stacks at the
entry point, which stack depot depends on to deduplicate them: traces
that continue past the interrupt entry lead to unbounded depot growth,
see commit e94006608949 ("lib/stackdepot: always do filter_irq_stacks()
in stack_depot_save()").

An architecture may deliver interrupts through entry code that cannot be
placed in .irqentry.text. in_irqentry_text() then never recognizes the
entry point and the truncation silently stops happening. The markers are
meant to cover all interrupt entry functions; when they do not, the depot
ends up holding essentially random stacks:

https://lore.kernel.org/all/CACT4Y+aReMGLYua2rCLHgFpS...@mail.gmail.com/

Add an optional arch_in_irqentry_text() hook, consulted in addition to
the section range checks, gated on a new ARCH_HAS_IN_IRQENTRY_TEXT
symbol. Gating keeps the default a static inline returning false, which
folds away entirely on every architecture that does not opt in, instead
of a __weak stub that every architecture would have to call. This
mirrors the existing ARCH_HAS_* hooks in lib/Kconfig such as
ARCH_HAS_COPY_MC.

No functional change on its own.

The first user is the FRED fix in the follow-up patch, which carries a
Fixes: tag and is Cc'ed to stable; tag this prerequisite for stable too,
so the two are picked up as a pair.

Cc: sta...@vger.kernel.org
Signed-off-by: Yuanhe Shu <xian...@linux.alibaba.com>
---
include/linux/stacktrace.h | 16 ++++++++++++++++
kernel/stacktrace.c | 3 ++-
lib/Kconfig | 3 +++
3 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/include/linux/stacktrace.h b/include/linux/stacktrace.h
index 525cf60673fe..e933ce86447f 100644
--- a/include/linux/stacktrace.h
+++ b/include/linux/stacktrace.h
@@ -62,6 +62,22 @@ void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie,
const struct pt_regs *regs);
#endif /* CONFIG_ARCH_STACKWALK */

+/*
+ * Optional arch provided check for additional IRQ entry text, called
+ * in addition to the .irqentry.text and .softirqentry.text range
+ * checks in in_irqentry_text(). Implement this if the architecture
+ * delivers interrupts or exceptions through entry code which cannot
+ * reside in those sections.
+ */
+#ifdef CONFIG_ARCH_HAS_IN_IRQENTRY_TEXT
+bool arch_in_irqentry_text(unsigned long addr);
+#else
+static inline bool arch_in_irqentry_text(unsigned long addr)
+{
+ return false;
+}
+#endif
+
#ifdef CONFIG_STACKTRACE
void stack_trace_print(const unsigned long *trace, unsigned int nr_entries,
int spaces);
diff --git a/kernel/stacktrace.c b/kernel/stacktrace.c
index afb3c116da91..9e85ac900889 100644
--- a/kernel/stacktrace.c
+++ b/kernel/stacktrace.c
@@ -379,7 +379,8 @@ static inline bool in_irqentry_text(unsigned long ptr)
return (ptr >= (unsigned long)&__irqentry_text_start &&
ptr < (unsigned long)&__irqentry_text_end) ||
(ptr >= (unsigned long)&__softirqentry_text_start &&
- ptr < (unsigned long)&__softirqentry_text_end);
+ ptr < (unsigned long)&__softirqentry_text_end) ||
+ arch_in_irqentry_text(ptr);
}

/**
diff --git a/lib/Kconfig b/lib/Kconfig
index 4e6b34c3346d..45ff30d0a995 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -551,6 +551,9 @@ config ARCH_HAS_COPY_MC
config ARCH_STACKWALK
bool

+config ARCH_HAS_IN_IRQENTRY_TEXT
+ bool
+
config STACKDEPOT
bool
select STACKTRACE
--
2.43.5

Bradley Morgan

unread,
Aug 27, 2026, 1:05:16 PMAug 27
to xian...@linux.alibaba.com, ak...@linux-foundation.org, andre...@gmail.com, b...@alien8.de, dave....@linux.intel.com, el...@google.com, gli...@google.com, g...@linux.ibm.com, h...@zytor.com, jpoi...@kernel.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, lu...@kernel.org, mi...@redhat.com, pet...@infradead.org, rdu...@infradead.org, ros...@goodmis.org, sta...@vger.kernel.org, tg...@kernel.org, x...@kernel.org, x...@zytor.com
On 27 August 2026 16:00:21 BST, Yuanhe Shu <xian...@linux.alibaba.com>
wrote:
LGTM, thanks

Reviewed-by: Bradley Morgan <br...@mainlining.org>
--- Thanks!
https://lore.kernel.org/all/EE579805-42F2-4C58...@grrlz.net/

H. Peter Anvin

unread,
Aug 27, 2026, 5:26:29 PMAug 27
to Yuanhe Shu, tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, pet...@infradead.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, kasa...@googlegroups.com, linux-...@vger.kernel.org, sta...@vger.kernel.org
This all makes sense to me.

I would in fact like to see the IDT-only code isolated so it can be poisoned
if not used. The FRED code probably should be as well, although it is also
used by KVM -- and potentially by other auxiliary users in the future -- so it
might not make as much sense there.

-hpa

Andrew Morton

unread,
Aug 27, 2026, 7:06:20 PMAug 27
to Yuanhe Shu, tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, pet...@infradead.org, ros...@goodmis.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, kasa...@googlegroups.com, linux-...@vger.kernel.org, sta...@vger.kernel.org
Good call. I suggest that the same Fixes: be attached to this patch
also, to help ensure that everything lands in the correct place.

I'll assume that both patches will be handled by the x86 maintainers.

Peter Zijlstra

unread,
Aug 29, 2026, 5:42:21 AM (13 days ago) Aug 29
to Yuanhe Shu, tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, kasa...@googlegroups.com, linux-...@vger.kernel.org, sta...@vger.kernel.org
On Thu, Aug 27, 2026 at 11:00:22PM +0800, Yuanhe Shu wrote:

> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 15fd9ec5ecac..78b8eb4a925f 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -555,6 +555,7 @@ config X86_CPU_RESCTRL_INTEL_AET
> config X86_FRED
> bool "Flexible Return and Event Delivery"
> depends on X86_64
> + select ARCH_HAS_IN_IRQENTRY_TEXT
> help
> When enabled, use Flexible Return and Event Delivery
> instead of the legacy SYSCALL/SYSENTER/IDT architecture for

I'm not sold on this being a CONFIG symbol, we have far too many of
those. We have many other patterns that might work here.

A common one for example is:

#ifndef arch_in_irqentry_text
static inline bool arch_in_irqentry_text(unsigned long addr) { return false; }
#endif

And then have the arch/x86/include/asm/ header do:

#define arch_in_irqentry_text arch_in_irqentry_text.
This is all confusing at best. __fred_entry_text covers all entries, it
cannot distinguish between irqentry and syscall. Why is that not a
problem?


Yuanhe Shu

unread,
Aug 31, 2026, 4:59:26 AM (11 days ago) Aug 31
to Peter Zijlstra, Yuanhe Shu, tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, kasa...@googlegroups.com, linux-...@vger.kernel.org, sta...@vger.kernel.org
On Sat, Aug 29, 2026 at 11:42:07AM +0200, Peter Zijlstra wrote:
> I'm not sold on this being a CONFIG symbol, we have far too many of
> those. [...]

Fair enough - v2 uses your pattern and drops the Kconfig symbol. The
fallback goes next to its only user in kernel/stacktrace.c; putting it in
linux/stacktrace.h would make that header pull in asm/sections.h. x86
defines the macro next to the markers it tests in asm/sections.h, which
also gets rid of the arch/x86/kernel/stacktrace.c hunk.

> This is all confusing at best. __fred_entry_text covers all entries, it
> cannot distinguish between irqentry and syscall. Why is that not a
> problem?

It can't. But the only consumer, filter_irq_stacks(), does not use the
range to classify entries - it uses it to find where the event stack
began, and cuts there. For anything entered from ring 3 the entry frame
is the outermost frame of the trace: the unwinder follows the pt_regs
the entry pushed and stops there because user_mode(regs) is true
(unwind_orc.c, "End-of-stack check for user tasks"). So the cut is a
no-op: the syscall trace is stored whole, same as under the IDT, where
entry_SYSCALL_64 sits outside the range. An IRQ hitting a task
mid-syscall cuts at the inner kernel entrypoint and drops the interrupted
syscall frames, which is also what the IDT range does today at the
asm_sysvec_* stub.

Only ring-0 events and the IRQ/NMI forwarded through
asm_fred_entry_from_kvm() have an unrelated context below the entry
frame, and those are the ones filling the depot.

The existing markers are not irq-only either: they wrap the whole
asm/idtentry.h expansion, asm_exc_* stubs included, so this range means
the same thing they do. If you would rather it covered only the ring-0
entry, moving the start marker to asm_fred_entrypoint_kernel (+256)
makes no behavioural difference - I went with the whole block for
symmetry with the IDT side, but have no preference either way.

Thanks,
Yuanhe

Peter Zijlstra

unread,
Aug 31, 2026, 5:01:35 AM (11 days ago) Aug 31
to Yuanhe Shu, tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, kasa...@googlegroups.com, linux-...@vger.kernel.org, sta...@vger.kernel.org
I would still argue the function name is incorrect, and the user might
want a comment explaining this.

Yuanhe Shu

unread,
Aug 31, 2026, 5:06:39 AM (11 days ago) Aug 31
to Andrew Morton, Yuanhe Shu, tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, pet...@infradead.org, ros...@goodmis.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, kasa...@googlegroups.com, linux-...@vger.kernel.org, sta...@vger.kernel.org
On Thu, Aug 27, 2026 at 04:06:15PM -0700, Andrew Morton wrote:
> Good call. I suggest that the same Fixes: be attached to this patch
> also, to help ensure that everything lands in the correct place.

Done in v2.

Thanks,
Yuanhe

Yuanhe Shu

unread,
Aug 31, 2026, 7:25:53 AM (11 days ago) Aug 31
to Peter Zijlstra, Yuanhe Shu, tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, kasa...@googlegroups.com, linux-...@vger.kernel.org, sta...@vger.kernel.org
On Mon, Aug 31, 2026 at 11:01:24AM +0200, Peter Zijlstra wrote:
> I would still argue the function name is incorrect, and the user might
> want a comment explaining this.

You are right, and it predates FRED: the ranges in_irqentry_text() tests
have always covered the asm_exc_* stubs, so it has never been literally
irq-only either. The hook inherited the wording because I named it after
the helper it extends, the way arch_nmi_enter() is named after
nmi_enter().

v2 renames both: in_event_entry_text() and arch_in_event_entry_text().
The helper is file local with a single caller, so the rename stays inside
kernel/stacktrace.c; filter_irq_stacks() keeps its name since it is
exported and used treewide. Both the generic definition and the x86 hook
now carry a comment saying the range is where a trace entered the kernel
and covers syscall entry on some architectures; the x86 one also spells
out why matching it is a no-op for filter_irq_stacks().

If you would rather have a different name, say so and I will respin.

Thanks,
Yuanhe

Yuanhe Shu

unread,
Aug 31, 2026, 7:29:51 AM (11 days ago) Aug 31
to H. Peter Anvin, Yuanhe Shu, tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, pet...@infradead.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, kasa...@googlegroups.com, linux-...@vger.kernel.org, sta...@vger.kernel.org
On Thu, Aug 27, 2026 at 02:26:05PM -0700, H. Peter Anvin wrote:
> This all makes sense to me.

Thanks for the review.

> I would in fact like to see the IDT-only code isolated so it can be poisoned
> if not used. The FRED code probably should be as well, although it is also
> used by KVM -- and potentially by other auxiliary users in the future -- so it
> might not make as much sense there.

For the IDT side the bounds at least exist already:
__irqentry_text_start..__irqentry_text_end wraps nothing but the
asm/idtentry.h expansion. It is not page aligned and shares pages with
the neighbouring entry code, though, so overwriting it in place is one
thing and unmapping it another.

You are right about the FRED side: the range added here covers
asm_fred_entry_from_kvm() as well, so it cannot be poisoned wholesale even
on non-FRED hardware. Either way that is separate from this fix.

Thanks,
Yuanhe

Peter Zijlstra

unread,
Aug 31, 2026, 7:52:11 AM (11 days ago) Aug 31
to Yuanhe Shu, tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, kasa...@googlegroups.com, linux-...@vger.kernel.org, sta...@vger.kernel.org
That seems fine, thank you!

Yuanhe Shu

unread,
Aug 31, 2026, 8:02:40 AM (11 days ago) Aug 31
to tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, pet...@infradead.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, br...@mainlining.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, Yuanhe Shu
FRED replaces the IDT event entry stubs with asm_fred_entrypoint_user and
asm_fred_entrypoint_kernel, which live in .noinstr.text. The IDT stubs
are the only code covered by __irqentry_text_start..__irqentry_text_end,
which in_irqentry_text() uses to find where an event entered the kernel.
With FRED the detection fails, filter_irq_stacks() no longer truncates
event stacks, and every trace saved from interrupt or exception context
by stack depot users (KASAN alloc/free tracking, SLUB object tracking,
...) becomes a unique combination of "event path x arbitrarily
interrupted context". The depot grows without bound until it is
exhausted.

What we saw: a FRED-capable dual-socket system with KASAN (generic,
inline) and SLUB object tracking enabled hit the limit on both sockets
roughly 80 minutes after boot,

Stack depot reached limit capacity
WARNING: CPU: 286 PID: 128614 at lib/stackdepot.c:271 depot_alloc_stack+0x158/0x170

after which KASAN and SLUB stack tracking silently stop recording (new
traces get handle 0) until reboot. The recorded traces confirmed the
mechanism: interrupt side traces ran through asm_fred_entrypoint_kernel
and continued into the frames of the interrupted task.

Patch 1 adds an optional arch_in_event_entry_text() hook to the generic
entry text check, and renames that check from in_irqentry_text() to
in_event_entry_text() since neither it nor the ranges it tests are
necessarily irq-only; no behavior change by itself. Patch 2
implements it for x86 by bracketing the FRED entry text with
__fred_entry_text_start/end, the same way the IDT stubs are bracketed,
and reporting that range from <asm/sections.h>.

Unlike arm64 and s390, which hit the same symptom and could fix it by
placing their interrupt entry code in .irqentry.text, x86 has no such
section: it emits the markers as labels around the sequentially laid out
IDT stubs and defines __irq_entry to __invalid_section so that nothing
can land in that section. The FRED entry points therefore cannot be
brought inside the existing range, and a second one has to be reported;
see patch 2 for the details.

Testing:

- Build-tested on mainline: full vmlinux builds and link with
CONFIG_X86_FRED=y, CONFIG_X86_KERNEL_IBT=y and KASAN (generic,
inline), with and without CONFIG_KVM_INTEL=y, and with
CONFIG_X86_FRED=n so that the generic fallback is used; objtool link
stage clean.
- Runtime-tested by backporting both patches to the affected kernel (a
6.6 based debug build) and rebooting that system with an unchanged
command line: traces recorded from FRED event context now end at
asm_fred_entrypoint_kernel instead of continuing into the
interrupted task, and the pool count levels off at ~1230 pools
within minutes of boot instead of reaching the 8192 pool limit.

Reproducing on current upstream:

- On FRED hardware, any KASAN or SLUB_DEBUG kernel; on v6.17 and
later, boot with stack_depot_max_pools=1024 to bring the
exhaustion warning up in minutes instead of hours, and watch the
pool count in /sys/kernel/debug/stackdepot/stats grow
monotonically without the fix and converge with it.
- Without FRED hardware, the KVM VMX interrupt forwarding path
(CONFIG_X86_FRED=y + CONFIG_KVM_INTEL) exercises the new filtering
as well, see patch 2.

Both patches carry the same Fixes: tag and are Cc'ed to stable, and 2/2
uses the hook added by 1/2, so they need to be applied together.

Changes in v2:

- 1/2: drop the new ARCH_HAS_IN_IRQENTRY_TEXT Kconfig symbol and use the
#ifndef macro override pattern instead, with the fallback next to its
only user in kernel/stacktrace.c (Peter Zijlstra)
- 1/2: rename in_irqentry_text() to in_event_entry_text() and name the
hook after it - the ranges are not necessarily irq-only; on x86 they
cover the exception entry stubs too (Peter Zijlstra)
- 1/2: carry the same Fixes: tag as 2/2 (Andrew Morton)
- 1/2: drop Bradley Morgan's Reviewed-by since the patch changed
materially
- 2/2: implement the hook as a static inline in <asm/sections.h> next to
the markers it tests, instead of a Kconfig gated function in
arch/x86/kernel/stacktrace.c; arch/x86/Kconfig is no longer touched
- 2/2: spell out, in the changelog and in a comment on the hook, why the
range covering the ring 3 entry point, and therefore syscalls, does not
change any trace (Peter Zijlstra)
- 2/2: add Reported-by for Xiang Zheng, who found the exhaustion

v1: https://lore.kernel.org/r/20260827150022.1...@linux.alibaba.com

Yuanhe Shu (2):
stacktrace: Provide arch_in_event_entry_text() hook
x86/fred: Fix stack depot filtering of FRED event stacks

arch/x86/entry/entry_64_fred.S | 14 ++++++++++++++
arch/x86/include/asm/sections.h | 23 +++++++++++++++++++++++
kernel/stacktrace.c | 22 +++++++++++++++++++---
3 files changed, 56 insertions(+), 3 deletions(-)


base-commit: 45c13f3f9e3bb15fd89ff2864c6f627a3b4b4229
--
2.43.7

Yuanhe Shu

unread,
Aug 31, 2026, 8:02:41 AM (11 days ago) Aug 31
to tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, pet...@infradead.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, br...@mainlining.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, Yuanhe Shu, sta...@vger.kernel.org
in_irqentry_text() decides whether a stack address belongs to interrupt
entry code by checking the .irqentry.text and .softirqentry.text section
ranges. filter_irq_stacks() uses it to truncate interrupt stacks at the
entry point, which stack depot depends on to deduplicate them: traces
that continue past the interrupt entry lead to unbounded depot growth,
see commit e94006608949 ("lib/stackdepot: always do filter_irq_stacks()
in stack_depot_save()").

An architecture may deliver interrupts through entry code that cannot be
placed in .irqentry.text. in_irqentry_text() then never recognizes the
entry point and the truncation silently stops happening. The markers are
meant to cover all interrupt entry functions; when they do not, the depot
fills with unfiltered stacks:

https://lore.kernel.org/all/CACT4Y+aReMGLYua2rCLHgFpS...@mail.gmail.com/

Add an optional arch_in_event_entry_text() hook, consulted in addition to
the section range checks. An architecture overrides it by defining a
macro of the same name in <asm/sections.h>, next to the section markers
it tests; the default here is a static inline returning false, which
folds away entirely on every architecture that does not opt in. This
mirrors the existing arch hook pattern of arch_nmi_enter() in
<linux/hardirq.h>. The fallback sits next to the hook's only user, so
no generic header gains a new dependency.

Rename in_irqentry_text() to in_event_entry_text() at the same time and
name the hook after it: the ranges it tests are not necessarily irq-only
- on x86 they also cover the exception entry stubs - and what
filter_irq_stacks() asks of them is where a trace entered the kernel.
The helper is file local with a single caller, so the rename stays inside
kernel/stacktrace.c; filter_irq_stacks() keeps its name as it is exported
and used treewide.

No functional change on its own.

The first user is the FRED fix in the follow-up patch. Both carry the
same Fixes: tag and are Cc'ed to stable so that they are picked up as a
pair.

Fixes: 14619d912b65 ("x86/fred: FRED entry/exit and dispatch code")
Cc: sta...@vger.kernel.org # v6.9+
Signed-off-by: Yuanhe Shu <xian...@linux.alibaba.com>
---
kernel/stacktrace.c | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/kernel/stacktrace.c b/kernel/stacktrace.c
index afb3c116da91..487ab2c858ca 100644
--- a/kernel/stacktrace.c
+++ b/kernel/stacktrace.c
@@ -14,6 +14,7 @@
#include <linux/kallsyms.h>
#include <linux/stacktrace.h>
#include <linux/interrupt.h>
+#include <asm/sections.h>

/**
* stack_trace_print - Print the entries in the stack trace
@@ -374,12 +375,27 @@ unsigned int stack_trace_save_user(unsigned long *store, unsigned int size)

#endif /* !CONFIG_ARCH_STACKWALK */

-static inline bool in_irqentry_text(unsigned long ptr)
+/*
+ * Optional arch hook for event entry text which cannot be placed in
+ * .irqentry.text. filter_irq_stacks() uses this and the section checks
+ * below to find where a trace entered the kernel, so the ranges are not
+ * necessarily irq-only: on x86 they also cover the exception entry stubs,
+ * and an architecture may deliver syscalls through the same entry text.
+ * A caller that has to tell interrupt entry and syscall entry apart
+ * cannot use this. An architecture overrides it by defining a macro of
+ * the same name in <asm/sections.h>, next to the markers it tests.
+ */
+#ifndef arch_in_event_entry_text
+static inline bool arch_in_event_entry_text(unsigned long addr) { return false; }
+#endif
+
+static inline bool in_event_entry_text(unsigned long ptr)
{
return (ptr >= (unsigned long)&__irqentry_text_start &&
ptr < (unsigned long)&__irqentry_text_end) ||
(ptr >= (unsigned long)&__softirqentry_text_start &&
- ptr < (unsigned long)&__softirqentry_text_end);
+ ptr < (unsigned long)&__softirqentry_text_end) ||
+ arch_in_event_entry_text(ptr);
}

/**
@@ -394,7 +410,7 @@ unsigned int filter_irq_stacks(unsigned long *entries, unsigned int nr_entries)
unsigned int i;

for (i = 0; i < nr_entries; i++) {
- if (in_irqentry_text(entries[i])) {
+ if (in_event_entry_text(entries[i])) {
/* Include the irqentry function into the stack. */
return i + 1;
}
--
2.43.7

Yuanhe Shu

unread,
Aug 31, 2026, 8:02:48 AM (11 days ago) Aug 31
to tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, pet...@infradead.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, br...@mainlining.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, Yuanhe Shu, Xiang Zheng, sta...@vger.kernel.org
With FRED, events are delivered to asm_fred_entrypoint_user and
asm_fred_entrypoint_kernel in .noinstr.text, not to the IDT stubs, which
are the only code covered by __irqentry_text_start..__irqentry_text_end.
in_event_entry_text() therefore never recognizes the event entry point and
filter_irq_stacks() does not truncate FRED event stacks: every trace
saved from interrupt or exception context by stack depot users such as
KASAN alloc/free tracking or SLUB object tracking combines the event path
with the arbitrarily interrupted context. The number of unique stacks
grows with the product of both and the depot is exhausted.

Observed on a dual-socket FRED-capable system with KASAN (generic,
inline) and SLUB object tracking enabled, on both sockets roughly 80
minutes after boot, once the depot had reached its maximum of 8192 pools
(128 MiB):

Stack depot reached limit capacity
WARNING: CPU: 286 PID: 128614 at lib/stackdepot.c:271 depot_alloc_stack+0x158/0x170

The traces had the expected shape: an interrupt side trace ran through
asm_fred_entrypoint_kernel into the frames of the task it had
interrupted. New traces are dropped (handle 0) from then on and the
depot never shrinks, so tracking stays dead until reboot. (Splat from a
6.6 based kernel; filter_irq_stacks() and the FRED entry layout are
unchanged in mainline.)

The entry points cannot be brought inside that range. x86 has no
.irqentry.text: commit f0178fc01fe4 ("x86/entry: Unbreak
__irqentry_text_start/end magic") dropped it from the linker script and
emits the markers as labels around the sequentially laid out IDT stubs
instead, exactly because the entry rework had moved that code into
.noinstr.text and broken the function graph tracer and
filter_irq_stacks(); __irq_entry has been __invalid_section since.
Those labels live inside entry_64.S and wrap the IDT stubs which
asm/idtentry.h emits into .entry.text, so the linker cannot place
another translation unit between them: only code compiled into
entry_64.S itself can end up inside the range. Architectures which do
have the section fixed the same symptom locally, e.g.
commit f6794950f0e5 ("arm64: set __exception_irq_entry with __irq_entry
as a default") and commit 45c9f2b856a0 ("s390/entry: Mark IRQ entries
to fix stack depot warnings").

Every FRED event leaves a return address in the FRED entry text: the
return address of the call to fred_entry_from_user/kernel, or a frame of
asm_fred_entry_from_kvm(), which the core entry code uses to forward VMX
interrupts and NMIs acknowledged as part of the VM-Exit; see
commit 0701c9e17bd9 ("x86/kvm/vmx: Move IRQ/NMI dispatch from KVM
into x86 core"). So bracket it with __fred_entry_text_start/end, the
same way the IDT stubs are bracketed, and report that range from
arch_in_event_entry_text(). Verified on that system with the fix
backported: traces from FRED event context now end at
asm_fred_entrypoint_kernel (/sys/kernel/debug/slab/*/alloc_traces) and
the pool count levels off a few minutes after boot instead of climbing
to the limit.

The range covers every FRED entry point, including the ring 3 one which
also serves syscalls, and the hook cannot tell them apart - it only gets
an address. That does not change any trace: filter_irq_stacks() cuts at
the innermost match, and for anything entered from ring 3 the entry frame
is already the outermost trace entry (the unwinder follows the pt_regs
the entry pushed and stops there because user_mode(regs) is true), so the
trace is returned unchanged. Only ring 0 events, and the IRQ/NMI the
core forwards through asm_fred_entry_from_kvm(), leave an unrelated
context below the entry frame. The IDT markers are not IRQ-only either:
they wrap the entire asm/idtentry.h expansion, so the synchronous
exception stubs have always been inside them. The function graph
tracer uses the same markers and has the same gap; it can be converted
separately.

This is not limited to FRED hardware: KVM_INTEL selects X86_FRED on
x86_64 (commit 28d11e4548b7 ("x86/fred: KVM: VMX: Always use FRED for
IRQs when CONFIG_X86_FRED=y")), so every kernel with Intel KVM support,
built in or as a module, carries the FRED dispatch code, and the
forwarding path above runs it even when the kernel itself uses the IDT.
KVM host stacks therefore take the same untruncated path on non-FRED
systems, albeit from a mostly fixed vcpu_run chain.

Reported-by: Xiang Zheng <xiang...@linux.alibaba.com>
Fixes: 14619d912b65 ("x86/fred: FRED entry/exit and dispatch code")
Cc: sta...@vger.kernel.org # v6.9+
Signed-off-by: Yuanhe Shu <xian...@linux.alibaba.com>
---
arch/x86/entry/entry_64_fred.S | 14 ++++++++++++++
arch/x86/include/asm/sections.h | 23 +++++++++++++++++++++++
2 files changed, 37 insertions(+)

diff --git a/arch/x86/entry/entry_64_fred.S b/arch/x86/entry/entry_64_fred.S
index b98f8945dfff..5a3db902e961 100644
--- a/arch/x86/entry/entry_64_fred.S
+++ b/arch/x86/entry/entry_64_fred.S
@@ -36,6 +36,17 @@
*/
.align 4096

+/*
+ * Bounds of the FRED event entry text. Every event delivered by FRED
+ * enters here, including events which the core entry code forwards
+ * through asm_fred_entry_from_kvm(). This is the FRED counterpart of
+ * __irqentry_text_start..__irqentry_text_end and lets
+ * in_event_entry_text() find the event entry point of a stack, see
+ * arch_in_event_entry_text().
+ */
+ .globl __fred_entry_text_start
+__fred_entry_text_start:
+
SYM_CODE_START_NOALIGN(asm_fred_entrypoint_user)
FRED_ENTER
call fred_entry_from_user
@@ -150,3 +161,6 @@ SYM_FUNC_START(asm_fred_entry_from_kvm)

SYM_FUNC_END(asm_fred_entry_from_kvm)
#endif
+
+ .globl __fred_entry_text_end
+__fred_entry_text_end:
diff --git a/arch/x86/include/asm/sections.h b/arch/x86/include/asm/sections.h
index 30e8ee7006f9..d18c9b9ca3bf 100644
--- a/arch/x86/include/asm/sections.h
+++ b/arch/x86/include/asm/sections.h
@@ -5,6 +5,29 @@
#include <asm-generic/sections.h>
#include <asm/extable.h>

+#ifdef CONFIG_X86_FRED
+extern char __fred_entry_text_start[], __fred_entry_text_end[];
+
+#define arch_in_event_entry_text arch_in_event_entry_text
+
+/*
+ * FRED delivers events to entry points in .noinstr.text, which
+ * __irqentry_text_start..__irqentry_text_end does not cover. See
+ * __fred_entry_text_start in entry_64_fred.S.
+ *
+ * Note that the range includes the ring 3 entry point, which also
+ * delivers syscalls. That is fine for the only consumer,
+ * filter_irq_stacks(): it cuts at the innermost match, and for an
+ * entry from ring 3 the entry frame is already the outermost frame
+ * of the trace, so matching it is a no-op.
+ */
+static inline bool arch_in_event_entry_text(unsigned long addr)
+{
+ return addr >= (unsigned long)__fred_entry_text_start &&
+ addr < (unsigned long)__fred_entry_text_end;
+}
+#endif
+
extern char __relocate_kernel_start[], __relocate_kernel_end[];
extern char __brk_base[], __brk_limit[];
extern char __end_rodata_aligned[];
--
2.43.7

Yuanhe Shu

unread,
Aug 31, 2026, 8:06:42 AM (11 days ago) Aug 31
to Bradley Morgan, Yuanhe Shu, tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, pet...@infradead.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, kasa...@googlegroups.com, linux-...@vger.kernel.org, sta...@vger.kernel.org
On Thu, Aug 27, 2026 at 06:04:48PM +0100, Bradley Morgan wrote:
> LGTM, thanks
>
> Reviewed-by: Bradley Morgan <br...@mainlining.org>

Thanks for reviewing v1. I dropped the tag in v2 since the patch changed
materially: Peter asked for the #ifndef macro override pattern instead of
a Kconfig symbol, so the hook and its fallback now sit next to their only
user in kernel/stacktrace.c and x86 defines the macro in <asm/sections.h>.
The helper and the hook are also renamed to in_event_entry_text() and
arch_in_event_entry_text(). Please have another look if you get the
chance:

https://lore.kernel.org/r/20260831120221.2...@linux.alibaba.com

Thanks,
Yuanhe

Bradley Morgan

unread,
Aug 31, 2026, 8:09:33 AM (11 days ago) Aug 31
to Yuanhe Shu, tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, pet...@infradead.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, kasa...@googlegroups.com, linux-...@vger.kernel.org, sta...@vger.kernel.org
On 31 August 2026 13:06:19 BST, Yuanhe Shu <xian...@linux.alibaba.com>
wrote:
>On Thu, Aug 27, 2026 at 06:04:48PM +0100, Bradley Morgan wrote:
>> LGTM, thanks
>>
>> Reviewed-by: Bradley Morgan <br...@mainlining.org>
>
>Thanks for reviewing v1. I dropped the tag in v2 since the patch changed
>materially: Peter asked for the #ifndef macro override pattern instead of
>a Kconfig symbol, so the hook and its fallback now sit next to their only
>user in kernel/stacktrace.c and x86 defines the macro in <asm/sections.h>.
>The helper and the hook are also renamed to in_event_entry_text() and
>arch_in_event_entry_text(). Please have another look if you get the
>chance:
>
>

Hmmm. Good opinion, it's varied imho. But I'm not conflicted. My tag
stands.
https://lore.kernel.org/r/20260831120221.2...@linux.alibaba.com
>
>Thanks,
>Yuanhe

--- Thanks!
https://lore.kernel.org/all/EE579805-42F2-4C58...@grrlz.net/

Dave Hansen

unread,
Aug 31, 2026, 10:01:58 AM (11 days ago) Aug 31
to Yuanhe Shu, tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, pet...@infradead.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, br...@mainlining.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, sta...@vger.kernel.org
On 8/31/26 05:02, Yuanhe Shu wrote:
> +/*
> + * Optional arch hook for event entry text which cannot be placed in
> + * .irqentry.text. filter_irq_stacks() uses this and the section checks
> + * below to find where a trace entered the kernel, so the ranges are not
> + * necessarily irq-only: on x86 they also cover the exception entry stubs,
> + * and an architecture may deliver syscalls through the same entry text.
> + * A caller that has to tell interrupt entry and syscall entry apart
> + * cannot use this. An architecture overrides it by defining a macro of
> + * the same name in <asm/sections.h>, next to the markers it tests.
> + */
> +#ifndef arch_in_event_entry_text
> +static inline bool arch_in_event_entry_text(unsigned long addr) { return false; }
> +#endif

As much as I love inflicting x86-isms on generic comments, I don't think
this comment needs to talk about x86. I find the most useful generic
definitions to be like an instruction manual for future arch/
maintainers. Maybe something like:

/*
* Used to help find where a trace entered the kernel.
*
* Architectures use this when event entry text cannot be placed in
* .irqentry.text alone. Architectures should define their
* version in <asm/sections.h>.
*/

... and then talk about why x86 needs it in the x86 definition.

Yuanhe Shu

unread,
Sep 1, 2026, 8:30:09 AM (10 days ago) Sep 1
to Dave Hansen, Yuanhe Shu, tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, pet...@infradead.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, br...@mainlining.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, sta...@vger.kernel.org
On Mon, Aug 31, 2026 at 07:01:52AM -0700, Dave Hansen wrote:
> As much as I love inflicting x86-isms on generic comments, I don't think
> this comment needs to talk about x86. I find the most useful generic
> definitions to be like an instruction manual for future arch/
> maintainers. Maybe something like:
[...]
> ... and then talk about why x86 needs it in the x86 definition.

Good point, v3 will do it that way. The x86 definition already says why
the range is needed there and that it covers the ring 3 entry point, so I
will move the note about not being able to tell interrupt entry and
syscall entry apart into that comment as well.

Thanks,
Yuanhe

Yuanhe Shu

unread,
Sep 1, 2026, 8:40:34 AM (10 days ago) Sep 1
to tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, pet...@infradead.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, br...@mainlining.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, Yuanhe Shu
FRED replaces the IDT event entry stubs with asm_fred_entrypoint_user and
asm_fred_entrypoint_kernel, which live in .noinstr.text. The IDT stubs
are the only code covered by __irqentry_text_start..__irqentry_text_end,
which in_irqentry_text() uses to find where an event entered the kernel.
With FRED the detection fails, filter_irq_stacks() no longer truncates
event stacks, and every trace saved from interrupt or exception context
by stack depot users (KASAN alloc/free tracking, SLUB object tracking,
...) becomes a unique combination of "event path x arbitrarily
interrupted context". The depot grows without bound until it is
exhausted.

What we saw: a FRED-capable dual-socket system with KASAN (generic,
inline) and SLUB object tracking enabled hit the limit on both sockets
roughly 80 minutes after boot,

Stack depot reached limit capacity
WARNING: CPU: 286 PID: 128614 at lib/stackdepot.c:271 depot_alloc_stack+0x158/0x170

after which KASAN and SLUB stack tracking silently stop recording (new
traces get handle 0) until reboot. The recorded traces confirmed the
mechanism: interrupt side traces ran through asm_fred_entrypoint_kernel
and continued into the frames of the interrupted task.

Patch 1 adds an optional arch_in_event_entry_text() hook to the generic
entry text check, and renames that check from in_irqentry_text() to
in_event_entry_text() since neither it nor the ranges it tests are
necessarily irq-only; no behavior change by itself. Patch 2
implements it for x86 by bracketing the FRED entry text with
__fred_entry_text_start/end, the same way the IDT stubs are bracketed,
Changes in v3:

- 1/2: drop the x86 details from the generic comment and phrase it as an
instruction for future arch maintainers (Dave Hansen)
- 1/2: restore Bradley Morgan's Reviewed-by - he confirmed the tag still
holds for the reworked version
- 2/2: state the caveat that the range cannot tell interrupt entry and
syscall entry apart here rather than in the generic comment

Changes in v2:

- 1/2: drop the new ARCH_HAS_IN_IRQENTRY_TEXT Kconfig symbol and use the
#ifndef macro override pattern instead, with the fallback next to its
only user in kernel/stacktrace.c (Peter Zijlstra)
- 1/2: rename in_irqentry_text() to in_event_entry_text() and name the
hook after it - the ranges are not necessarily irq-only; on x86 they
cover the exception entry stubs too (Peter Zijlstra)
- 1/2: carry the same Fixes: tag as 2/2 (Andrew Morton)
- 1/2: drop Bradley Morgan's Reviewed-by since the patch changed
materially
- 2/2: implement the hook as a static inline in <asm/sections.h> next to
the markers it tests, instead of a Kconfig gated function in
arch/x86/kernel/stacktrace.c; arch/x86/Kconfig is no longer touched
- 2/2: spell out, in the changelog and in a comment on the hook, why the
range covering the ring 3 entry point, and therefore syscalls, does not
change any trace (Peter Zijlstra)
- 2/2: add Reported-by for Xiang Zheng, who found the exhaustion

v1: https://lore.kernel.org/r/20260827150022.1...@linux.alibaba.com
v2: https://lore.kernel.org/r/20260831120221.2...@linux.alibaba.com

Yuanhe Shu (2):
stacktrace: Provide arch_in_event_entry_text() hook
x86/fred: Fix stack depot filtering of FRED event stacks

arch/x86/entry/entry_64_fred.S | 14 ++++++++++++++
arch/x86/include/asm/sections.h | 24 ++++++++++++++++++++++++
kernel/stacktrace.c | 19 ++++++++++++++++---
3 files changed, 54 insertions(+), 3 deletions(-)


base-commit: 45c13f3f9e3bb15fd89ff2864c6f627a3b4b4229
--
2.43.7

Yuanhe Shu

unread,
Sep 1, 2026, 8:40:35 AM (10 days ago) Sep 1
to tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, pet...@infradead.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, br...@mainlining.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, Yuanhe Shu, sta...@vger.kernel.org
Fixes: 14619d912b65 ("x86/fred: FRED entry/exit and dispatch code")
Cc: sta...@vger.kernel.org # v6.9+
Signed-off-by: Yuanhe Shu <xian...@linux.alibaba.com>
Reviewed-by: Bradley Morgan <br...@mainlining.org>
---
kernel/stacktrace.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/kernel/stacktrace.c b/kernel/stacktrace.c
index afb3c116da91..62b84998b13e 100644
--- a/kernel/stacktrace.c
+++ b/kernel/stacktrace.c
@@ -14,6 +14,7 @@
#include <linux/kallsyms.h>
#include <linux/stacktrace.h>
#include <linux/interrupt.h>
+#include <asm/sections.h>

/**
* stack_trace_print - Print the entries in the stack trace
@@ -374,12 +375,24 @@ unsigned int stack_trace_save_user(unsigned long *store, unsigned int size)

#endif /* !CONFIG_ARCH_STACKWALK */

-static inline bool in_irqentry_text(unsigned long ptr)
+/*
+ * Used to help find where a trace entered the kernel.
+ *
+ * Architectures use this when event entry text cannot be placed in
+ * .irqentry.text alone. Architectures should define a macro of the
+ * same name in <asm/sections.h>.
+ */
+#ifndef arch_in_event_entry_text
+static inline bool arch_in_event_entry_text(unsigned long addr) { return false; }
+#endif
+
+static inline bool in_event_entry_text(unsigned long ptr)
{
return (ptr >= (unsigned long)&__irqentry_text_start &&
ptr < (unsigned long)&__irqentry_text_end) ||
(ptr >= (unsigned long)&__softirqentry_text_start &&
- ptr < (unsigned long)&__softirqentry_text_end);
+ ptr < (unsigned long)&__softirqentry_text_end) ||
+ arch_in_event_entry_text(ptr);
}

/**
@@ -394,7 +407,7 @@ unsigned int filter_irq_stacks(unsigned long *entries, unsigned int nr_entries)

Yuanhe Shu

unread,
Sep 1, 2026, 8:40:38 AM (10 days ago) Sep 1
to tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, pet...@infradead.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, gli...@google.com, g...@linux.ibm.com, br...@mainlining.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, Yuanhe Shu, Xiang Zheng, sta...@vger.kernel.org
With FRED, events are delivered to asm_fred_entrypoint_user and
asm_fred_entrypoint_kernel in .noinstr.text, not to the IDT stubs, which
are the only code covered by __irqentry_text_start..__irqentry_text_end.
in_event_entry_text() therefore never recognizes the event entry point and
filter_irq_stacks() does not truncate FRED event stacks: every trace
saved from interrupt or exception context by stack depot users such as
KASAN alloc/free tracking or SLUB object tracking combines the event path
with the arbitrarily interrupted context. The number of unique stacks
grows with the product of both and the depot is exhausted.

Observed on a dual-socket FRED-capable system with KASAN (generic,
inline) and SLUB object tracking enabled, on both sockets roughly 80
minutes after boot, once the depot had reached its maximum of 8192 pools
(128 MiB):

Stack depot reached limit capacity
WARNING: CPU: 286 PID: 128614 at lib/stackdepot.c:271 depot_alloc_stack+0x158/0x170

The traces had the expected shape: an interrupt side trace ran through
asm_fred_entrypoint_kernel into the frames of the task it had
interrupted. New traces are dropped (handle 0) from then on and the
depot never shrinks, so tracking stays dead until reboot. (Splat from a
6.6 based kernel; filter_irq_stacks() and the FRED entry layout are
unchanged in mainline.)

The entry points cannot be brought inside that range. x86 has no
.irqentry.text: commit f0178fc01fe4 ("x86/entry: Unbreak
__irqentry_text_start/end magic") dropped it from the linker script and
emits the markers as labels around the sequentially laid out IDT stubs
Fixes: 14619d912b65 ("x86/fred: FRED entry/exit and dispatch code")
Cc: sta...@vger.kernel.org # v6.9+
Signed-off-by: Yuanhe Shu <xian...@linux.alibaba.com>
---
arch/x86/entry/entry_64_fred.S | 14 ++++++++++++++
arch/x86/include/asm/sections.h | 24 ++++++++++++++++++++++++
2 files changed, 38 insertions(+)
index 30e8ee7006f9..f34170ecc4e4 100644
--- a/arch/x86/include/asm/sections.h
+++ b/arch/x86/include/asm/sections.h
@@ -5,6 +5,30 @@
#include <asm-generic/sections.h>
#include <asm/extable.h>

+#ifdef CONFIG_X86_FRED
+extern char __fred_entry_text_start[], __fred_entry_text_end[];
+
+#define arch_in_event_entry_text arch_in_event_entry_text
+
+/*
+ * FRED delivers events to entry points in .noinstr.text, which
+ * __irqentry_text_start..__irqentry_text_end does not cover. See
+ * __fred_entry_text_start in entry_64_fred.S.
+ *
+ * Note that the range includes the ring 3 entry point, which also
+ * delivers syscalls, so it cannot tell interrupt entry and syscall
+ * entry apart. That is fine for the only consumer,
+ * filter_irq_stacks(): it cuts at the innermost match, and for an
+ * entry from ring 3 the entry frame is already the outermost frame
+ * of the trace, so matching it is a no-op.
+ */
+static inline bool arch_in_event_entry_text(unsigned long addr)

Alexander Potapenko

unread,
Sep 2, 2026, 9:02:40 AM (9 days ago) Sep 2
to Yuanhe Shu, tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, pet...@infradead.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, g...@linux.ibm.com, br...@mainlining.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, sta...@vger.kernel.org
On Tue, Sep 1, 2026 at 2:40 PM Yuanhe Shu <xian...@linux.alibaba.com> wrote:

> The first user is the FRED fix in the follow-up patch. Both carry the
> same Fixes: tag and are Cc'ed to stable so that they are picked up as a
> pair.
>
> Fixes: 14619d912b65 ("x86/fred: FRED entry/exit and dispatch code")
> Cc: sta...@vger.kernel.org # v6.9+
> Signed-off-by: Yuanhe Shu <xian...@linux.alibaba.com>
> Reviewed-by: Bradley Morgan <br...@mainlining.org>
Acked-by: Alexander Potapenko <gli...@google.com>

Alexander Potapenko

unread,
Sep 2, 2026, 9:18:21 AM (9 days ago) Sep 2
to Yuanhe Shu, tg...@kernel.org, mi...@redhat.com, b...@alien8.de, dave....@linux.intel.com, x...@kernel.org, h...@zytor.com, x...@zytor.com, lu...@kernel.org, jpoi...@kernel.org, pet...@infradead.org, ros...@goodmis.org, ak...@linux-foundation.org, rdu...@infradead.org, el...@google.com, andre...@gmail.com, g...@linux.ibm.com, br...@mainlining.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, Xiang Zheng, sta...@vger.kernel.org
On Tue, Sep 1, 2026 at 2:40 PM Yuanhe Shu <xian...@linux.alibaba.com> wrote:
>

> Reported-by: Xiang Zheng <xiang...@linux.alibaba.com>
> Fixes: 14619d912b65 ("x86/fred: FRED entry/exit and dispatch code")
> Cc: sta...@vger.kernel.org # v6.9+
> Signed-off-by: Yuanhe Shu <xian...@linux.alibaba.com>
Acked-by: Alexander Potapenko <gli...@google.com>
Reply all
Reply to author
Forward
0 new messages