Skip to content

Conversation

@kernel-patches-daemon-bpf
Copy link

Pull request for series with
subject: Pass external callchain entry to get_perf_callchain
version: 5
url: https://patchwork.kernel.org/project/netdevbpf/list/?series=1021316

Tao Chen added 3 commits November 9, 2025 08:44
From BPF stack map, we want to ensure that the callchain buffer
will not be overwritten by other preemptive tasks. Peter
suggested provide more flexible stack-sampling APIs, which
can be used in BPF, and we can still use the perf callchain
entry with the help of these APIs. The next patch will modify
the BPF part.

In the future, these APIs will also make it convenient for us to
add stack-sampling kfuncs in the eBPF subsystem, just as Andrii and
Alexei discussed earlier.

Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Tao Chen <chen.dylane@linux.dev>
From BPF side, preemption usually is enabled. Yonghong said, it is
possible that both tasks (at process level) may reach right before
"recursion[rctx]++;". In such cases, both tasks will be able to get
buffer and this is not right.

Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
Signed-off-by: Tao Chen <chen.dylane@linux.dev>
As Alexei noted, get_perf_callchain() return values may be reused
if a task is preempted after the BPF program enters migrate disable
mode. The perf_callchain_entres has a small stack of entries, and
we can reuse it as follows:

1. get the perf callchain entry
2. BPF use...
3. put the perf callchain entry

Signed-off-by: Tao Chen <chen.dylane@linux.dev>
@kernel-patches-daemon-bpf
Copy link
Author

Upstream branch: f8c67d8
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=1021316
version: 5

@kernel-patches-review-bot
Copy link

commit 7c4b90d7813c12316e209f9634a97f3013925faa
Author: Tao Chen <chen.dylane@linux.dev>

perf: Refactor get_perf_callchain

This patch refactors get_perf_callchain() by extracting the
initialization and callchain collection logic into separate functions
to provide more flexible stack-sampling APIs for BPF.

> diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
> index fd1d91017..edd3058e4 100644
> --- a/include/linux/perf_event.h
> +++ b/include/linux/perf_event.h
> @@ -67,6 +67,7 @@ struct perf_callchain_entry_ctx {
>  	u32				nr;
>  	short				contexts;
>  	bool				contexts_maxed;
> +	bool				add_mark;
>  };

[ ... ]

> diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
> index 808c0d7a3..fb1f26be2 100644
> --- a/kernel/events/callchain.c
> +++ b/kernel/events/callchain.c

[ ... ]

> +void __get_perf_callchain_user(struct perf_callchain_entry_ctx *ctx, struct pt_regs *regs)
> +{
> +	int start_entry_idx;
> +
> +	if (!user_mode(regs)) {
> +		if (current->flags & (PF_KTHREAD | PF_USER_WORKER))
> +			return;
> +		regs = task_pt_regs(current);
> +	}
> +
> +	if (ctx->add_mark)
> +		perf_callchain_store_context(ctx, PERF_CONTEXT_USER);
> +
> +	start_entry_idx = ctx->nr;
                          ^^^^^^^^
> +	perf_callchain_user(ctx, regs);
> +	fixup_uretprobe_trampoline_entries(ctx->entry, start_entry_idx);
> +}

Can this break uprobe trampoline fixups? The original code used
entry->nr for start_entry_idx, but the refactored version uses ctx->nr.

These two counters track different things:
- entry->nr counts ALL entries (incremented by both
  perf_callchain_store_context() and perf_callchain_store())
- ctx->nr only counts regular callchain entries (incremented only by
  perf_callchain_store(), not by perf_callchain_store_context())

When add_mark is true, perf_callchain_store_context() increments
entry->nr but not ctx->nr, causing them to become out of sync.

For example, if kernel callchain collection runs first with add_mark
set:

  Initial: ctx->nr = entry->nr = 0

  In __get_perf_callchain_kernel():
    perf_callchain_store_context() stores PERF_CONTEXT_KERNEL marker
      -> entry->nr becomes 1, ctx->nr still 0
    perf_callchain_kernel() stores N kernel frames
      -> entry->nr becomes 1+N, ctx->nr becomes N

  In __get_perf_callchain_user():
    perf_callchain_store_context() stores PERF_CONTEXT_USER marker
      -> entry->nr becomes 2+N, ctx->nr still N
    start_entry_idx = ctx->nr assigns N (should be 2+N)
    fixup_uretprobe_trampoline_entries() scans from wrong index

This causes fixup_uretprobe_trampoline_entries() to scan kernel
callchain entries instead of user callchain entries, missing the
uretprobe trampolines that need to be fixed up.

Should this use ctx->entry->nr instead of ctx->nr?



AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

In-Reply-To-Subject: perf: Refactor get_perf_callchain
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/19211481431

@kernel-patches-daemon-bpf
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant