perf: Clean ups and simplifications
Subsystems (5)
cover perf: Clean ups and simplifications
This is a resend from: https://lore.kernel.org/linux-trace-kernel/[email protected]/
It cleanly applied on top of the latest tip/perf/core:
448f97fba901 ("perf: Convert mmap() refcounts to refcount_t")
The ongoing work to support sframes[1] in the kernel required a few clean ups to the perf kernel side. Instead of having these changes in the ongoing work, there's no reason they cannot be applied now.
These are just clean ups to the perf code to help simplify the updates that will be made later.
[1] https://lore.kernel.org/linux-trace-kernel/[email protected]
Josh Poimboeuf (4):
perf: Remove get_perf_callchain() init_nr argument
perf: Have get_perf_callchain() return NULL if crosstask and user are set
perf: Simplify get_perf_callchain() user logic
perf: Skip user unwind if the task is a kernel thread
Steven Rostedt (1):
perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
----
include/linux/perf_event.h | 2 +- kernel/bpf/stackmap.c | 4 ++-- kernel/events/callchain.c | 40 +++++++++++++++++++--------------------- kernel/events/core.c | 9 +++++---- 4 files changed, 27 insertions(+), 28 deletions(-)
PATCH RESEND 1/5 perf: Remove get_perf_callchain() init_nr argument
From: Josh Poimboeuf <[email protected]>
The 'init_nr' argument has double duty: it's used to initialize both the number of contexts and the number of stack entries. That's confusing and the callers always pass zero anyway. Hard code the zero.
--- include/linux/perf_event.h | 2 +- kernel/bpf/stackmap.c | 4 ++-- kernel/events/callchain.c | 12 ++++++------ kernel/events/core.c | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-)
include/linux/perf_event.h +1 -1
@@ -1719,7 +1719,7 @@ DECLARE_PER_CPU(struct perf_callchain_entry, perf_callchain_entry);extern void perf_callchain_user (struct perf_callchain_entry_ctx *entry,struct pt_regs *regs);extern void perf_callchain_kernel (struct perf_callchain_entry_ctx *entry,struct pt_regs *regs);extern struct perf_callchain_entry * -get_perf_callchain (struct pt_regs *regs,u32 init_nr,bool kernel,bool user, +get_perf_callchain (struct pt_regs *regs,bool kernel,bool user,u32 max_stack,bool crosstask,bool add_mark);extern int get_callchain_buffers (int max_stack);extern void put_callchain_buffers (void );
kernel/bpf/stackmap.c +2 -2
@@ -314,7 +314,7 @@ BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, struct bpf_map *, map,if (max_depth > sysctl_perf_event_max_stack) max_depth = sysctl_perf_event_max_stack; - trace =get_perf_callchain (regs,0 , kernel, user, max_depth, + trace =get_perf_callchain (regs, kernel, user, max_depth, false, false);if (unlikely (!trace))
@@ -451,7 +451,7 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,else if (kernel && task) trace =get_callchain_entry_for_task (task, max_depth);else - trace =get_perf_callchain (regs,0 , kernel, user, max_depth, + trace =get_perf_callchain (regs, kernel, user, max_depth, crosstask, false);if (unlikely (!trace) || trace->nr < skip) {
kernel/events/callchain.c +6 -6
@@ -217,7 +217,7 @@ static void fixup_uretprobe_trampoline_entries(struct perf_callchain_entry *entr }struct perf_callchain_entry * -get_perf_callchain (struct pt_regs *regs,u32 init_nr,bool kernel,bool user, +get_perf_callchain (struct pt_regs *regs,bool kernel,bool user,u32 max_stack,bool crosstask,bool add_mark) {struct perf_callchain_entry *entry;
@@ -228,11 +228,11 @@ get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user,if (!entry)return NULL ; - ctx.entry = entry; - ctx.max_stack = max_stack; - ctx.nr = entry->nr = init_nr; - ctx.contexts =0 ; - ctx.contexts_maxed = false; + ctx.entry = entry; + ctx.max_stack = max_stack; + ctx.nr = entry->nr =0 ; + ctx.contexts =0 ; + ctx.contexts_maxed = false;if (kernel && !user_mode (regs)) {if (add_mark)
kernel/events/core.c +1 -1
@@ -8210,7 +8210,7 @@ perf_callchain(struct perf_event *event, struct pt_regs *regs)if (!kernel && !user)return &__empty_callchain; - callchain =get_perf_callchain (regs,0 , kernel, user, + callchain =get_perf_callchain (regs, kernel, user, max_stack, crosstask, true);return callchain ?: &__empty_callchain; }
Signature · 1 line
2.50.1
[tip: perf/core] perf: Remove get_perf_callchain() init_nr argument
The following commit has been merged into the perf/core branch of tip:
The following commit has been merged into the perf/core branch of tip:
Commit-ID: e649bcda25b5ae1a30a182cc450f928a0b282c93 Gitweb: https://git.kernel.org/tip/e649bcda25b5ae1a30a182cc450f928a0b282c93 Author: Josh Poimboeuf <[email protected]> AuthorDate: Wed, 20 Aug 2025 14:03:39 -04:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Tue, 26 Aug 2025 09:51:12 +02:00
perf: Remove get_perf_callchain() init_nr argument
The 'init_nr' argument has double duty: it's used to initialize both the number of contexts and the number of stack entries. That's confusing and the callers always pass zero anyway. Hard code the zero.
--- include/linux/perf_event.h | 2 +- kernel/bpf/stackmap.c | 4 ++-- kernel/events/callchain.c | 12 ++++++------ kernel/events/core.c | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-)
include/linux/perf_event.h +1 -1
@@ -1719,7 +1719,7 @@ DECLARE_PER_CPU(struct perf_callchain_entry, perf_callchain_entry);extern void perf_callchain_user (struct perf_callchain_entry_ctx *entry,struct pt_regs *regs);extern void perf_callchain_kernel (struct perf_callchain_entry_ctx *entry,struct pt_regs *regs);extern struct perf_callchain_entry * -get_perf_callchain (struct pt_regs *regs,u32 init_nr,bool kernel,bool user, +get_perf_callchain (struct pt_regs *regs,bool kernel,bool user,u32 max_stack,bool crosstask,bool add_mark);extern int get_callchain_buffers (int max_stack);extern void put_callchain_buffers (void );
kernel/bpf/stackmap.c +2 -2
@@ -314,7 +314,7 @@ BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, struct bpf_map *, map,if (max_depth > sysctl_perf_event_max_stack) max_depth = sysctl_perf_event_max_stack; - trace =get_perf_callchain (regs,0 , kernel, user, max_depth, + trace =get_perf_callchain (regs, kernel, user, max_depth, false, false);if (unlikely (!trace))
@@ -451,7 +451,7 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,else if (kernel && task) trace =get_callchain_entry_for_task (task, max_depth);else - trace =get_perf_callchain (regs,0 , kernel, user, max_depth, + trace =get_perf_callchain (regs, kernel, user, max_depth, crosstask, false);if (unlikely (!trace) || trace->nr < skip) {
kernel/events/callchain.c +6 -6
@@ -217,7 +217,7 @@ static void fixup_uretprobe_trampoline_entries(struct perf_callchain_entry *entr }struct perf_callchain_entry * -get_perf_callchain (struct pt_regs *regs,u32 init_nr,bool kernel,bool user, +get_perf_callchain (struct pt_regs *regs,bool kernel,bool user,u32 max_stack,bool crosstask,bool add_mark) {struct perf_callchain_entry *entry;
@@ -228,11 +228,11 @@ get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user,if (!entry)return NULL ; - ctx.entry = entry; - ctx.max_stack = max_stack; - ctx.nr = entry->nr = init_nr; - ctx.contexts =0 ; - ctx.contexts_maxed = false; + ctx.entry = entry; + ctx.max_stack = max_stack; + ctx.nr = entry->nr =0 ; + ctx.contexts =0 ; + ctx.contexts_maxed = false;if (kernel && !user_mode (regs)) {if (add_mark)
kernel/events/core.c +1 -1
@@ -8210,7 +8210,7 @@ perf_callchain(struct perf_event *event, struct pt_regs *regs)if (!kernel && !user)return &__empty_callchain; - callchain =get_perf_callchain (regs,0 , kernel, user, + callchain =get_perf_callchain (regs, kernel, user, max_stack, crosstask, true);return callchain ?: &__empty_callchain; }
PATCH RESEND 2/5 perf: Have get_perf_callchain() return NULL if crosstask and user are set
In reply to Steven RostedtFrom: Josh Poimboeuf <[email protected]>
get_perf_callchain() doesn't support cross-task unwinding for user space stacks, have it return NULL if both the crosstask and user arguments are set.
--- kernel/events/callchain.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
kernel/events/callchain.c +5 -5
@@ -224,6 +224,10 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,struct perf_callchain_entry_ctx ctx;int rctx, start_entry_idx; +/* crosstask is not supported for user stacks */ +if (crosstask && user && !kernel) +return NULL ; + entry =get_callchain_entry (&rctx);if (!entry)return NULL ;
@@ -240,7 +244,7 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,perf_callchain_kernel (&ctx, regs); } -if (user) { +if (user && !crosstask) {if (!user_mode (regs)) {if (current->mm) regs =task_pt_regs (current);
@@ -249,9 +253,6 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user, }if (regs) { -if (crosstask) - goto exit_put; -if (add_mark)perf_callchain_store_context (&ctx,PERF_CONTEXT_USER );
@@ -261,7 +262,6 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user, } } -exit_put:put_callchain_entry (rctx);return entry;
Signature · 1 line
2.50.1
[tip: perf/core] perf: Have get_perf_callchain() return NULL if crosstask and user are set
The following commit has been merged into the perf/core branch of tip:
The following commit has been merged into the perf/core branch of tip:
Commit-ID: 153f9e74dec230f2e070e16fa061bc7adfd2c450 Gitweb: https://git.kernel.org/tip/153f9e74dec230f2e070e16fa061bc7adfd2c450 Author: Josh Poimboeuf <[email protected]> AuthorDate: Wed, 20 Aug 2025 14:03:40 -04:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Tue, 26 Aug 2025 09:51:12 +02:00
perf: Have get_perf_callchain() return NULL if crosstask and user are set
get_perf_callchain() doesn't support cross-task unwinding for user space stacks, have it return NULL if both the crosstask and user arguments are set.
--- kernel/events/callchain.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
kernel/events/callchain.c +5 -5
@@ -224,6 +224,10 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,struct perf_callchain_entry_ctx ctx;int rctx, start_entry_idx; +/* crosstask is not supported for user stacks */ +if (crosstask && user && !kernel) +return NULL ; + entry =get_callchain_entry (&rctx);if (!entry)return NULL ;
@@ -240,7 +244,7 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,perf_callchain_kernel (&ctx, regs); } -if (user) { +if (user && !crosstask) {if (!user_mode (regs)) {if (current->mm) regs =task_pt_regs (current);
@@ -249,9 +253,6 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user, }if (regs) { -if (crosstask) - goto exit_put; -if (add_mark)perf_callchain_store_context (&ctx,PERF_CONTEXT_USER );
@@ -261,7 +262,6 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user, } } -exit_put:put_callchain_entry (rctx);return entry;
PATCH RESEND 3/5 perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
In reply to Steven RostedtFrom: Steven Rostedt <[email protected]>
To determine if a task is a kernel thread or not, it is more reliable to use (current->flags & (PF_KTHREAD|PF_USER_WORKERi)) than to rely on current->mm being NULL. That is because some kernel tasks (io_uring helpers) may have a mm field.
--- kernel/events/callchain.c | 6 +++--- kernel/events/core.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-)
kernel/events/callchain.c +3 -3
@@ -246,10 +246,10 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,if (user && !crosstask) {if (!user_mode (regs)) { -if (current->mm) - regs =task_pt_regs (current); -else +if (current->flags & (PF_KTHREAD |PF_USER_WORKER )) regs =NULL ; +else + regs =task_pt_regs (current); }if (regs) {
kernel/events/core.c +2 -2
@@ -7446,7 +7446,7 @@ static void perf_sample_regs_user(struct perf_regs *regs_user,if (user_mode (regs)) { regs_user->abi =perf_reg_abi (current); regs_user->regs = regs; - }else if (!(current->flags &PF_KTHREAD )) { + }else if (!(current->flags & (PF_KTHREAD |PF_USER_WORKER ))) {perf_get_regs_user (regs_user, regs); }else { regs_user->abi =PERF_SAMPLE_REGS_ABI_NONE ;
@@ -8086,7 +8086,7 @@ static u64 perf_virt_to_phys(u64 virt)* Try IRQ-safe get_user_page_fast_only first. * If failed, leave phys_addr as 0. */ -if (current->mm !=NULL ) { +if (!(current->flags & (PF_KTHREAD |PF_USER_WORKER ))) {struct page *p;pagefault_disable ();
Signature · 1 line
2.50.1
[tip: perf/core] perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
The following commit has been merged into the perf/core branch of tip:
The following commit has been merged into the perf/core branch of tip:
Commit-ID: 90942f9fac05702065ff82ed0bade0d08168d4ea Gitweb: https://git.kernel.org/tip/90942f9fac05702065ff82ed0bade0d08168d4ea Author: Steven Rostedt <[email protected]> AuthorDate: Wed, 20 Aug 2025 14:03:41 -04:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Tue, 26 Aug 2025 09:51:13 +02:00
perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
To determine if a task is a kernel thread or not, it is more reliable to use (current->flags & (PF_KTHREAD|PF_USER_WORKERi)) than to rely on current->mm being NULL. That is because some kernel tasks (io_uring helpers) may have a mm field.
--- kernel/events/callchain.c | 6 +++--- kernel/events/core.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-)
kernel/events/callchain.c +3 -3
@@ -246,10 +246,10 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,if (user && !crosstask) {if (!user_mode (regs)) { -if (current->mm) - regs =task_pt_regs (current); -else +if (current->flags & (PF_KTHREAD |PF_USER_WORKER )) regs =NULL ; +else + regs =task_pt_regs (current); }if (regs) {
kernel/events/core.c +2 -2
@@ -7446,7 +7446,7 @@ static void perf_sample_regs_user(struct perf_regs *regs_user,if (user_mode (regs)) { regs_user->abi =perf_reg_abi (current); regs_user->regs = regs; - }else if (!(current->flags &PF_KTHREAD )) { + }else if (!(current->flags & (PF_KTHREAD |PF_USER_WORKER ))) {perf_get_regs_user (regs_user, regs); }else { regs_user->abi =PERF_SAMPLE_REGS_ABI_NONE ;
@@ -8086,7 +8086,7 @@ static u64 perf_virt_to_phys(u64 virt)* Try IRQ-safe get_user_page_fast_only first. * If failed, leave phys_addr as 0. */ -if (current->mm !=NULL ) { +if (!(current->flags & (PF_KTHREAD |PF_USER_WORKER ))) {struct page *p;pagefault_disable ();
Re: [RESEND][PATCH 3/5] perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
In reply to Steven RostedtHi Steven,
Quoted 48 lines · Steven Rostedt
From: Steven Rostedt <[email protected]>
To determine if a task is a kernel thread or not, it is more reliable to use (
current->flags& (PF_KTHREAD|PF_USER_WORKERi)) than to rely oncurrent->mmbeing NULL. That is because some kernel tasks (io_uringhelpers) may have a mm field.Signed-off-by Steven Rostedt (Google) <[email protected]>--- kernel/events/callchain.c | 6 +++--- kernel/events/core.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-)kernel/events/callchain.c +3
-3@@ -246,10 +246,10 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,if (user && !crosstask) {if (!user_mode (regs)) { -if (current->mm) - regs =task_pt_regs (current); -else +if (current->flags & (PF_KTHREAD |PF_USER_WORKER )) regs =NULL ; +else + regs =task_pt_regs (current); }if (regs) {kernel/events/core.c +1
-1@@ -7446,7 +7446,7 @@ static void perf_sample_regs_user(struct perf_regs *regs_user,if (user_mode (regs)) { regs_user->abi =perf_reg_abi (current); regs_user->regs = regs; - }else if (!(current->flags &PF_KTHREAD )) { + }else if (!(current->flags & (PF_KTHREAD |PF_USER_WORKER ))) {perf_get_regs_user (regs_user, regs); }else { regs_user->abi =PERF_SAMPLE_REGS_ABI_NONE ;
kernel/events/core.c static u64 perf_virt_to_phys(u64 virt) · line 8089
Quoted 5 lines
kernel/events/core.c +1
-1@@ -8086,7 +8086,7 @@ static u64 perf_virt_to_phys(u64 virt)* Try IRQ-safe get_user_page_fast_only first. * If failed, leave phys_addr as 0. */ -if (current->mm !=NULL ) { +if (!(current->flags & (PF_KTHREAD |PF_USER_WORKER ))) {
Subsequent code uses current->mm. This triggers a crash when running a page table stress test. See below for details. I have seen the crash in 6.12.57 and 6.18-rc5.
Guenter
---
[ 120.334908] BUG: kernel NULL pointer dereference, address: 0000000000000078 [ 120.341901] #PF: supervisor read access in kernel mode [ 120.347055] #PF: error_code(0x0000) - not-present page [ 120.352208] PGD 0 P4D 0 [ 120.354750] Oops: Oops: 0000 [#1] SMP NOPTI [ 120.358946] CPU: 36 UID: 0 PID: 14127 Comm: page_table_stre Tainted: G S O 6.18.0-smp-DEV #2 NONE [ 120.369242] Tainted: [S]=CPU_OUT_OF_SPEC, [O]=OOT_MODULE [ 120.374568] Hardware name: Google LLC Indus/Indus_QC_03, BIOS 30.116.4 08/29/2025 [ 120.382075] RIP: 0010:gup_fast_fallback+0x150/0xb60 [ 120.386977] Code: d0 c9 8b 48 89 84 24 a0 00 00 00 48 8b 80 30 05 00 00 0f b6 0d 0d 6b 1a 01 49 89 f8 49 d3 e8 41 81 e0 ff 01 00 00 41 c1 e0 03 <4c> 03 40 78 4c 8d 5b ff 44 89 c8 83 e0 01 48 8d 04 45 05 00 00 00 [ 120.405809] RSP: 0018:ffffa32be5f9b7a0 EFLAGS: 00010006 [ 120.411051] RAX: 0000000000000000 RBX: 00007f0f57dfd000 RCX: 0000000000000027 [ 120.418210] RDX: 0000000000000046 RSI: 0000000000000001 RDI: 00007f0f57dfc000 [ 120.425368] RBP: 0000000000000000 R08: 00000000000007f0 R09: 0000000000100002 [ 120.432526] R10: ffffa32be5f9b8c8 R11: 0000000000000000 R12: 00007f0f57dfc6c0 [ 120.439683] R13: ffff99b44dd7c800 R14: 00000000fffffff2 R15: 00000000000800c3 [ 120.446842] FS: 0000000000000000(0000) GS:ffff9a127357b000(0000) knlGS:0000000000000000 [ 120.454956] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 120.460721] CR2: 0000000000000078 CR3: 000000512d03e006 CR4: 00000000007706f0 [ 120.467879] PKRU: 55555554 [ 120.470592] Call Trace: [ 120.473045] <TASK> [ 120.475152] perf_prepare_sample+0x77b/0x910 [ 120.479445] perf_event_output+0x35/0x100 [ 120.483467] intel_pmu_drain_pebs_nhm+0x570/0x750 [ 120.488198] intel_pmu_pebs_sched_task+0x74/0x80 [ 120.492839] ? __put_partials+0xd6/0x130 [ 120.496775] ? __mt_destroy+0x3f/0x80 [ 120.500451] ? put_cpu_partial+0x9b/0xc0 [ 120.504384] ? __slab_free+0x249/0x320 [ 120.508144] ? refill_obj_stock+0x120/0x1a0 [ 120.512341] ? __mt_destroy+0x3f/0x80 [ 120.516013] ? kfree+0x2ca/0x390 [ 120.519254] ? update_load_avg+0x1c8/0x7d0 [ 120.523364] ? update_entity_lag+0xf6/0x110 [ 120.527560] intel_pmu_sched_task+0x1d/0x30 [ 120.531755] perf_pmu_sched_task+0xf2/0x1a0 [ 120.535952] __perf_event_task_sched_out+0x3f/0x1f0 [ 120.540844] ? pick_next_task_fair+0x3e/0x2a0 [ 120.545214] __schedule+0xad0/0xb40 [ 120.548715] do_task_dead+0x48/0xa0 [ 120.552215] do_exit+0x734/0x920 [ 120.555463] ? do_exit+0x9/0x920 [ 120.558699] do_group_exit+0x85/0x90 [ 120.562284] __x64_sys_exit_group+0x17/0x20 [ 120.566478] x64_sys_call+0x21f7/0x2200 [ 120.570327] do_syscall_64+0x6f/0x940 [ 120.574001] ? clear_bhb_loop+0x50/0xa0 [ 120.577849] entry_SYSCALL_64_after_hwframe+0x76/0x7e [ 120.582915] RIP: 0033:0x7f0f5a0d2c48 [ 120.586501] Code: Unable to access opcode bytes at 0x7f0f5a0d2c1e. [ 120.592700] RSP: 002b:00007f0f57dfcec8 EFLAGS: 00000207 ORIG_RAX: 00000000000000e7 [ 120.600294] RAX: ffffffffffffffda RBX: 00007f0f57dfd700 RCX: 00007f0f5a0d2c48 [ 120.607452] RDX: 00007f0f57dfd660 RSI: 0000000000000000 RDI: 0000000000000000 [ 120.614607] RBP: 00007f0f57dfcef0 R08: 00007f0f57dfd700 R09: 00007f0f57dfd700 [ 120.621765] R10: 00007f0f5a17a6c0 R11: 0000000000000207 R12: 00007f0f57dfd9d0 [ 120.628923] R13: 00007ffc64840aa6 R14: 00007f0f57dfdd1c R15: 00007f0f57dfcfc0 [ 120.636081] </TASK> [ 120.638272] Modules linked in: vfat fat i2c_mux_pca954x i2c_mux spidev cdc_acm xhci_pci xhci_hcd gq(O) sha3_generic [ 120.649976] gsmi: Log Shutdown Reason 0x03 [ 120.654086] CR2: 0000000000000078 [ 120.657409] ---[ end trace 0000000000000000 ]---
Stack decode:
[ 120.334908] BUG: kernel NULL pointer dereference, address: 0000000000000078 [ 120.341901] #PF: supervisor read access in kernel mode [ 120.347055] #PF: error_code(0x0000) - not-present page [ 120.352208] PGD 0 P4D 0 [ 120.354750] Oops: Oops: 0000 [#1] SMP NOPTI [ 120.358946] CPU: 36 UID: 0 PID: 14127 Comm: page_table_stre Tainted: G S O 6.18.0-smp-DEV #2 NONE [ 120.369242] Tainted: [S]=CPU_OUT_OF_SPEC, [O]=OOT_MODULE [ 120.374568] Hardware name: Google LLC Indus/Indus_QC_03, BIOS 30.116.4 08/29/2025 [ 120.382075] RIP: 0010:gup_fast_fallback (./include/linux/pgtable.h:140 mm/gup.c:3795 mm/gup.c:3899 mm/gup.c:3946) [ 120.386977] Code: d0 c9 8b 48 89 84 24 a0 00 00 00 48 8b 80 30 05 00 00 0f b6 0d 0d 6b 1a 01 49 89 f8 49 d3 e8 41 81 e0 ff 01 00 00 41 c1 e0 03 <4c> 03 40 78 4c 8d 5b ff 44 89 c8 83 e0 01 48 8d 04 45 05 00 00 00 All code ======== 0: d0 c9 ror $1,%cl 2: 8b 48 89 mov -0x77(%rax),%ecx 5: 84 24 a0 test %ah,(%rax,%riz,4) 8: 00 00 add %al,(%rax) a: 00 48 8b add %cl,-0x75(%rax) d: 80 30 05 xorb $0x5,(%rax) 10: 00 00 add %al,(%rax) 12: 0f b6 0d 0d 6b 1a 01 movzbl 0x11a6b0d(%rip),%ecx # 0x11a6b26 19: 49 89 f8 mov %rdi,%r8 1c: 49 d3 e8 shr %cl,%r8 1f: 41 81 e0 ff 01 00 00 and $0x1ff,%r8d 26: 41 c1 e0 03 shl $0x3,%r8d 2a:* 4c 03 40 78 add 0x78(%rax),%r8 <-- trapping instruction 2e: 4c 8d 5b ff lea -0x1(%rbx),%r11 32: 44 89 c8 mov %r9d,%eax 35: 83 e0 01 and $0x1,%eax 38: 48 8d 04 45 05 00 00 lea 0x5(,%rax,2),%rax 3f: 00
Code starting with the faulting instruction
===========================================
0: 4c 03 40 78 add 0x78(%rax),%r8 4: 4c 8d 5b ff lea -0x1(%rbx),%r11 8: 44 89 c8 mov %r9d,%eax b: 83 e0 01 and $0x1,%eax e: 48 8d 04 45 05 00 00 lea 0x5(,%rax,2),%rax 15: 00 [ 120.405809] RSP: 0018:ffffa32be5f9b7a0 EFLAGS: 00010006 [ 120.411051] RAX: 0000000000000000 RBX: 00007f0f57dfd000 RCX: 0000000000000027 [ 120.418210] RDX: 0000000000000046 RSI: 0000000000000001 RDI: 00007f0f57dfc000 [ 120.425368] RBP: 0000000000000000 R08: 00000000000007f0 R09: 0000000000100002 [ 120.432526] R10: ffffa32be5f9b8c8 R11: 0000000000000000 R12: 00007f0f57dfc6c0 [ 120.439683] R13: ffff99b44dd7c800 R14: 00000000fffffff2 R15: 00000000000800c3 [ 120.446842] FS: 0000000000000000(0000) GS:ffff9a127357b000(0000) knlGS:0000000000000000 [ 120.454956] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 120.460721] CR2: 0000000000000078 CR3: 000000512d03e006 CR4: 00000000007706f0 [ 120.467879] PKRU: 55555554 [ 120.470592] Call Trace: [ 120.473045] <TASK> [ 120.475152] perf_prepare_sample (kernel/events/core.c:7490 kernel/events/core.c:8302) [ 120.479445] perf_event_output (kernel/events/core.c:8389 kernel/events/core.c:8426) [ 120.483467] intel_pmu_drain_pebs_nhm (arch/x86/events/intel/ds.c:? arch/x86/events/intel/ds.c:2182 arch/x86/events/intel/ds.c:2372) [ 120.488198] intel_pmu_pebs_sched_task (arch/x86/events/intel/ds.c:939 arch/x86/events/intel/ds.c:1248) [ 120.492839] ? __put_partials (mm/slub.c:3195) [ 120.496775] ? __mt_destroy (lib/maple_tree.c:? lib/maple_tree.c:6883) [ 120.500451] ? put_cpu_partial (mm/slub.c:3278) [ 120.504384] ? __slab_free (mm/slub.c:4521) [ 120.508144] ? refill_obj_stock (./include/linux/percpu-refcount.h:335 ./include/linux/percpu-refcount.h:351 ./include/linux/memcontrol.h:988 mm/memcontrol.c:3732) [ 120.512341] ? __mt_destroy (lib/maple_tree.c:? lib/maple_tree.c:6883) [ 120.516013] ? kfree (mm/slab.h:681 mm/slub.c:4649 mm/slub.c:4797) [ 120.519254] ? update_load_avg (kernel/sched/fair.c:5376 kernel/sched/fair.c:5601 kernel/sched/fair.c:5720) [ 120.523364] ? update_entity_lag (kernel/sched/fair.c:?) [ 120.527560] intel_pmu_sched_task (arch/x86/events/intel/core.c:5231) [ 120.531755] perf_pmu_sched_task (kernel/events/core.c:1219 kernel/events/core.c:1231 kernel/events/core.c:3739 kernel/events/core.c:3755) [ 120.535952] __perf_event_task_sched_out (kernel/events/core.c:3776) [ 120.540844] ? pick_next_task_fair (kernel/sched/sched.h:4660 kernel/sched/sched.h:4666 kernel/sched/fair.c:9593 kernel/sched/fair.c:15504) [ 120.545214] __schedule (kernel/sched/core.c:7405 kernel/sched/core.c:8080) [ 120.548715] do_task_dead (??:?) [ 120.552215] do_exit (./include/linux/list.h:364 kernel/exit.c:810 kernel/exit.c:1030) [ 120.555463] ? do_exit (kernel/exit.c:934) [ 120.558699] do_group_exit (kernel/exit.c:1161) [ 120.562284] __x64_sys_exit_group (kernel/exit.c:1172) [ 120.566478] x64_sys_call (arch/x86/entry/syscall_64.c:32) [ 120.570327] do_syscall_64 (arch/x86/entry/common.c:57 arch/x86/entry/common.c:100) [ 120.574001] ? clear_bhb_loop (arch/x86/entry/entry_64.S:1598)
Re: [RESEND][PATCH 3/5] perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
Quoted 1 line · On Wed, 12 Nov 2025 19:11:15 -0800 Guenter Roeck <[email protected]> wrote:
Hi Steven,
Hi Guenter,
Somehow this got filed away in my archive without me seeing it.
Quoted 51 lines · Steven Rostedt
Quoted 49 lines
From: Steven Rostedt <[email protected]>
To determine if a task is a kernel thread or not, it is more reliable to use (
current->flags& (PF_KTHREAD|PF_USER_WORKERi)) than to rely oncurrent->mmbeing NULL. That is because some kernel tasks (io_uringhelpers) may have a mm field.Signed-off-by Steven Rostedt (Google) <[email protected]>--- kernel/events/callchain.c | 6 +++--- kernel/events/core.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-)kernel/events/callchain.c +3
-3@@ -246,10 +246,10 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,if (user && !crosstask) {if (!user_mode (regs)) { -if (current->mm) - regs =task_pt_regs (current); -else +if (current->flags & (PF_KTHREAD |PF_USER_WORKER )) regs =NULL ; +else + regs =task_pt_regs (current); }if (regs) {kernel/events/core.c +1
-1@@ -7446,7 +7446,7 @@ static void perf_sample_regs_user(struct perf_regs *regs_user,if (user_mode (regs)) { regs_user->abi =perf_reg_abi (current); regs_user->regs = regs; - }else if (!(current->flags &PF_KTHREAD )) { + }else if (!(current->flags & (PF_KTHREAD |PF_USER_WORKER ))) {perf_get_regs_user (regs_user, regs); }else { regs_user->abi =PERF_SAMPLE_REGS_ABI_NONE ;@@ -8086,7 +8086,7 @@ static u64 perf_virt_to_phys(u64 virt)* Try IRQ-safe get_user_page_fast_only first.
Quoted 8 lines
kernel/events/core.c static u64 perf_virt_to_phys(u64 virt) · line 8089
Quoted 4 lines
kernel/events/core.c +1
-1* If failed, leave phys_addr as 0. */ -if (current->mm !=NULL ) { +if (!(current->flags & (PF_KTHREAD |PF_USER_WORKER ))) {Subsequent code uses
current->mm. This triggers a crash when running a page table stress test. See below for details. I have seen the crash in 6.12.57 and 6.18-rc5.
Hmm, that should not happen. But obvious it is. Can you add this:
kernel/events/callchain.c +2 -0
@@ -248,6 +248,8 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,if (!user_mode (regs)) {if (current->flags & (PF_KTHREAD |PF_USER_WORKER )) goto exit_put; +if (WARN_ONCE (!current->mm,"Bad flags %x" , current->flags)) + goto exit_put; regs =task_pt_regs (current); }
I'd like to see what current->flags are when ->mm is NULL.
Thanks!
-- Steve
Re: [RESEND][PATCH 3/5] perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
In reply to Guenter RoeckQuoted 34 lines · On Wed, 12 Nov 2025 19:11:15 -0800 Guenter Roeck <[email protected]> wrote:
[ 120.334908] BUG: kernel NULL pointer dereference, address: 0000000000000078 [ 120.341901] #PF: supervisor read access in kernel mode [ 120.347055] #PF: error_code(0x0000) - not-present page [ 120.352208] PGD 0 P4D 0 [ 120.354750] Oops: Oops: 0000 [#1] SMP NOPTI [ 120.358946] CPU: 36 UID: 0 PID: 14127 Comm: page_table_stre Tainted: G S O 6.18.0-smp-DEV #2 NONE [ 120.369242] Tainted: [S]=CPU_OUT_OF_SPEC, [O]=OOT_MODULE [ 120.374568] Hardware name: Google LLC Indus/Indus_QC_03, BIOS 30.116.4 08/29/2025 [ 120.382075] RIP: 0010:gup_fast_fallback+0x150/0xb60 [ 120.386977] Code: d0 c9 8b 48 89 84 24 a0 00 00 00 48 8b 80 30 05 00 00 0f b6 0d 0d 6b 1a 01 49 89 f8 49 d3 e8 41 81 e0 ff 01 00 00 41 c1 e0 03 <4c> 03 40 78 4c 8d 5b ff 44 89 c8 83 e0 01 48 8d 04 45 05 00 00 00 [ 120.405809] RSP: 0018:ffffa32be5f9b7a0 EFLAGS: 00010006 [ 120.411051] RAX: 0000000000000000 RBX: 00007f0f57dfd000 RCX: 0000000000000027 [ 120.418210] RDX: 0000000000000046 RSI: 0000000000000001 RDI: 00007f0f57dfc000 [ 120.425368] RBP: 0000000000000000 R08: 00000000000007f0 R09: 0000000000100002 [ 120.432526] R10: ffffa32be5f9b8c8 R11: 0000000000000000 R12: 00007f0f57dfc6c0 [ 120.439683] R13: ffff99b44dd7c800 R14: 00000000fffffff2 R15: 00000000000800c3 [ 120.446842] FS: 0000000000000000(0000) GS:ffff9a127357b000(0000) knlGS:0000000000000000 [ 120.454956] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 120.460721] CR2: 0000000000000078 CR3: 000000512d03e006 CR4: 00000000007706f0 [ 120.467879] PKRU: 55555554 [ 120.470592] Call Trace: [ 120.473045] <TASK> [ 120.475152] perf_prepare_sample+0x77b/0x910 [ 120.479445] perf_event_output+0x35/0x100 [ 120.483467] intel_pmu_drain_pebs_nhm+0x570/0x750 [ 120.488198] intel_pmu_pebs_sched_task+0x74/0x80 [ 120.492839] ? __put_partials+0xd6/0x130 [ 120.496775] ? __mt_destroy+0x3f/0x80 [ 120.500451] ? put_cpu_partial+0x9b/0xc0 [ 120.504384] ? __slab_free+0x249/0x320 [ 120.508144] ? refill_obj_stock+0x120/0x1a0 [ 120.512341] ? __mt_destroy+0x3f/0x80 [ 120.516013] ? kfree+0x2ca/0x390
Quoted 8 lines
[ 120.519254] ? update_load_avg+0x1c8/0x7d0 [ 120.523364] ? update_entity_lag+0xf6/0x110 [ 120.527560] intel_pmu_sched_task+0x1d/0x30 [ 120.531755] perf_pmu_sched_task+0xf2/0x1a0 [ 120.535952] __perf_event_task_sched_out+0x3f/0x1f0 [ 120.540844] ? pick_next_task_fair+0x3e/0x2a0 [ 120.545214] __schedule+0xad0/0xb40 [ 120.548715] do_task_dead+0x48/0xa0
Ah, this is called at do_task_dead()
I guess we need to also test for !current->mm because the flags set for an exiting task is done when we can still do callchains. Thus, the only way to know if it is safe to do a callchain when a task is exiting is via task->mm and not task->flags :-/
-- Steve
Quoted 21 lines
[ 120.552215] do_exit+0x734/0x920 [ 120.555463] ? do_exit+0x9/0x920 [ 120.558699] do_group_exit+0x85/0x90 [ 120.562284] __x64_sys_exit_group+0x17/0x20 [ 120.566478] x64_sys_call+0x21f7/0x2200 [ 120.570327] do_syscall_64+0x6f/0x940 [ 120.574001] ? clear_bhb_loop+0x50/0xa0 [ 120.577849] entry_SYSCALL_64_after_hwframe+0x76/0x7e [ 120.582915] RIP: 0033:0x7f0f5a0d2c48 [ 120.586501] Code: Unable to access opcode bytes at 0x7f0f5a0d2c1e. [ 120.592700] RSP: 002b:00007f0f57dfcec8 EFLAGS: 00000207 ORIG_RAX: 00000000000000e7 [ 120.600294] RAX: ffffffffffffffda RBX: 00007f0f57dfd700 RCX: 00007f0f5a0d2c48 [ 120.607452] RDX: 00007f0f57dfd660 RSI: 0000000000000000 RDI: 0000000000000000 [ 120.614607] RBP: 00007f0f57dfcef0 R08: 00007f0f57dfd700 R09: 00007f0f57dfd700 [ 120.621765] R10: 00007f0f5a17a6c0 R11: 0000000000000207 R12: 00007f0f57dfd9d0 [ 120.628923] R13: 00007ffc64840aa6 R14: 00007f0f57dfdd1c R15: 00007f0f57dfcfc0 [ 120.636081] </TASK> [ 120.638272] Modules linked in: vfat fat i2c_mux_pca954x i2c_mux spidev cdc_acm xhci_pci xhci_hcd gq(O) sha3_generic [ 120.649976] gsmi: Log Shutdown Reason 0x03 [ 120.654086] CR2: 0000000000000078 [ 120.657409] ---[ end trace 0000000000000000 ]---
Steven Rostedt
maintainerRe: [RESEND][PATCH 3/5] perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
Quoted 4 lines · On Mon, 26 Jan 2026 12:05:53 -0500 Steven Rostedt <[email protected]> wrote:
I guess we need to also test for !current->mm because the flags set for an exiting task is done when we can still do callchains. Thus, the only way to know if it is safe to do a callchain when a task is exiting is via
task->mmand nottask->flags:-/
Can you test this patch?
-- Steve
kernel/events/callchain.c +8 -1
@@ -246,7 +246,14 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,if (user && !crosstask) {if (!user_mode (regs)) { -if (current->flags & (PF_KTHREAD |PF_USER_WORKER )) +/* +* Testing current->mm is not enough as some kernel threads +* may have one set. But testing the flags is not enough +* either as this can be called after a user task +* frees its mm just before it exits. +*/ +if (!current->mm || + (current->flags & (PF_KTHREAD |PF_USER_WORKER ))) goto exit_put; regs =task_pt_regs (current); }
Re: [RESEND][PATCH 3/5] perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
Quoted 10 lines · Steven Rostedt
Quoted 4 lines · On Mon, 26 Jan 2026 12:05:53 -0500 Steven Rostedt <[email protected]> wrote:
I guess we need to also test for !current->mm because the flags set for an exiting task is done when we can still do callchains. Thus, the only way to know if it is safe to do a callchain when a task is exiting is via
task->mmand nottask->flags:-/Can you test this patch?
Sure, though we had dropped the offending patch from the LTS backport, so that will take a bit.
Guenter
Quoted 22 lines
-- Steve
kernel/events/callchain.c +8
-1@@ -246,7 +246,14 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,if (user && !crosstask) {if (!user_mode (regs)) { -if (current->flags & (PF_KTHREAD |PF_USER_WORKER )) +/* +* Testing current->mm is not enough as some kernel threads +* may have one set. But testing the flags is not enough +* either as this can be called after a user task +* frees its mm just before it exits. +*/ +if (!current->mm || + (current->flags & (PF_KTHREAD |PF_USER_WORKER ))) goto exit_put; regs =task_pt_regs (current); }
Re: [RESEND][PATCH 3/5] perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
In reply to Steven RostedtQuoted 10 lines · Steven Rostedt
Quoted 4 lines · On Mon, 26 Jan 2026 12:05:53 -0500 Steven Rostedt <[email protected]> wrote:
I guess we need to also test for !current->mm because the flags set for an exiting task is done when we can still do callchains. Thus, the only way to know if it is safe to do a callchain when a task is exiting is via
task->mmand nottask->flags:-/Can you test this patch?
Still crashing, though not as often and with a slightly different backtrace. I added the backtrace to the bug report @ Google.
Guenter
Quoted 22 lines
-- Steve
kernel/events/callchain.c +8
-1@@ -246,7 +246,14 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,if (user && !crosstask) {if (!user_mode (regs)) { -if (current->flags & (PF_KTHREAD |PF_USER_WORKER )) +/* +* Testing current->mm is not enough as some kernel threads +* may have one set. But testing the flags is not enough +* either as this can be called after a user task +* frees its mm just before it exits. +*/ +if (!current->mm || + (current->flags & (PF_KTHREAD |PF_USER_WORKER ))) goto exit_put; regs =task_pt_regs (current); }
Steven Rostedt
maintainerRe: [RESEND][PATCH 3/5] perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
Quoted 2 lines · On Mon, 26 Jan 2026 17:32:35 -0800 Guenter Roeck <[email protected]> wrote:
Still crashing, though not as often and with a slightly different backtrace. I added the backtrace to the bug report @ Google.
I figured there would be other locations. A while ago I had a patch to wrap the checks in a "is_user_thread()" helper function[1], but Ingo had issues with it. It seems now it's biting us in the butt and let's see if it would help now. I modified it slightly.
[1] https://lore.kernel.org/linux-trace-kernel/[email protected]/
If the below fixes it, I'll resend it, but now as a real bug fix.
-- Steve
include/linux/sched.h +5 -0
@@ -1776,6 +1776,11 @@ static __always_inline bool is_percpu_thread(void) (current->nr_cpus_allowed ==1 ); } +static __always_inline bool is_user_task(struct task_struct *task) +{ +return task->mm && !(task->flags & (PF_KTHREAD |PF_USER_WORKER )); +} +/* Per-process atomic flags. */ #define PFA_NO_NEW_PRIVS 0/* May not gain new privileges. */ #define PFA_SPREAD_PAGE 1/* Spread page cache over cpuset */
kernel/events/callchain.c +1 -1
@@ -246,7 +246,7 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,if (user && !crosstask) {if (!user_mode (regs)) { -if (current->flags & (PF_KTHREAD |PF_USER_WORKER )) +if (!is_user_task (current)) goto exit_put; regs =task_pt_regs (current); }
kernel/events/core.c +3 -3
@@ -7460,7 +7460,7 @@ static void perf_sample_regs_user(struct perf_regs *regs_user,if (user_mode (regs)) { regs_user->abi =perf_reg_abi (current); regs_user->regs = regs; - }else if (!(current->flags & (PF_KTHREAD |PF_USER_WORKER ))) { + }else if (is_user_task (current)) {perf_get_regs_user (regs_user, regs); }else { regs_user->abi =PERF_SAMPLE_REGS_ABI_NONE ;
@@ -8100,7 +8100,7 @@ static u64 perf_virt_to_phys(u64 virt)* Try IRQ-safe get_user_page_fast_only first. * If failed, leave phys_addr as 0. */ -if (!(current->flags & (PF_KTHREAD |PF_USER_WORKER ))) { +if (is_user_task (current)) {struct page *p;pagefault_disable ();
@@ -8215,7 +8215,7 @@ perf_callchain(struct perf_event *event, struct pt_regs *regs) {bool kernel = !event->attr.exclude_callchain_kernel;bool user = !event->attr.exclude_callchain_user && - !(current->flags & (PF_KTHREAD |PF_USER_WORKER )); +is_user_task (current);/* Disallow cross-task user callchains. */ bool crosstask = event->ctx->task && event->ctx->task != current; bool defer_user = IS_ENABLED(CONFIG_UNWIND_USER) && user &&
Re: [RESEND][PATCH 3/5] perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
Hi Steven,
Quoted 6 lines · Steven Rostedt
Quoted 2 lines · On Mon, 26 Jan 2026 17:32:35 -0800 Guenter Roeck <[email protected]> wrote:
Still crashing, though not as often and with a slightly different backtrace. I added the backtrace to the bug report @ Google.
Quoted 9 lines
I figured there would be other locations. A while ago I had a patch to wrap the checks in a "
is_user_thread()" helper function[1], but Ingo had issues with it. It seems now it's biting us in the butt and let's see if it would help now. I modified it slightly.[1] https://lore.kernel.org/linux-trace-kernel/[email protected]/
If the below fixes it, I'll resend it, but now as a real bug fix.
Trying. So far I can no longer reproduce the problem with the patch below applied. Obviously that doesn't mean that the problem is fixed, only that I can no longer reproduce it. I'll keep trying with different platforms.
Guenter
Quoted 62 lines
-- Steve
include/linux/sched.h +5
-0@@ -1776,6 +1776,11 @@ static __always_inline bool is_percpu_thread(void) (current->nr_cpus_allowed ==1 ); } +static __always_inline bool is_user_task(struct task_struct *task) +{ +return task->mm && !(task->flags & (PF_KTHREAD |PF_USER_WORKER )); +} +/* Per-process atomic flags. */ #define PFA_NO_NEW_PRIVS 0/* May not gain new privileges. */ #define PFA_SPREAD_PAGE 1/* Spread page cache over cpuset */ kernel/events/callchain.c +1
-1@@ -246,7 +246,7 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,if (user && !crosstask) {if (!user_mode (regs)) { -if (current->flags & (PF_KTHREAD |PF_USER_WORKER )) +if (!is_user_task (current)) goto exit_put; regs =task_pt_regs (current); }kernel/events/core.c +3
-3@@ -7460,7 +7460,7 @@ static void perf_sample_regs_user(struct perf_regs *regs_user,if (user_mode (regs)) { regs_user->abi =perf_reg_abi (current); regs_user->regs = regs; - }else if (!(current->flags & (PF_KTHREAD |PF_USER_WORKER ))) { + }else if (is_user_task (current)) {perf_get_regs_user (regs_user, regs); }else { regs_user->abi =PERF_SAMPLE_REGS_ABI_NONE ;@@ -8100,7 +8100,7 @@ static u64 perf_virt_to_phys(u64 virt)* Try IRQ-safe get_user_page_fast_only first. * If failed, leave phys_addr as 0. */ -if (!(current->flags & (PF_KTHREAD |PF_USER_WORKER ))) { +if (is_user_task (current)) {struct page *p;pagefault_disable ();@@ -8215,7 +8215,7 @@ perf_callchain(struct perf_event *event, struct pt_regs *regs) {bool kernel = !event->attr.exclude_callchain_kernel;bool user = !event->attr.exclude_callchain_user && - !(current->flags & (PF_KTHREAD |PF_USER_WORKER )); +is_user_task (current);/* Disallow cross-task user callchains. */ bool crosstask = event->ctx->task && event->ctx->task != current; bool defer_user = IS_ENABLED(CONFIG_UNWIND_USER) && user &&
Steven Rostedt
maintainerRe: [RESEND][PATCH 3/5] perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
Quoted 3 lines · On Tue, 27 Jan 2026 11:07:05 -0800 Guenter Roeck <[email protected]> wrote:
Trying. So far I can no longer reproduce the problem with the patch below applied. Obviously that doesn't mean that the problem is fixed, only that I can no longer reproduce it. I'll keep trying with different platforms.
Well, the revert of the patch just replaces the flags test with a test for current->mm being NULL. This patch simply makes all those locations test both the flags and for current->mm being NULL.
I can't see how it doesn't fix it.
Anyway, I'll start making this into a legitimate patch.
Thanks,
-- Steve
Guenter Roeck
Tested-byRe: [RESEND][PATCH 3/5] perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
In reply to Steven RostedtQuoted 6 lines · Steven Rostedt
Quoted 2 lines · On Mon, 26 Jan 2026 17:32:35 -0800 Guenter Roeck <[email protected]> wrote:
Still crashing, though not as often and with a slightly different backtrace. I added the backtrace to the bug report @ Google.
Quoted 9 lines
I figured there would be other locations. A while ago I had a patch to wrap the checks in a "
is_user_thread()" helper function[1], but Ingo had issues with it. It seems now it's biting us in the butt and let's see if it would help now. I modified it slightly.[1] https://lore.kernel.org/linux-trace-kernel/[email protected]/
If the below fixes it, I'll resend it, but now as a real bug fix.
All attempts to reproduce the problem after applying the patch below failed, so feel free to go ahead and add
to the patch.
Thanks,
Guenter
Quoted 62 lines
-- Steve
include/linux/sched.h +5
-0@@ -1776,6 +1776,11 @@ static __always_inline bool is_percpu_thread(void) (current->nr_cpus_allowed ==1 ); } +static __always_inline bool is_user_task(struct task_struct *task) +{ +return task->mm && !(task->flags & (PF_KTHREAD |PF_USER_WORKER )); +} +/* Per-process atomic flags. */ #define PFA_NO_NEW_PRIVS 0/* May not gain new privileges. */ #define PFA_SPREAD_PAGE 1/* Spread page cache over cpuset */ kernel/events/callchain.c +1
-1@@ -246,7 +246,7 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,if (user && !crosstask) {if (!user_mode (regs)) { -if (current->flags & (PF_KTHREAD |PF_USER_WORKER )) +if (!is_user_task (current)) goto exit_put; regs =task_pt_regs (current); }kernel/events/core.c +3
-3@@ -7460,7 +7460,7 @@ static void perf_sample_regs_user(struct perf_regs *regs_user,if (user_mode (regs)) { regs_user->abi =perf_reg_abi (current); regs_user->regs = regs; - }else if (!(current->flags & (PF_KTHREAD |PF_USER_WORKER ))) { + }else if (is_user_task (current)) {perf_get_regs_user (regs_user, regs); }else { regs_user->abi =PERF_SAMPLE_REGS_ABI_NONE ;@@ -8100,7 +8100,7 @@ static u64 perf_virt_to_phys(u64 virt)* Try IRQ-safe get_user_page_fast_only first. * If failed, leave phys_addr as 0. */ -if (!(current->flags & (PF_KTHREAD |PF_USER_WORKER ))) { +if (is_user_task (current)) {struct page *p;pagefault_disable ();@@ -8215,7 +8215,7 @@ perf_callchain(struct perf_event *event, struct pt_regs *regs) {bool kernel = !event->attr.exclude_callchain_kernel;bool user = !event->attr.exclude_callchain_user && - !(current->flags & (PF_KTHREAD |PF_USER_WORKER )); +is_user_task (current);/* Disallow cross-task user callchains. */ bool crosstask = event->ctx->task && event->ctx->task != current; bool defer_user = IS_ENABLED(CONFIG_UNWIND_USER) && user &&
PATCH RESEND 4/5 perf: Simplify get_perf_callchain() user logic
In reply to Steven RostedtFrom: Josh Poimboeuf <[email protected]>
Simplify the get_perf_callchain() user logic a bit. task_pt_regs() should never be NULL.
--- kernel/events/callchain.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-)
kernel/events/callchain.c +8 -10
@@ -247,21 +247,19 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,if (user && !crosstask) {if (!user_mode (regs)) {if (current->flags & (PF_KTHREAD |PF_USER_WORKER )) - regs =NULL ; -else - regs =task_pt_regs (current); + goto exit_put; + regs =task_pt_regs (current); } -if (regs) { -if (add_mark) -perf_callchain_store_context (&ctx,PERF_CONTEXT_USER ); +if (add_mark) +perf_callchain_store_context (&ctx,PERF_CONTEXT_USER ); - start_entry_idx = entry->nr; -perf_callchain_user (&ctx, regs); -fixup_uretprobe_trampoline_entries (entry, start_entry_idx); - } + start_entry_idx = entry->nr; +perf_callchain_user (&ctx, regs); +fixup_uretprobe_trampoline_entries (entry, start_entry_idx); } +exit_put:put_callchain_entry (rctx);return entry;
Signature · 1 line
2.50.1
[tip: perf/core] perf: Simplify get_perf_callchain() user logic
The following commit has been merged into the perf/core branch of tip:
The following commit has been merged into the perf/core branch of tip:
Commit-ID: d77e3319e31098a6cb97b7ce4e71ba676e327fd7 Gitweb: https://git.kernel.org/tip/d77e3319e31098a6cb97b7ce4e71ba676e327fd7 Author: Josh Poimboeuf <[email protected]> AuthorDate: Wed, 20 Aug 2025 14:03:42 -04:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Tue, 26 Aug 2025 09:51:13 +02:00
perf: Simplify get_perf_callchain() user logic
Simplify the get_perf_callchain() user logic a bit. task_pt_regs() should never be NULL.
--- kernel/events/callchain.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-)
kernel/events/callchain.c +8 -10
@@ -247,21 +247,19 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,if (user && !crosstask) {if (!user_mode (regs)) {if (current->flags & (PF_KTHREAD |PF_USER_WORKER )) - regs =NULL ; -else - regs =task_pt_regs (current); + goto exit_put; + regs =task_pt_regs (current); } -if (regs) { -if (add_mark) -perf_callchain_store_context (&ctx,PERF_CONTEXT_USER ); +if (add_mark) +perf_callchain_store_context (&ctx,PERF_CONTEXT_USER ); - start_entry_idx = entry->nr; -perf_callchain_user (&ctx, regs); -fixup_uretprobe_trampoline_entries (entry, start_entry_idx); - } + start_entry_idx = entry->nr; +perf_callchain_user (&ctx, regs); +fixup_uretprobe_trampoline_entries (entry, start_entry_idx); } +exit_put:put_callchain_entry (rctx);return entry;
PATCH RESEND 5/5 perf: Skip user unwind if the task is a kernel thread
In reply to Steven RostedtFrom: Josh Poimboeuf <[email protected]>
If the task is not a user thread, there's no user stack to unwind.
--- kernel/events/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/events/core.c +2 -1
@@ -8198,7 +8198,8 @@ struct perf_callchain_entry * perf_callchain(struct perf_event *event, struct pt_regs *regs) { bool kernel = !event->attr.exclude_callchain_kernel; -bool user = !event->attr.exclude_callchain_user; +bool user = !event->attr.exclude_callchain_user && + !(current->flags & (PF_KTHREAD |PF_USER_WORKER ));/* Disallow cross-task user callchains. */ bool crosstask = event->ctx->task && event->ctx->task != current;const u32 max_stack = event->attr.sample_max_stack;
Signature · 1 line
2.50.1
[tip: perf/core] perf: Skip user unwind if the task is a kernel thread
The following commit has been merged into the perf/core branch of tip:
The following commit has been merged into the perf/core branch of tip:
Commit-ID: 16ed389227651330879e17bd83d43bd234006722 Gitweb: https://git.kernel.org/tip/16ed389227651330879e17bd83d43bd234006722 Author: Josh Poimboeuf <[email protected]> AuthorDate: Wed, 20 Aug 2025 14:03:43 -04:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Tue, 26 Aug 2025 09:51:13 +02:00
perf: Skip user unwind if the task is a kernel thread
If the task is not a user thread, there's no user stack to unwind.
--- kernel/events/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/events/core.c +2 -1
@@ -8198,7 +8198,8 @@ struct perf_callchain_entry * perf_callchain(struct perf_event *event, struct pt_regs *regs) { bool kernel = !event->attr.exclude_callchain_kernel; -bool user = !event->attr.exclude_callchain_user; +bool user = !event->attr.exclude_callchain_user && + !(current->flags & (PF_KTHREAD |PF_USER_WORKER ));/* Disallow cross-task user callchains. */ bool crosstask = event->ctx->task && event->ctx->task != current;const u32 max_stack = event->attr.sample_max_stack;
Peter Zijlstra
maintainerQuoted 16 lines · Steven Rostedt
This is a resend from: https://lore.kernel.org/linux-trace-kernel/[email protected]/
It cleanly applied on top of the latest tip/perf/core:
448f97fba901("perf: Convertmmap()refcounts torefcount_t")The ongoing work to support sframes[1] in the kernel required a few clean ups to the perf kernel side. Instead of having these changes in the ongoing work, there's no reason they cannot be applied now.
These are just clean ups to the perf code to help simplify the updates that will be made later.
[1] https://lore.kernel.org/linux-trace-kernel/[email protected]
Quoted 8 lines
Josh Poimboeuf (4):
perf: Removeget_perf_callchain()init_nrargument
perf: Haveget_perf_callchain()return NULL if crosstask and user are set
perf: Simplifyget_perf_callchain()user logic
perf: Skip user unwind if the task is a kernel threadSteven Rostedt (1):
perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
Thanks!