* Re: [PATCH] tracing: remove __printf() attribute on __ftrace_vbprintk()
From: Arnd Bergmann @ 2026-02-03 15:56 UTC (permalink / raw)
To: Andy Shevchenko, kernel test robot
Cc: Arnd Bergmann, Steven Rostedt, Masami Hiramatsu, Simon Horman,
Jeff Layton, Anna Schumaker, Chuck Lever, llvm, oe-kbuild-all,
Mathieu Desnoyers, Andrew Morton, Linux Memory Management List,
Randy Dunlap, Yury Norov, Joel Fernandes, linux-kernel,
linux-trace-kernel
In-Reply-To: <aYINAPJS9zXlUGCw@smile.fi.intel.com>
On Tue, Feb 3, 2026, at 15:58, Andy Shevchenko wrote:
> On Tue, Feb 03, 2026 at 08:12:57PM +0800, kernel test robot wrote:
>
>> kernel test robot noticed the following build warnings:
>
> Yeah, you need to go for the full stack of these calls and mark the
> bottom one with __diag() to avoid these warnings. That's my understanding
> and what BPF people required. Chasing this one-by-one would produce
> unneeded churn.
From what I can tell, I can just move the printf attribute
to the __ftrace_vbprintk() definition to make this bit work.
I'll send an updated patch:
--- a/kernel/trace/trace_printk.c
+++ b/kernel/trace/trace_printk.c
@@ -197,6 +197,7 @@ struct notifier_block module_trace_bprintk_format_nb = {
.notifier_call = module_trace_bprintk_format_notify,
};
+__printf(2, 3)
int __trace_bprintk(unsigned long ip, const char *fmt, ...)
{
int ret;
There are unrelated warnings for BPF that I managed to
shut up the same way, doing
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index b54ec0e945aa..45d026fc4e8a 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -1046,6 +1046,7 @@ int bpf_bprintf_prepare(const char *fmt, u32 fmt_size, const u64 *raw_args,
return err;
}
+__printf(3, 0)
BPF_CALL_5(bpf_snprintf, char *, str, u32, str_size, char *, fmt,
const void *, args, u32, data_len)
{
diff --git a/kernel/bpf/stream.c b/kernel/bpf/stream.c
index 24730df55e69..816fd7fba3d2 100644
--- a/kernel/bpf/stream.c
+++ b/kernel/bpf/stream.c
@@ -212,6 +212,7 @@ __bpf_kfunc_start_defs();
* Avoid using enum bpf_stream_id so that kfunc users don't have to pull in the
* enum in headers.
*/
+__printf(2, 0)
__bpf_kfunc int bpf_stream_vprintk(int stream_id, const char *fmt__str, const void *args,
u32 len__sz, struct bpf_prog_aux *aux)
{
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index eadaef8592a3..2d3de71ab86a 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -359,6 +359,7 @@ static const struct bpf_func_proto bpf_probe_write_user_proto = {
#define MAX_TRACE_PRINTK_VARARGS 3
#define BPF_TRACE_PRINTK_SIZE 1024
+__printf(1, 0)
BPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_size, u64, arg1,
u64, arg2, u64, arg3)
{
@@ -412,6 +413,7 @@ const struct bpf_func_proto *bpf_get_trace_printk_proto(void)
return &bpf_trace_printk_proto;
}
+__printf(1, 0)
BPF_CALL_4(bpf_trace_vprintk, char *, fmt, u32, fmt_size, const void *, args,
u32, data_len)
{
@@ -455,6 +457,7 @@ const struct bpf_func_proto *bpf_get_trace_vprintk_proto(void)
return &bpf_trace_vprintk_proto;
}
+__printf(2, 0)
BPF_CALL_5(bpf_seq_printf, struct seq_file *, m, char *, fmt, u32, fmt_size,
const void *, args, u32, data_len)
{
Since those functions have no callers, the annotation on the
print functions does nothing.
With those added, and a couple of drivers fixed to use the
correct printf attributes, the only remaining one I see is
in samples/trace_events/trace-events-sample.h:
In file included from /home/arnd/arm-soc/include/trace/define_trace.h:132,
from /home/arnd/arm-soc/samples/trace_events/trace-events-sample.h:640,
from /home/arnd/arm-soc/samples/trace_events/trace-events-sample.c:12:
/home/arnd/arm-soc/samples/trace_events/./trace-events-sample.h: In function 'trace_event_get_offsets_foo_bar':
/home/arnd/arm-soc/include/trace/stages/stage5_get_offsets.h:33:31: error: function 'trace_event_get_offsets_foo_bar' might be a candidate for 'gnu_printf' format attribute [-Werror=suggest-attribute=format]
33 | { (void)sizeof(struct _test_no_array_##item *); }
| ^~~~~~~~~~~~~~~
/home/arnd/arm-soc/include/trace/trace_events.h:285:9: note: in definition of macro 'DECLARE_EVENT_CLASS'
285 | tstruct; \
| ^~~~~~~
/home/arnd/arm-soc/include/trace/trace_events.h:43:30: note: in expansion of macro 'PARAMS'
43 | PARAMS(tstruct), \
| ^~~~~~
/home/arnd/arm-soc/samples/trace_events/./trace-events-sample.h:291:1: note: in expansion of macro 'TRACE_EVENT'
291 | TRACE_EVENT(foo_bar,
| ^~~~~~~~~~~
/home/arnd/arm-soc/samples/trace_events/./trace-events-sample.h:299:9: note: in expansion of macro 'TP_STRUCT__entry'
299 | TP_STRUCT__entry(
| ^~~~~~~~~~~~~~~~
/home/arnd/arm-soc/samples/trace_events/./trace-events-sample.h:301:17: note: in expansion of macro '__field'
301 | __field( int, bar )
| ^~~~~~~
/home/arnd/arm-soc/samples/trace_events/./trace-events-sample.h: In function 'do_trace_event_raw_event_foo_bar':
I don't think this is related, but I also don't see an obvious
workaround other than forcing the warning off around that
definition.
Arnd
^ permalink raw reply related
* Re: [RFC bpf-next 01/12] ftrace: Add ftrace_hash_count function
From: Steven Rostedt @ 2026-02-03 15:40 UTC (permalink / raw)
To: Jiri Olsa
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, bpf,
linux-trace-kernel, Martin KaFai Lau, Eduard Zingerman, Song Liu,
Yonghong Song, Menglong Dong
In-Reply-To: <20260203093819.2105105-2-jolsa@kernel.org>
On Tue, 3 Feb 2026 10:38:08 +0100
Jiri Olsa <jolsa@kernel.org> wrote:
> diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
> index 705db0a6d995..6dade0eaee46 100644
> --- a/include/linux/ftrace.h
> +++ b/include/linux/ftrace.h
> @@ -413,6 +413,7 @@ struct ftrace_hash *alloc_ftrace_hash(int size_bits);
> void free_ftrace_hash(struct ftrace_hash *hash);
> struct ftrace_func_entry *add_ftrace_hash_entry_direct(struct ftrace_hash *hash,
> unsigned long ip, unsigned long direct);
> +unsigned long ftrace_hash_count(struct ftrace_hash *hash);
>
> /* The hash used to know what functions callbacks trace */
> struct ftrace_ops_hash {
> diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
> index b12dbd93ae1c..be9e0ac1fd95 100644
> --- a/kernel/trace/ftrace.c
> +++ b/kernel/trace/ftrace.c
> @@ -6284,7 +6284,7 @@ int modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
> }
> EXPORT_SYMBOL_GPL(modify_ftrace_direct);
>
> -static unsigned long hash_count(struct ftrace_hash *hash)
> +unsigned long ftrace_hash_count(struct ftrace_hash *hash)
> {
> return hash ? hash->count : 0;
> }
I think this may make it less likely to inline this function, so let's just
add an external function, and even add a "inline" to the original:
static inline unsigned long hash_count(struct ftrace_hash *hash)
{
return hash ? hash->count : 0;
}
unsigned long ftrace_hash_count(struct ftrace_hash *hash)
{
return hash_count(hash);
}
And don't modify anything else.
-- Steve
^ permalink raw reply
* Re: [PATCH 2/2] tracing: resolve enum names for function arguments via BTF
From: Steven Rostedt @ 2026-02-03 15:17 UTC (permalink / raw)
To: Donglin Peng
Cc: andrii.nakryiko, ast, mhiramat, linux-kernel, Donglin Peng,
linux-trace-kernel, bpf, Eduard Zingerman
In-Reply-To: <CAErzpmvgR7QgUTkcEfYstci9wNfGZBksczbkMv5w0ijoUcsBwg@mail.gmail.com>
On Tue, 3 Feb 2026 21:50:47 +0800
Donglin Peng <dolinux.peng@gmail.com> wrote:
> Testing revealed that sorting within resolve_btfids introduces issues with
> btf__dedup. Therefore, I plan to move the sorting logic directly into
> btf__add_enum_value and btf__add_enum64_value in libbpf, which are
> invoked by pahole. However, it means that we need a newer pahole
> version.
Sorting isn't a requirement just something I wanted to bring up. If it's
too complex and doesn't achieve much benefit then let's not do it.
My worry is because "cat trace" takes quite a long time just reading the
BTF arguments. I'm worried it will just get worse with enums as well.
I have trace-cmd reading BTF now (just haven't officially released it) and
doing an extract and reading the trace.dat file is much faster than reading
the trace file with arguments. I'll need to implement the enum logic too in
libtraceevent.
-- Steve
^ permalink raw reply
* Re: [PATCH] tracing: remove __printf() attribute on __ftrace_vbprintk()
From: Andy Shevchenko @ 2026-02-03 14:58 UTC (permalink / raw)
To: kernel test robot
Cc: Arnd Bergmann, Steven Rostedt, Masami Hiramatsu, Simon Horman,
Jeff Layton, Anna Schumaker, Chuck Lever, llvm, oe-kbuild-all,
Arnd Bergmann, Mathieu Desnoyers, Andrew Morton,
Linux Memory Management List, Randy Dunlap, Yury Norov,
Joel Fernandes, linux-kernel, linux-trace-kernel
In-Reply-To: <202602032036.FQK7gJvV-lkp@intel.com>
On Tue, Feb 03, 2026 at 08:12:57PM +0800, kernel test robot wrote:
> kernel test robot noticed the following build warnings:
Yeah, you need to go for the full stack of these calls and mark the bottom one
with __diag() to avoid these warnings. That's my understanding and what BPF people
required. Chasing this one-by-one would produce unneeded churn.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v2] tracing: Fix funcgraph_exit calltime/rettime offset for 32-bit ARM
From: Steven Rostedt @ 2026-02-03 14:30 UTC (permalink / raw)
To: jempty.liang
Cc: mhiramat, mark.rutland, mathieu.desnoyers, linux-kernel,
linux-trace-kernel
In-Reply-To: <19eab264.7fae.19c22f5d17c.Coremail.imntjempty@163.com>
On Tue, 3 Feb 2026 18:04:21 +0800 (CST)
"jempty.liang" <imntjempty@163.com> wrote:
> > #include "trace_output.h"
> >
> >+/* The alignment of a type when in a structure */
> >+#define ALIGN_STRUCTFIELD(type) ((int)(__alignof__(struct {type b;})))
> >+
> > /* Stub function for events with triggers */
> > static int ftrace_event_register(struct trace_event_call *call,
> > enum trace_reg type, void *data)
> >@@ -88,7 +91,7 @@ static void __always_unused ____ftrace_check_##name(void) \
> > #undef __field_ext
> > #define __field_ext(_type, _item, _filter_type) { \
> > .type = #_type, .name = #_item, \
> >- .size = sizeof(_type), .align = __alignof__(_type), \
> >+ .size = sizeof(_type), .align = ALIGN_STRUCTFIELD(_type), \
> > is_signed_type(_type), .filter_type = _filter_type },
> >
> On the 32-bit ARM platform, when _type is unsigned long long, the resulting align value is 8 instead of the expected 4.
> >
Are you saying this still doesn't work?
That would be an issue because then it would have the same bugs with
generic trace events which uses the same solution.
-- Steve
^ permalink raw reply
* Re: [PATCH 2/2] tracing: resolve enum names for function arguments via BTF
From: Donglin Peng @ 2026-02-03 13:50 UTC (permalink / raw)
To: Steven Rostedt, andrii.nakryiko
Cc: ast, mhiramat, linux-kernel, Donglin Peng, linux-trace-kernel,
bpf, Eduard Zingerman
In-Reply-To: <CAErzpmuFQqT3+7cSjq4HrYj0Bp_qjagJSh313_ePJxs+0QjVFA@mail.gmail.com>
On Tue, Feb 3, 2026 at 10:17 AM Donglin Peng <dolinux.peng@gmail.com> wrote:
>
> On Tue, Feb 3, 2026 at 12:12 AM Steven Rostedt <rostedt@goodmis.org> wrote:
> >
> > On Mon, 2 Feb 2026 19:15:48 +0800
> > Donglin Peng <dolinux.peng@gmail.com> wrote:
> >
> > > @@ -754,6 +755,14 @@ void print_function_args(struct trace_seq *s, unsigned long *args,
> > > break;
> > > case BTF_KIND_ENUM:
> > > trace_seq_printf(s, "%ld", arg);
> > > + for_each_enum(i, t, enump) {
> > > + if (arg == enump->val) {
> > > + trace_seq_printf(s, " [%s]",
> > > + btf_name_by_offset(btf,
> > > + enump->name_off));
> > > + break;
> > > + }
> > > + }
> > > break;
> >
> > I have to ask; how big is that enum list?
>
> Based on local vmlinux analysis (6.18 kernel):
> - 78% enums have vlen ≤ 10
> - 95% enums have vlen ≤ 50
> - Max observed vlen: 349 (extremely rare case)
>
> $ bpftool btf dump file x86_64/vmlinux | grep "^\[" | grep ENUM | grep
> -v "(anon)" | awk -F '[ =]' '{
> for(i=1; i<=NF; i++) {
> if ($i == "vlen") {
> count[$(i+1)]++
> }
> }
> }
> END {
> for (vlen in count) {
> print "vlen=" vlen ": " count[vlen] " times"
> }
> }' | sort -k 2 -n
> vlen=104: 1 times
> vlen=114: 1 times
> vlen=116: 1 times
> vlen=129: 1 times
> vlen=146: 1 times
> vlen=167: 1 times
> vlen=181: 1 times
> vlen=183: 1 times
> vlen=201: 1 times
> vlen=213: 1 times
> vlen=33: 1 times
> vlen=349: 1 times
> vlen=42: 1 times
> vlen=45: 1 times
> vlen=48: 1 times
> vlen=50: 1 times
> vlen=54: 1 times
> vlen=55: 1 times
> vlen=56: 1 times
> vlen=59: 1 times
> vlen=60: 1 times
> vlen=61: 1 times
> vlen=64: 1 times
> vlen=68: 1 times
> vlen=71: 1 times
> vlen=74: 1 times
> vlen=83: 1 times
> vlen=85: 1 times
> vlen=87: 1 times
> vlen=122: 2 times
> vlen=38: 2 times
> vlen=39: 2 times
> vlen=43: 2 times
> vlen=44: 2 times
> vlen=49: 2 times
> vlen=52: 2 times
> vlen=58: 2 times
> vlen=73: 2 times
> vlen=79: 2 times
> vlen=35: 3 times
> vlen=41: 3 times
> vlen=46: 3 times
> vlen=25: 4 times
> vlen=27: 4 times
> vlen=28: 4 times
> vlen=29: 4 times
> vlen=34: 4 times
> vlen=37: 4 times
> vlen=40: 4 times
> vlen=19: 5 times
> vlen=30: 5 times
> vlen=20: 6 times
> vlen=22: 6 times
> vlen=24: 6 times
> vlen=16: 8 times
> vlen=23: 8 times
> vlen=26: 8 times
> vlen=31: 8 times
> vlen=32: 8 times
> vlen=17: 11 times
> vlen=18: 12 times
> vlen=21: 12 times
> vlen=15: 13 times
> vlen=14: 21 times
> vlen=12: 25 times
> vlen=13: 25 times
> vlen=10: 34 times
> vlen=11: 35 times
> vlen=1: 58 times
> vlen=8: 70 times
> vlen=9: 74 times
> vlen=7: 102 times
> vlen=6: 108 times
> vlen=5: 170 times
> vlen=2: 193 times
> vlen=4: 250 times
> vlen=3: 333 times
>
> >
> > Do we really want to do a linear search for every enum we come across?
>
> I think linear search is efficient for typical enum value lists (vlen < 10), I
> also support using binary search where feasible.
>
> >
> > What we could do is for the first time we hit an enum, create an array of
> > enums, sort them, and do a binary search from then on. This could be saved
> > in the tracing code itself (in kernel/trace/trace_btf.c), if BPF doesn't
> > care about it.
>
> I think this approach adds unnecessary complexity. Instead, we could
> leverage btf2btf during the resolve_btfids phase to proactively sort the
> btf_enum entries of enum-type btf_type by their value, enabling efficient
> binary search lookups.
Testing revealed that sorting within resolve_btfids introduces issues with
btf__dedup. Therefore, I plan to move the sorting logic directly into
btf__add_enum_value and btf__add_enum64_value in libbpf, which are
invoked by pahole. However, it means that we need a newer pahole
version.
>
> >
> > -- Steve
^ permalink raw reply
* Re: [PATCH mm-unstable v14 08/16] khugepaged: generalize collapse_huge_page for mTHP collapse
From: Lorenzo Stoakes @ 2026-02-03 13:07 UTC (permalink / raw)
To: Nico Pache
Cc: linux-mm, linux-doc, linux-kernel, linux-trace-kernel, akpm,
david, ziy, baolin.wang, Liam.Howlett, ryan.roberts, dev.jain,
baohua, lance.yang, vbabka, rppt, surenb, mhocko, corbet, rostedt,
mhiramat, mathieu.desnoyers, matthew.brost, joshua.hahnjy,
rakie.kim, byungchul, gourry, ying.huang, apopple, jannh,
pfalcato, jackmanb, hannes, willy, peterx, wangkefeng.wang,
usamaarif642, sunnanyong, vishal.moola, thomas.hellstrom, yang,
kas, aarcange, raquini, anshuman.khandual, catalin.marinas, tiwai,
will, dave.hansen, jack, cl, jglisse, zokeefe, rientjes, rdunlap,
hughd, richard.weiyang
In-Reply-To: <20260122192841.128719-9-npache@redhat.com>
On Thu, Jan 22, 2026 at 12:28:33PM -0700, Nico Pache wrote:
> Pass an order and offset to collapse_huge_page to support collapsing anon
> memory to arbitrary orders within a PMD. order indicates what mTHP size we
> are attempting to collapse to, and offset indicates were in the PMD to
> start the collapse attempt.
>
> For non-PMD collapse we must leave the anon VMA write locked until after
> we collapse the mTHP-- in the PMD case all the pages are isolated, but in
> the mTHP case this is not true, and we must keep the lock to prevent
> changes to the VMA from occurring.
>
> Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
> Tested-by: Baolin Wang <baolin.wang@linux.alibaba.com>
> Signed-off-by: Nico Pache <npache@redhat.com>
> ---
> mm/khugepaged.c | 111 +++++++++++++++++++++++++++++++-----------------
> 1 file changed, 71 insertions(+), 40 deletions(-)
>
> diff --git a/mm/khugepaged.c b/mm/khugepaged.c
> index 9b7e05827749..76cb17243793 100644
> --- a/mm/khugepaged.c
> +++ b/mm/khugepaged.c
> @@ -1151,44 +1151,54 @@ static enum scan_result alloc_charge_folio(struct folio **foliop, struct mm_stru
> return SCAN_SUCCEED;
> }
>
> -static enum scan_result collapse_huge_page(struct mm_struct *mm, unsigned long address,
> - int referenced, int unmapped, struct collapse_control *cc)
> +static enum scan_result collapse_huge_page(struct mm_struct *mm, unsigned long start_addr,
> + int referenced, int unmapped, struct collapse_control *cc,
> + bool *mmap_locked, unsigned int order)
> {
> LIST_HEAD(compound_pagelist);
> pmd_t *pmd, _pmd;
> - pte_t *pte;
> + pte_t *pte = NULL;
> pgtable_t pgtable;
> struct folio *folio;
> spinlock_t *pmd_ptl, *pte_ptl;
> enum scan_result result = SCAN_FAIL;
> struct vm_area_struct *vma;
> struct mmu_notifier_range range;
> + bool anon_vma_locked = false;
> + const unsigned long nr_pages = 1UL << order;
> + const unsigned long pmd_address = start_addr & HPAGE_PMD_MASK;
>
> - VM_BUG_ON(address & ~HPAGE_PMD_MASK);
> + VM_WARN_ON_ONCE(pmd_address & ~HPAGE_PMD_MASK);
>
> /*
> * Before allocating the hugepage, release the mmap_lock read lock.
> * The allocation can take potentially a long time if it involves
> * sync compaction, and we do not need to hold the mmap_lock during
> * that. We will recheck the vma after taking it again in write mode.
> + * If collapsing mTHPs we may have already released the read_lock.
> */
> - mmap_read_unlock(mm);
> + if (*mmap_locked) {
> + mmap_read_unlock(mm);
> + *mmap_locked = false;
> + }
>
> - result = alloc_charge_folio(&folio, mm, cc, HPAGE_PMD_ORDER);
> + result = alloc_charge_folio(&folio, mm, cc, order);
> if (result != SCAN_SUCCEED)
> goto out_nolock;
>
> mmap_read_lock(mm);
> - result = hugepage_vma_revalidate(mm, address, true, &vma, cc,
> - HPAGE_PMD_ORDER);
> + *mmap_locked = true;
> + result = hugepage_vma_revalidate(mm, pmd_address, true, &vma, cc, order);
Why would we use the PMD address here rather than the actual start address?
Also please add /*expect_anon=*/ before the 'true' because it's hard to
understand what that references.
> if (result != SCAN_SUCCEED) {
> mmap_read_unlock(mm);
> + *mmap_locked = false;
> goto out_nolock;
> }
>
> - result = find_pmd_or_thp_or_none(mm, address, &pmd);
> + result = find_pmd_or_thp_or_none(mm, pmd_address, &pmd);
> if (result != SCAN_SUCCEED) {
> mmap_read_unlock(mm);
> + *mmap_locked = false;
> goto out_nolock;
> }
>
> @@ -1198,13 +1208,16 @@ static enum scan_result collapse_huge_page(struct mm_struct *mm, unsigned long a
> * released when it fails. So we jump out_nolock directly in
> * that case. Continuing to collapse causes inconsistency.
> */
> - result = __collapse_huge_page_swapin(mm, vma, address, pmd,
> - referenced, HPAGE_PMD_ORDER);
> - if (result != SCAN_SUCCEED)
> + result = __collapse_huge_page_swapin(mm, vma, start_addr, pmd,
> + referenced, order);
> + if (result != SCAN_SUCCEED) {
> + *mmap_locked = false;
> goto out_nolock;
> + }
> }
>
> mmap_read_unlock(mm);
> + *mmap_locked = false;
> /*
> * Prevent all access to pagetables with the exception of
> * gup_fast later handled by the ptep_clear_flush and the VM
> @@ -1214,20 +1227,20 @@ static enum scan_result collapse_huge_page(struct mm_struct *mm, unsigned long a
> * mmap_lock.
> */
> mmap_write_lock(mm);
> - result = hugepage_vma_revalidate(mm, address, true, &vma, cc,
> - HPAGE_PMD_ORDER);
> + result = hugepage_vma_revalidate(mm, pmd_address, true, &vma, cc, order);
> if (result != SCAN_SUCCEED)
> goto out_up_write;
> /* check if the pmd is still valid */
> vma_start_write(vma);
> - result = check_pmd_still_valid(mm, address, pmd);
> + result = check_pmd_still_valid(mm, pmd_address, pmd);
> if (result != SCAN_SUCCEED)
> goto out_up_write;
>
> anon_vma_lock_write(vma->anon_vma);
> + anon_vma_locked = true;
>
> - mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, mm, address,
> - address + HPAGE_PMD_SIZE);
> + mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, mm, start_addr,
> + start_addr + (PAGE_SIZE << order));
> mmu_notifier_invalidate_range_start(&range);
>
> pmd_ptl = pmd_lock(mm, pmd); /* probably unnecessary */
> @@ -1239,24 +1252,21 @@ static enum scan_result collapse_huge_page(struct mm_struct *mm, unsigned long a
> * Parallel GUP-fast is fine since GUP-fast will back off when
> * it detects PMD is changed.
> */
> - _pmd = pmdp_collapse_flush(vma, address, pmd);
> + _pmd = pmdp_collapse_flush(vma, pmd_address, pmd);
> spin_unlock(pmd_ptl);
> mmu_notifier_invalidate_range_end(&range);
> tlb_remove_table_sync_one();
>
> - pte = pte_offset_map_lock(mm, &_pmd, address, &pte_ptl);
> + pte = pte_offset_map_lock(mm, &_pmd, start_addr, &pte_ptl);
> if (pte) {
> - result = __collapse_huge_page_isolate(vma, address, pte, cc,
> - HPAGE_PMD_ORDER,
> - &compound_pagelist);
> + result = __collapse_huge_page_isolate(vma, start_addr, pte, cc,
> + order, &compound_pagelist);
> spin_unlock(pte_ptl);
> } else {
> result = SCAN_NO_PTE_TABLE;
> }
>
> if (unlikely(result != SCAN_SUCCEED)) {
> - if (pte)
> - pte_unmap(pte);
> spin_lock(pmd_ptl);
> BUG_ON(!pmd_none(*pmd));
> /*
> @@ -1266,21 +1276,21 @@ static enum scan_result collapse_huge_page(struct mm_struct *mm, unsigned long a
> */
> pmd_populate(mm, pmd, pmd_pgtable(_pmd));
> spin_unlock(pmd_ptl);
> - anon_vma_unlock_write(vma->anon_vma);
> goto out_up_write;
> }
>
> /*
> - * All pages are isolated and locked so anon_vma rmap
> - * can't run anymore.
> + * For PMD collapse all pages are isolated and locked so anon_vma
> + * rmap can't run anymore. For mTHP collapse we must hold the lock
> */
> - anon_vma_unlock_write(vma->anon_vma);
> + if (is_pmd_order(order)) {
> + anon_vma_unlock_write(vma->anon_vma);
> + anon_vma_locked = false;
> + }
>
> result = __collapse_huge_page_copy(pte, folio, pmd, _pmd,
> - vma, address, pte_ptl,
> - HPAGE_PMD_ORDER,
> - &compound_pagelist);
> - pte_unmap(pte);
> + vma, start_addr, pte_ptl,
> + order, &compound_pagelist);
> if (unlikely(result != SCAN_SUCCEED))
> goto out_up_write;
>
> @@ -1290,20 +1300,42 @@ static enum scan_result collapse_huge_page(struct mm_struct *mm, unsigned long a
> * write.
> */
> __folio_mark_uptodate(folio);
> - pgtable = pmd_pgtable(_pmd);
> + if (is_pmd_order(order)) { /* PMD collapse */
> + pgtable = pmd_pgtable(_pmd);
>
> - spin_lock(pmd_ptl);
> - BUG_ON(!pmd_none(*pmd));
> - pgtable_trans_huge_deposit(mm, pmd, pgtable);
> - map_anon_folio_pmd_nopf(folio, pmd, vma, address);
> + spin_lock(pmd_ptl);
> + WARN_ON_ONCE(!pmd_none(*pmd));
> + pgtable_trans_huge_deposit(mm, pmd, pgtable);
> + map_anon_folio_pmd_nopf(folio, pmd, vma, pmd_address);
> + } else { /* mTHP collapse */
> + pte_t mthp_pte = mk_pte(folio_page(folio, 0), vma->vm_page_prot);
> +
> + mthp_pte = maybe_mkwrite(pte_mkdirty(mthp_pte), vma);
> + spin_lock(pmd_ptl);
> + WARN_ON_ONCE(!pmd_none(*pmd));
> + folio_ref_add(folio, nr_pages - 1);
> + folio_add_new_anon_rmap(folio, vma, start_addr, RMAP_EXCLUSIVE);
> + folio_add_lru_vma(folio, vma);
> + set_ptes(vma->vm_mm, start_addr, pte, mthp_pte, nr_pages);
> + update_mmu_cache_range(NULL, vma, start_addr, pte, nr_pages);
> +
> + smp_wmb(); /* make PTEs visible before PMD. See pmd_install() */
> + pmd_populate(mm, pmd, pmd_pgtable(_pmd));
I seriously hate this being open-coded, can we separate it out into another
function?
> + }
> spin_unlock(pmd_ptl);
>
> folio = NULL;
>
> result = SCAN_SUCCEED;
> out_up_write:
> + if (anon_vma_locked)
> + anon_vma_unlock_write(vma->anon_vma);
Thanks it's much better tracking this specifically.
The whole damn thing needs refactoring (by this I mean - khugepaged and really
THP in general to be clear :) but it's not your fault.
Could I ask though whether you might help out with some cleanups after this
lands :)
I feel like we all need to do our bit to pay down some technical debt!
> + if (pte)
> + pte_unmap(pte);
> mmap_write_unlock(mm);
> + *mmap_locked = false;
> out_nolock:
> + WARN_ON_ONCE(*mmap_locked);
> if (folio)
> folio_put(folio);
> trace_mm_collapse_huge_page(mm, result == SCAN_SUCCEED, result);
> @@ -1471,9 +1503,8 @@ static enum scan_result collapse_scan_pmd(struct mm_struct *mm,
> pte_unmap_unlock(pte, ptl);
> if (result == SCAN_SUCCEED) {
> result = collapse_huge_page(mm, start_addr, referenced,
> - unmapped, cc);
> - /* collapse_huge_page will return with the mmap_lock released */
> - *mmap_locked = false;
> + unmapped, cc, mmap_locked,
> + HPAGE_PMD_ORDER);
> }
> out:
> trace_mm_khugepaged_scan_pmd(mm, folio, referenced,
> --
> 2.52.0
>
Cheers, Lorenzo
^ permalink raw reply
* Re: [PATCH] tracing: remove __printf() attribute on __ftrace_vbprintk()
From: kernel test robot @ 2026-02-03 12:12 UTC (permalink / raw)
To: Arnd Bergmann, Steven Rostedt, Masami Hiramatsu, Simon Horman,
Jeff Layton, Anna Schumaker, Chuck Lever
Cc: llvm, oe-kbuild-all, Arnd Bergmann, Mathieu Desnoyers,
Andrew Morton, Linux Memory Management List, Andy Shevchenko,
Randy Dunlap, Yury Norov, Joel Fernandes, linux-kernel,
linux-trace-kernel
In-Reply-To: <20260202095834.1328352-1-arnd@kernel.org>
Hi Arnd,
kernel test robot noticed the following build warnings:
[auto build test WARNING on next-20260130]
[cannot apply to trace/for-next linus/master v6.19-rc8 v6.19-rc7 v6.19-rc6 v6.19-rc8]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Arnd-Bergmann/tracing-remove-__printf-attribute-on-__ftrace_vbprintk/20260202-180958
base: next-20260130
patch link: https://lore.kernel.org/r/20260202095834.1328352-1-arnd%40kernel.org
patch subject: [PATCH] tracing: remove __printf() attribute on __ftrace_vbprintk()
config: riscv-allmodconfig (https://download.01.org/0day-ci/archive/20260203/202602032036.FQK7gJvV-lkp@intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 9b8addffa70cee5b2acc5454712d9cf78ce45710)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260203/202602032036.FQK7gJvV-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602032036.FQK7gJvV-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> kernel/trace/trace_printk.c:212:34: warning: diagnostic behavior may be improved by adding the 'format(printf, 2, 3)' attribute to the declaration of '__trace_bprintk' [-Wmissing-format-attribute]
212 | ret = trace_vbprintk(ip, fmt, ap);
| ^
include/linux/trace_printk.h:110:5: note: '__trace_bprintk' declared here
110 | int __trace_bprintk(unsigned long ip, const char *fmt, ...);
| ^
1 warning generated.
vim +212 kernel/trace/trace_printk.c
1ba28e02a18cbd kernel/trace/trace_bprintk.c Lai Jiangshan 2009-03-06 199
48ead02030f849 kernel/trace/trace_printk.c Frederic Weisbecker 2009-03-12 200 int __trace_bprintk(unsigned long ip, const char *fmt, ...)
1427cdf0592368 kernel/trace/trace_bprintk.c Lai Jiangshan 2009-03-06 201 {
769b0441f438c4 kernel/trace/trace_printk.c Frederic Weisbecker 2009-03-06 202 int ret;
769b0441f438c4 kernel/trace/trace_printk.c Frederic Weisbecker 2009-03-06 203 va_list ap;
1427cdf0592368 kernel/trace/trace_bprintk.c Lai Jiangshan 2009-03-06 204
769b0441f438c4 kernel/trace/trace_printk.c Frederic Weisbecker 2009-03-06 205 if (unlikely(!fmt))
769b0441f438c4 kernel/trace/trace_printk.c Frederic Weisbecker 2009-03-06 206 return 0;
769b0441f438c4 kernel/trace/trace_printk.c Frederic Weisbecker 2009-03-06 207
b9f9108cad3998 kernel/trace/trace_printk.c Steven Rostedt (Red Hat 2015-09-29 208) if (!trace_printk_enabled)
769b0441f438c4 kernel/trace/trace_printk.c Frederic Weisbecker 2009-03-06 209 return 0;
769b0441f438c4 kernel/trace/trace_printk.c Frederic Weisbecker 2009-03-06 210
769b0441f438c4 kernel/trace/trace_printk.c Frederic Weisbecker 2009-03-06 211 va_start(ap, fmt);
40ce74f19c2807 kernel/trace/trace_printk.c Steven Rostedt 2009-03-19 @212 ret = trace_vbprintk(ip, fmt, ap);
769b0441f438c4 kernel/trace/trace_printk.c Frederic Weisbecker 2009-03-06 213 va_end(ap);
769b0441f438c4 kernel/trace/trace_printk.c Frederic Weisbecker 2009-03-06 214 return ret;
1427cdf0592368 kernel/trace/trace_bprintk.c Lai Jiangshan 2009-03-06 215 }
48ead02030f849 kernel/trace/trace_printk.c Frederic Weisbecker 2009-03-12 216 EXPORT_SYMBOL_GPL(__trace_bprintk);
1427cdf0592368 kernel/trace/trace_bprintk.c Lai Jiangshan 2009-03-06 217
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH mm-unstable v14 07/16] khugepaged: introduce collapse_max_ptes_none helper function
From: Lorenzo Stoakes @ 2026-02-03 12:08 UTC (permalink / raw)
To: Nico Pache
Cc: linux-mm, linux-doc, linux-kernel, linux-trace-kernel, akpm,
david, ziy, baolin.wang, Liam.Howlett, ryan.roberts, dev.jain,
baohua, lance.yang, vbabka, rppt, surenb, mhocko, corbet, rostedt,
mhiramat, mathieu.desnoyers, matthew.brost, joshua.hahnjy,
rakie.kim, byungchul, gourry, ying.huang, apopple, jannh,
pfalcato, jackmanb, hannes, willy, peterx, wangkefeng.wang,
usamaarif642, sunnanyong, vishal.moola, thomas.hellstrom, yang,
kas, aarcange, raquini, anshuman.khandual, catalin.marinas, tiwai,
will, dave.hansen, jack, cl, jglisse, zokeefe, rientjes, rdunlap,
hughd, richard.weiyang
In-Reply-To: <20260122192841.128719-8-npache@redhat.com>
On Thu, Jan 22, 2026 at 12:28:32PM -0700, Nico Pache wrote:
> The current mechanism for determining mTHP collapse scales the
> khugepaged_max_ptes_none value based on the target order. This
> introduces an undesirable feedback loop, or "creep", when max_ptes_none
> is set to a value greater than HPAGE_PMD_NR / 2.
>
> With this configuration, a successful collapse to order N will populate
> enough pages to satisfy the collapse condition on order N+1 on the next
> scan. This leads to unnecessary work and memory churn.
>
> To fix this issue introduce a helper function that will limit mTHP
> collapse support to two max_ptes_none values, 0 and HPAGE_PMD_NR - 1.
> This effectively supports two modes:
>
> - max_ptes_none=0: never introduce new none-pages for mTHP collapse.
> - max_ptes_none=511 (on 4k pagesz): Always collapse to the highest
> available mTHP order.
>
> This removes the possiblilty of "creep", while not modifying any uAPI
> expectations. A warning will be emitted if any non-supported
> max_ptes_none value is configured with mTHP enabled.
>
> The limits can be ignored by passing full_scan=true, this is useful for
> madvise_collapse (which ignores limits), or in the case of
> collapse_scan_pmd(), allows the full PMD to be scanned when mTHP
> collapse is available.
Thanks, great commit msg!
>
> Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
> Signed-off-by: Nico Pache <npache@redhat.com>
This LGTM in terms of logic, some nits below, with those addressed feel
free to add:
Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cheers, Lorenzo
> ---
> mm/khugepaged.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 42 insertions(+), 1 deletion(-)
>
> diff --git a/mm/khugepaged.c b/mm/khugepaged.c
> index 0f68902edd9a..9b7e05827749 100644
> --- a/mm/khugepaged.c
> +++ b/mm/khugepaged.c
> @@ -460,6 +460,44 @@ void __khugepaged_enter(struct mm_struct *mm)
> wake_up_interruptible(&khugepaged_wait);
> }
>
> +/**
> + * collapse_max_ptes_none - Calculate maximum allowed empty PTEs for collapse
> + * @order: The folio order being collapsed to
> + * @full_scan: Whether this is a full scan (ignore limits)
> + *
> + * For madvise-triggered collapses (full_scan=true), all limits are bypassed
> + * and allow up to HPAGE_PMD_NR - 1 empty PTEs.
> + *
> + * For PMD-sized collapses (order == HPAGE_PMD_ORDER), use the configured
> + * khugepaged_max_ptes_none value.
> + *
> + * For mTHP collapses, we currently only support khugepaged_max_pte_none values
> + * of 0 or (HPAGE_PMD_NR - 1). Any other value will emit a warning and no mTHP
> + * collapse will be attempted
> + *
> + * Return: Maximum number of empty PTEs allowed for the collapse operation
> + */
> +static unsigned int collapse_max_ptes_none(unsigned int order, bool full_scan)
> +{
> + /* ignore max_ptes_none limits */
> + if (full_scan)
> + return HPAGE_PMD_NR - 1;
I wonder if, given we are effectively doing:
const unsigned int nr_pages = collapse_max_ptes_none(order, /*full_scan=*/true);
...
foo(nr_pages);
In places where we ignore limits, whether we would be better off putting
HPAGE_PMD_NR - 1 into a define and just using that in these cases, like:
#define COLLAPSE_MAX_PTES_LIM (HPAGE_PMD_NR - 1)
Then instead doing:
foo(COLLAPSE_MAX_PTES_LIM);
?
Seems somewhat silly to pass in a boolean that makes it return a set value in
cases where you know that should be the case at the outset.
> +
> + if (is_pmd_order(order))
> + return khugepaged_max_ptes_none;
> +
> + /* Zero/non-present collapse disabled. */
> + if (!khugepaged_max_ptes_none)
> + return 0;
> +
> + if (khugepaged_max_ptes_none == HPAGE_PMD_NR - 1)
Having a define for HPAGE_PMD_NR - 1 would also be handy here...
> + return (1 << order) - 1;
> +
> + pr_warn_once("mTHP collapse only supports max_ptes_none values of 0 or %d\n",
> + HPAGE_PMD_NR - 1);
...and here.
Also a MICRO nit here - the function returns unsigned int and thus we
express PTEs in this unit, so maybe use %u rather than %d?
> + return -EINVAL;
> +}
Logic of this function looks correct though!
> +
> void khugepaged_enter_vma(struct vm_area_struct *vma,
> vm_flags_t vm_flags)
> {
> @@ -548,7 +586,10 @@ static enum scan_result __collapse_huge_page_isolate(struct vm_area_struct *vma,
> int none_or_zero = 0, shared = 0, referenced = 0;
> enum scan_result result = SCAN_FAIL;
> const unsigned long nr_pages = 1UL << order;
> - int max_ptes_none = khugepaged_max_ptes_none >> (HPAGE_PMD_ORDER - order);
> + int max_ptes_none = collapse_max_ptes_none(order, !cc->is_khugepaged);
Yeah, the !cc->is_khugepaged is a bit gross here, so as per the above, maybe do:
int max_ptes_none;
if (cc->is_khugepaged)
max_ptes_none = collapse_max_ptes_none(order);
else /* MADV_COLLAPSE is not limited. */
max_ptes_none = COLLAPSE_MAX_PTES_LIM;
> +
> + if (max_ptes_none == -EINVAL)
> + return result;
>
> for (_pte = pte; _pte < pte + nr_pages;
> _pte++, addr += PAGE_SIZE) {
> --
> 2.52.0
>
^ permalink raw reply
* Re: [PATCH mm-unstable v14 03/16] introduce collapse_single_pmd to unify khugepaged and madvise_collapse
From: Lorenzo Stoakes @ 2026-02-03 11:43 UTC (permalink / raw)
To: Nico Pache
Cc: linux-mm, linux-doc, linux-kernel, linux-trace-kernel, akpm,
david, ziy, baolin.wang, Liam.Howlett, ryan.roberts, dev.jain,
baohua, lance.yang, vbabka, rppt, surenb, mhocko, corbet, rostedt,
mhiramat, mathieu.desnoyers, matthew.brost, joshua.hahnjy,
rakie.kim, byungchul, gourry, ying.huang, apopple, jannh,
pfalcato, jackmanb, hannes, willy, peterx, wangkefeng.wang,
usamaarif642, sunnanyong, vishal.moola, thomas.hellstrom, yang,
kas, aarcange, raquini, anshuman.khandual, catalin.marinas, tiwai,
will, dave.hansen, jack, cl, jglisse, zokeefe, rientjes, rdunlap,
hughd, richard.weiyang, David Hildenbrand, shivankg
In-Reply-To: <b824f131-3e51-422c-9e98-044b0a2928a6@redhat.com>
On Wed, Jan 28, 2026 at 09:38:37AM -0700, Nico Pache wrote:
> Hi Andrew,
>
> could you please apply the following fixup to avoid potentially using a stale
> VMA in the new writeback-retry logic for madvise collapse.
>
> Thank you!
> -- Nico
>
> ----8<----
> commit a9ac3b1bfa926dd707ac3a785583f8d7a0579578
> Author: Nico Pache <npache@redhat.com>
> Date: Fri Jan 23 16:32:42 2026 -0700
>
> madvise writeback retry logic fix
>
> Signed-off-by: Nico Pache <npache@redhat.com>
>
> diff --git a/mm/khugepaged.c b/mm/khugepaged.c
> index 59e5a5588d85..2b054f7d9753 100644
> --- a/mm/khugepaged.c
> +++ b/mm/khugepaged.c
> @@ -2418,6 +2418,14 @@ static enum scan_result collapse_single_pmd(unsigned long
> addr,
> mmap_read_unlock(mm);
> *mmap_locked = false;
> result = collapse_scan_file(mm, addr, file, pgoff, cc);
> +
> + if (!cc->is_khugepaged && result == SCAN_PAGE_DIRTY_OR_WRITEBACK &&
> + mapping_can_writeback(file->f_mapping)) {
> + const loff_t lstart = (loff_t)pgoff << PAGE_SHIFT;
> + const loff_t lend = lstart + HPAGE_PMD_SIZE - 1;
> +
> + filemap_write_and_wait_range(file->f_mapping, lstart, lend);
> + }
> fput(file);
>
> if (result != SCAN_PTE_MAPPED_HUGEPAGE)
> @@ -2840,19 +2848,8 @@ int madvise_collapse(struct vm_area_struct *vma, unsigned
> long start,
> *lock_dropped = true;
>
> if (result == SCAN_PAGE_DIRTY_OR_WRITEBACK && !triggered_wb) {
> - struct file *file = get_file(vma->vm_file);
> - pgoff_t pgoff = linear_page_index(vma, addr);
> -
> - if (mapping_can_writeback(file->f_mapping)) {
> - loff_t lstart = (loff_t)pgoff << PAGE_SHIFT;
> - loff_t lend = lstart + HPAGE_PMD_SIZE - 1;
> -
> - filemap_write_and_wait_range(file->f_mapping, lstart, lend);
> - triggered_wb = true;
> - fput(file);
> - goto retry;
> - }
> - fput(file);
> + triggered_wb = true;
> + goto retry;
> }
LGTM, with this in place you can add back my tag to the patch.
It'd be good to reference this in the commit message, but you can do that
on a respin.
So:
Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
^ permalink raw reply
* Re: [PATCH mm-unstable v14 03/16] introduce collapse_single_pmd to unify khugepaged and madvise_collapse
From: Lorenzo Stoakes @ 2026-02-03 11:35 UTC (permalink / raw)
To: Nico Pache
Cc: linux-mm, linux-doc, linux-kernel, linux-trace-kernel, akpm,
david, ziy, baolin.wang, Liam.Howlett, ryan.roberts, dev.jain,
baohua, lance.yang, vbabka, rppt, surenb, mhocko, corbet, rostedt,
mhiramat, mathieu.desnoyers, matthew.brost, joshua.hahnjy,
rakie.kim, byungchul, gourry, ying.huang, apopple, jannh,
pfalcato, jackmanb, hannes, willy, peterx, wangkefeng.wang,
usamaarif642, sunnanyong, vishal.moola, thomas.hellstrom, yang,
kas, aarcange, raquini, anshuman.khandual, catalin.marinas, tiwai,
will, dave.hansen, jack, cl, jglisse, zokeefe, rientjes, rdunlap,
hughd, richard.weiyang, David Hildenbrand
In-Reply-To: <20260122192841.128719-4-npache@redhat.com>
Another trivial point on this one, you're missing the prefix in the subject
here. In general I think better to say mm/khugepaged: rather than
khugepaged: also.
Cheers, Lorenzo
^ permalink raw reply
* Re: [PATCH v5 09/15] sched: Add task enqueue/dequeue trace points
From: Gabriele Monaco @ 2026-02-03 11:06 UTC (permalink / raw)
To: Peter Zijlstra
Cc: K Prateek Nayak, Tomas Glozar, Clark Williams, John Kacur,
linux-kernel, Steven Rostedt, Nam Cao, Juri Lelli, Ingo Molnar,
linux-trace-kernel
In-Reply-To: <20260122155500.362683-10-gmonaco@redhat.com>
Hi Peter,
On Thu, 2026-01-22 at 16:54 +0100, Gabriele Monaco wrote:
> From: Nam Cao <namcao@linutronix.de>
>
> Add trace points into enqueue_task() and dequeue_task().
Can I have an Ack for these tracepoints?
Thanks,
Gabriele
>
> Suggested-by: Peter Zijlstra <peterz@infradead.org>
> Signed-off-by: Nam Cao <namcao@linutronix.de>
> Reviewed-by: K Prateek Nayak <kprateek.nayak@amd.com>
> Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
> ---
>
> Notes:
> V5:
> * Do not fire enqueue tracepoint for delayed enqueues
>
> include/trace/events/sched.h | 13 +++++++++++++
> kernel/sched/core.c | 10 +++++++++-
> kernel/sched/sched.h | 2 ++
> 3 files changed, 24 insertions(+), 1 deletion(-)
>
> diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
> index 366b2e8ec40c..f4e1d3554e3e 100644
> --- a/include/trace/events/sched.h
> +++ b/include/trace/events/sched.h
> @@ -912,6 +912,19 @@ DECLARE_TRACE(sched_dl_server_stop,
> TP_PROTO(struct sched_dl_entity *dl_se, int cpu),
> TP_ARGS(dl_se, cpu));
>
> +/*
> + * The two trace points below may not work as expected for fair tasks due
> + * to delayed dequeue. See:
> + * https://lore.kernel.org/lkml/179674c6-f82a-4718-ace2-67b5e672fdee@amd.com/
> + */
> +DECLARE_TRACE(sched_enqueue,
> + TP_PROTO(struct task_struct *tsk, int cpu),
> + TP_ARGS(tsk, cpu));
> +
> +DECLARE_TRACE(sched_dequeue,
> + TP_PROTO(struct task_struct *tsk, int cpu),
> + TP_ARGS(tsk, cpu));
> +
> #endif /* _TRACE_SCHED_H */
>
> /* This part must be outside protection */
> diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> index f6293fa02fb7..c885d7885172 100644
> --- a/kernel/sched/core.c
> +++ b/kernel/sched/core.c
> @@ -2087,6 +2087,9 @@ unsigned long get_wchan(struct task_struct *p)
>
> void enqueue_task(struct rq *rq, struct task_struct *p, int flags)
> {
> + if (trace_sched_enqueue_tp_enabled() && !(flags & ENQUEUE_DELAYED))
> + trace_sched_enqueue_tp(p, rq->cpu);
> +
> if (!(flags & ENQUEUE_NOCLOCK))
> update_rq_clock(rq);
>
> @@ -2114,6 +2117,8 @@ void enqueue_task(struct rq *rq, struct task_struct *p,
> int flags)
> */
> inline bool dequeue_task(struct rq *rq, struct task_struct *p, int flags)
> {
> + int ret;
> +
> if (sched_core_enabled(rq))
> sched_core_dequeue(rq, p, flags);
>
> @@ -2131,7 +2136,10 @@ inline bool dequeue_task(struct rq *rq, struct
> task_struct *p, int flags)
> */
> uclamp_rq_dec(rq, p);
> rq->queue_mask |= p->sched_class->queue_mask;
> - return p->sched_class->dequeue_task(rq, p, flags);
> + ret = p->sched_class->dequeue_task(rq, p, flags);
> + if (trace_sched_dequeue_tp_enabled() && !(flags & DEQUEUE_SLEEP))
> + trace_sched_dequeue_tp(p, rq->cpu);
> + return ret;
> }
>
> void activate_task(struct rq *rq, struct task_struct *p, int flags)
> diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
> index e885a935b716..8465472b40fa 100644
> --- a/kernel/sched/sched.h
> +++ b/kernel/sched/sched.h
> @@ -2918,6 +2918,8 @@ static inline void sub_nr_running(struct rq *rq,
> unsigned count)
>
> static inline void __block_task(struct rq *rq, struct task_struct *p)
> {
> + trace_sched_dequeue_tp(p, rq->cpu);
> +
> if (p->sched_contributes_to_load)
> rq->nr_uninterruptible++;
>
^ permalink raw reply
* Re: [PATCH v5] stm: class: Add MIPI OST protocol support
From: Alexander Shishkin @ 2026-02-03 10:26 UTC (permalink / raw)
To: Yingchao Deng (Consultant), Yingchao Deng, Steven Rostedt,
Masami Hiramatsu, Mathieu Desnoyers, Jonathan Corbet,
Maxime Coquelin, Alexandre Torgue
Cc: linux-kernel, linux-trace-kernel, linux-doc, linux-arm-kernel,
Tingwei Zhang, Yuanfang Zhang, Jinlong Mao, alexander.shishkin
In-Reply-To: <dac5b6f0-5d0d-4dcd-b615-cdf9b81f4bf6@quicinc.com>
"Yingchao Deng (Consultant)" <quic_yingdeng@quicinc.com> writes:
> On 1/30/2026 5:48 PM, Alexander Shishkin wrote:
>> Yingchao Deng<yingchao.deng@oss.qualcomm.com> writes:
>>
>>> + for (i = 1; i < ARRAY_SIZE(str_ost_entity_type); i++) {
>>> + if (i == pn->entity_type)
>>> + sz += sysfs_emit_at(page, sz, "[%s] ", str_ost_entity_type[i]);
>>> + else
>>> + sz += sysfs_emit_at(page, sz, "%s ", str_ost_entity_type[i]);
>>> + }
>> Greg hates this. Documentation [0] says "preferably": "Attributes should
>> be ASCII text files, preferably with only one value per file.", but
>> somebody will get yelled at if this gets spotted, and since it's
>> probably going to be me, let's maybe not do this.
> Using two sysfs nodes, entity_available (listing supported options)
> and entity (the current value), is this acceptable?
My apologies, I didn't see that this was a configfs attribute (as it
should be).
Having said that, these ost types are almost enum stm_source_type. The
console is missing, but there is already a console source, so adding it
to the enum and the making the console source driver type that makes
sense. And once you have that, you'll get the entity type in your
ost_write() method via the @source parameter. Then, you'll only need a
tiny lookup table that maps enum stm_source_type to OST_ENTITY_* and use
that in the encoded packet.
This leaves the question of OST_ENTITY_TYPE_NONE and
OST_ENTITY_TYPE_DIAG. They are both unclear to me. OST_ENTITY_TYPE_NONE
basically means "no type, reject write", meaning that type 0 in an OST
packet is invalid, which seems weird and wasteful, is that what the
protocol spec says?
OST_ENTITY_TYPE_DIAG is also not explained; since we're already in the
tracing territory, "diag" may mean anything at all. From its value being
at the upper end of the 8-bit spectrum, I'm guessing it either something
very specialized or something very generic. Can it be a catch-all for
STM_USER (which is a catch-all)? Alternatively, you could propagate the
matched policy node's name to the pdrv->write() and in ost_write() check
if it's "diag" to select this type. strncmp() in pdrv->write() is not
ideal, though.
Either way, no extra attribute needed.
Because,
# mkdir diag ftrace console
# echo diag > diag/entity
# echo ftrace > ftrace/entity
# echo console > console/entity
is really a hat on a hat.
Would something like this work for you?
Thanks,
--
Alex
^ permalink raw reply
* Re: [RFC PATCH v1 05/37] KVM: guest_memfd: Wire up kvm_get_memory_attributes() to per-gmem attributes
From: Xu Yilun @ 2026-02-03 9:56 UTC (permalink / raw)
To: Sean Christopherson
Cc: Jason Gunthorpe, Ackerley Tng, Alexey Kardashevskiy, cgroups, kvm,
linux-doc, linux-fsdevel, linux-kernel, linux-kselftest, linux-mm,
linux-trace-kernel, x86, akpm, binbin.wu, bp, brauner,
chao.p.peng, chenhuacai, corbet, dave.hansen, dave.hansen, david,
dmatlack, erdemaktas, fan.du, fvdl, haibo1.xu, hannes, hch, hpa,
hughd, ira.weiny, isaku.yamahata, jack, james.morse, jarkko,
jgowans, jhubbard, jroedel, jthoughton, jun.miao, kai.huang,
keirf, kent.overstreet, liam.merwick, maciej.wieczor-retman, mail,
maobibo, mathieu.desnoyers, maz, mhiramat, mhocko, mic,
michael.roth, mingo, mlevitsk, mpe, muchun.song, nikunj, nsaenz,
oliver.upton, palmer, pankaj.gupta, paul.walmsley, pbonzini,
peterx, pgonda, prsampat, pvorel, qperret, richard.weiyang,
rick.p.edgecombe, rientjes, rostedt, roypat, rppt, shakeel.butt,
shuah, steven.price, steven.sistare, suzuki.poulose, tabba, tglx,
thomas.lendacky, vannapurve, vbabka, viro, vkuznets, wei.w.wang,
will, willy, wyihan, xiaoyao.li, yan.y.zhao, yilun.xu, yuzenghui,
zhiquan1.li
In-Reply-To: <aXqx3_eE0rNh6nP0@google.com>
> +1. For guest_memfd, we initially defined per-VM memory attributes to track
> private vs. shared. But as Ackerley noted, we are in the process of deprecating
> that support, e.g. by making it incompatible with various guest_memfd features,
> in favor of having each guest_memfd instance track the state of a given page.
>
> The original guest_memfd design was that it would _only_ hold private pages, and
> so tracking private vs. shared in guest_memfd didn't make any sense. As we've
> pivoted to in-place conversion, tracking private vs. shared in the guest_memfd
> has basically become mandatory. We could maaaaaybe make it work with per-VM
> attributes, but it would be insanely complex.
>
> For a dmabuf fd, the story is the same as guest_memfd. Unless private vs. shared
> is all or nothing, and can never change, then the only entity that can track that
> info is the owner of the dmabuf. And even if the private vs. shared attributes
> are constant, tracking it external to KVM makes sense, because then the provider
> can simply hardcode %true/%false.
For CoCo-VM and Tee-IO, I'm wondering if host or KVM has to maintain
the private/shared attribute for "assigned MMIO". I'm not naming them
"host MMIO" cause unlike RAM host never needs to access them, either in
private manner or shared manner.
Traditionally, host maps these MMIOs only because KVM needs HVA->HPA
mapping to find pfn and setup KVM MMU. Now we have FD based approach so
with dmabuf fd, host no longer needs mapping. Does that give confidence
that KVM only needs to setup MMU for this type of MMIO as private/shared
according to guest's intension (which is fault->is_private)?
We don't need to track private/shared in VFIO MMIO dmabuf, only to keep
them unmappable.
>
> As for _how_ to do that, no matter where the attributes are stored, we're going
> to have to teach KVM to play nice with a non-guest_memfd provider of private
> memory.
>
^ permalink raw reply
* Re: [RFC bpf-next 09/12] libbpf: Add support to create tracing multi link
From: bot+bpf-ci @ 2026-02-03 10:14 UTC (permalink / raw)
To: jolsa, ast, daniel, andrii
Cc: bpf, linux-trace-kernel, kafai, eddyz87, songliubraving, yhs,
menglong8.dong, rostedt, ast, andrii, daniel, martin.lau, eddyz87,
yonghong.song, clm, ihor.solodrai
In-Reply-To: <20260203093819.2105105-10-jolsa@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 4183 bytes --]
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index 0c8bf0b5c..a16243300 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
[ ... ]
> +struct bpf_link *
> +bpf_program__attach_tracing_multi(const struct bpf_program *prog, const char *pattern,
> + const struct bpf_tracing_multi_opts *opts)
> +{
> + LIBBPF_OPTS(bpf_link_create_opts, lopts);
> + __u32 *btf_ids, cnt, *free_ids = NULL;
> + int prog_fd, link_fd, err;
> + struct bpf_link *link;
> +
> + btf_ids = OPTS_GET(opts, btf_ids, false);
> + cnt = OPTS_GET(opts, cnt, false);
> +
> + if (!pattern && !btf_ids && !cnt)
> + return libbpf_err_ptr(-EINVAL);
> + if (pattern && (btf_ids || cnt))
> + return libbpf_err_ptr(-EINVAL);
> +
> + if (pattern) {
> + err = bpf_object__load_vmlinux_btf(prog->obj, true);
> + if (err)
> + return libbpf_err_ptr(err);
> +
> + cnt = btf__find_by_glob_kind(prog->obj->btf_vmlinux, BTF_KIND_FUNC,
> + pattern, NULL, &btf_ids);
> + if (cnt <= 0)
> + return libbpf_err_ptr(-EINVAL);
> + free_ids = btf_ids;
> + }
> +
> + lopts.tracing_multi.btf_ids = btf_ids;
> + lopts.tracing_multi.btf_ids_cnt = cnt;
> +
> + link = calloc(1, sizeof(*link));
> + if (!link)
> + return libbpf_err_ptr(-ENOMEM);
If calloc fails here and pattern was provided, btf__find_by_glob_kind() will
have allocated btf_ids (tracked by free_ids). Does this leak free_ids? The
error label below frees it properly, but this return bypasses that path.
Something like:
if (!link) {
free(free_ids);
return libbpf_err_ptr(-ENOMEM);
}
or using goto error would fix this.
> + link->detach = &bpf_link__detach_fd;
> +
> + prog_fd = bpf_program__fd(prog);
> + link_fd = bpf_link_create(prog_fd, 0, prog->expected_attach_type, &lopts);
> + if (link_fd < 0) {
> + err = -errno;
> + pr_warn("prog '%s': failed to attach: %s\n", prog->name, errstr(err));
> + goto error;
> + }
> + link->fd = link_fd;
> + free(free_ids);
> + return link;
> +error:
> + free(link);
> + free(free_ids);
> + return libbpf_err_ptr(err);
> +}
> +
> +static int attach_tracing_multi(const struct bpf_program *prog, long cookie, struct bpf_link **link)
> +{
> + const char *spec;
> + char *pattern;
> + bool is_fexit;
> + int n;
> +
> + /* no auto-attach for SEC("fentry.multi") and SEC("fexit.multi") */
> + if (strcmp(prog->sec_name, "fentry.multi") == 0 ||
> + strcmp(prog->sec_name, "fexit.multi") == 0)
> + return 0;
> +
> + is_fexit = str_has_pfx(prog->sec_name, "fexit.multi/");
> + if (is_fexit)
> + spec = prog->sec_name + sizeof("fexit.multi/") - 1;
> + else
> + spec = prog->sec_name + sizeof("fentry.multi/") - 1;
> +
> + n = sscanf(spec, "%m[a-zA-Z0-9_.*?]", &pattern);
> + if (n < 1) {
> + pr_warn("tracing multi pattern is invalid: %s\n", pattern);
When sscanf fails to match (n < 1), pattern is never assigned because %m only
allocates on successful match. Should this print spec instead of the
uninitialized pattern? Compare with attach_kprobe_multi() which uses:
pr_warn("kprobe multi pattern is invalid: %s\n", spec);
> + return -EINVAL;
> + }
> +
> + *link = bpf_program__attach_tracing_multi(prog, pattern, NULL);
> + return libbpf_get_error(*link);
Is pattern being leaked here? sscanf with %m allocates the string, but there
is no free(pattern) before returning. Compare with attach_kprobe_multi():
*link = bpf_program__attach_kprobe_multi_opts(prog, pattern, &opts);
free(pattern);
return libbpf_get_error(*link);
> +}
---
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
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/21625440628
AI-authorship-score: low
AI-authorship-explanation: The commit contains typical human copy-paste errors (forgetting to add free(), using wrong variable in error message) and a minor grammatical mistake, suggesting human authorship.
issues-found: 3
issue-severity-score: medium
issue-severity-explanation: Memory leaks on every use of fentry.multi/fexit.multi auto-attach and potential undefined behavior from using uninitialized variable in error path.
^ permalink raw reply
* Re: [RFC bpf-next 06/12] bpf: Add bpf_trampoline_multi_attach/detach functions
From: bot+bpf-ci @ 2026-02-03 10:14 UTC (permalink / raw)
To: jolsa, ast, daniel, andrii
Cc: bpf, linux-trace-kernel, kafai, eddyz87, songliubraving, yhs,
menglong8.dong, rostedt, ast, andrii, daniel, martin.lau, eddyz87,
yonghong.song, clm, ihor.solodrai
In-Reply-To: <20260203093819.2105105-7-jolsa@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 2453 bytes --]
> diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
> index 2be2f1d0b..b76bb5450 100644
> --- a/kernel/bpf/trampoline.c
> +++ b/kernel/bpf/trampoline.c
[ ... ]
> +int bpf_trampoline_multi_attach(struct bpf_prog *prog, u32 *ids,
> + struct bpf_tracing_multi_link *link)
> +{
> + struct bpf_attach_target_info tgt_info = {};
> + struct bpf_tracing_multi_node *mnode;
> + int j, i, err, cnt = link->nodes_cnt;
> + struct fentry_multi_data data = {};
> + struct bpf_trampoline *tr;
> + u64 key;
> +
> + data.reg = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS);
> + if (!data.reg)
> + return -ENOMEM;
> +
> + data.modify = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS);
> + if (!data.modify) {
> + free_ftrace_hash(data.reg);
> + return -ENOMEM;
> + }
> +
> + for (i = 0; i < cnt; i++) {
> + mnode = &link->nodes[i];
> + err = bpf_check_attach_target(NULL, prog, NULL, ids[i], &tgt_info);
> + if (err)
> + goto rollback_put;
> +
> + key = bpf_trampoline_compute_key(NULL, prog->aux->attach_btf, ids[i]);
> +
> + tr = bpf_trampoline_get(key, &tgt_info);
> + if (!tr)
> + goto rollback_put;
When bpf_trampoline_get() returns NULL here, the code jumps to
rollback_put without setting err. If bpf_check_attach_target() succeeded
on this iteration (setting err to 0), the function will return 0 instead
of an error code.
Should this be something like:
tr = bpf_trampoline_get(key, &tgt_info);
if (!tr) {
err = -ENOMEM;
goto rollback_put;
}
> +
> + mnode->trampoline = tr;
> + mnode->node.prog = prog;
> + }
[ ... ]
> +rollback_put:
> + for (j = 0; j < i; j++) {
> + mnode = &link->nodes[j];
> + bpf_trampoline_put(mnode->trampoline);
> + }
> +
> + free_fentry_multi_data(&data);
> + return err;
> +}
---
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
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/21625440628
AI-authorship-score: low
AI-authorship-explanation: The code follows established kernel patterns and contains a human-typical oversight error (missing error assignment); the commit message has a minor copy-paste error typical of human editing.
issues-found: 1
issue-severity-score: low
issue-severity-explanation: Missing error code when bpf_trampoline_get fails causes silent failure under memory pressure, but does not cause crashes or data corruption.
^ permalink raw reply
* Re: [RFC bpf-next 08/12] libbpf: Add btf__find_by_glob_kind function
From: bot+bpf-ci @ 2026-02-03 10:14 UTC (permalink / raw)
To: jolsa, ast, daniel, andrii
Cc: bpf, linux-trace-kernel, kafai, eddyz87, songliubraving, yhs,
menglong8.dong, rostedt, ast, andrii, daniel, martin.lau, eddyz87,
yonghong.song, clm, ihor.solodrai
In-Reply-To: <20260203093819.2105105-9-jolsa@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 2764 bytes --]
> diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
> index 83fe79ffc..64502b3ef 100644
> --- a/tools/lib/bpf/btf.c
> +++ b/tools/lib/bpf/btf.c
[ ... ]
> +int btf__find_by_glob_kind(const struct btf *btf, __u32 kind,
> + const char *allow_pattern, const char *deny_pattern,
> + __u32 **__ids)
> +{
> + __u32 i, nr_types = btf__type_cnt(btf);
> + int cnt = 0, alloc = 0;
> + __u32 *ids = NULL;
> +
> + for (i = 1; i < nr_types; i++) {
> + const struct btf_type *t = btf__type_by_id(btf, i);
> + const char *name;
> + __u32 *p;
> +
> + if (btf_kind(t) != kind)
> + continue;
> + name = btf__name_by_offset(btf, t->name_off);
> + if (!name)
> + continue;
> +
> + if (deny_pattern && glob_match(name, deny_pattern))
> + continue;
> + if (allow_pattern && !glob_match(name, allow_pattern))
> + continue;
> +
> + if (cnt == alloc) {
> + alloc = max(16, alloc * 3 / 2);
> + p = libbpf_reallocarray(ids, alloc, sizeof(__u32));
> + if (!p) {
> + free(ids);
> + return -ENOMEM;
Should this use libbpf_err(-ENOMEM) to set errno for userspace callers?
Other similar functions in btf.c like btf_find_by_name_kind() use
libbpf_err() for their error returns:
return libbpf_err(-ENOENT);
> + }
> + ids = p;
> + }
> + ids[cnt] = i;
> + cnt++;
> + }
> +
> + *__ids = ids;
> + return cnt;
> +}
> diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h
> index b30008c26..d7b47bb0b 100644
> --- a/tools/lib/bpf/btf.h
> +++ b/tools/lib/bpf/btf.h
[ ... ]
> +int btf__find_by_glob_kind(const struct btf *btf, __u32 kind,
> + const char *allow_pattern, const char *deny_pattern,
> + __u32 **__ids);
Is this intended to be a public API? The btf__ prefix and placement in btf.h
suggest it should be public, but it is missing:
1) The LIBBPF_API macro that all other btf__* functions in this header have,
for example:
LIBBPF_API __s32 btf__find_by_name_kind(const struct btf *btf,
const char *type_name, __u32 kind);
2) An entry in libbpf.map to export the symbol from the shared library.
---
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
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/21625440628
AI-authorship-score: low
AI-authorship-explanation: The code and commit message follow established kernel and libbpf conventions without telltale signs of AI generation, and Jiri Olsa is a well-known BPF kernel maintainer.
issues-found: 2
issue-severity-score: low
issue-severity-explanation: Missing libbpf_err wrapper and incomplete public API declaration are API consistency issues that do not cause crashes or security problems.
^ permalink raw reply
* Re: [RFC bpf-next 07/12] bpf: Add support to create tracing multi link
From: bot+bpf-ci @ 2026-02-03 10:13 UTC (permalink / raw)
To: jolsa, ast, daniel, andrii
Cc: bpf, linux-trace-kernel, kafai, eddyz87, songliubraving, yhs,
menglong8.dong, rostedt, ast, andrii, daniel, martin.lau, eddyz87,
yonghong.song, clm, ihor.solodrai
In-Reply-To: <20260203093819.2105105-8-jolsa@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 3355 bytes --]
> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
> index 68600972a..010785246 100644
> --- a/include/uapi/linux/bpf.h
> +++ b/include/uapi/linux/bpf.h
[ ... ]
> @@ -1863,6 +1864,10 @@ union bpf_attr {
> };
> __u64 expected_revision;
> } cgroup;
> + struct {
> + __aligned_u64 btf_ids; /* addresses to attach */
> + __u32 btf_ids_cnt; /* addresses count */
> + } tracing_multi;
The comments say "addresses to attach" and "addresses count", but the field is
named btf_ids and contains BTF type IDs, not addresses. Should these comments
say "BTF IDs to attach" and "BTF IDs count" instead?
> diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
> index f7baeb827..82e625aa0 100644
> --- a/kernel/trace/bpf_trace.c
> +++ b/kernel/trace/bpf_trace.c
[ ... ]
> +static void bpf_tracing_multi_link_show_fdinfo(const struct bpf_link *link,
> + struct seq_file *seq)
> +{
> + struct bpf_tracing_multi_link *tr_link =
> + container_of(link, struct bpf_tracing_multi_link, link);
> +
> + seq_printf(seq, "attach_type:\t%d\n", tr_link->attach_type);
> +}
> +
> +static int bpf_tracing_multi_link_fill_link_info(const struct bpf_link *link,
> + struct bpf_link_info *info)
> +{
> + struct bpf_tracing_multi_link *tr_link =
> + container_of(link, struct bpf_tracing_multi_link, link);
> +
> + info->tracing.attach_type = tr_link->attach_type;
> + return 0;
> +}
Both functions above use tr_link->attach_type, but looking at
bpf_tracing_multi_attach() below, this field is never initialized:
> +int bpf_tracing_multi_attach(struct bpf_prog *prog, const union bpf_attr *attr)
> +{
[ ... ]
> + link = kzalloc(struct_size(link, nodes, cnt), GFP_KERNEL);
> + if (!link) {
> + err = -ENOMEM;
> + goto error;
> + }
> +
> + link->nodes_cnt = cnt;
> +
> + bpf_link_init(&link->link, BPF_LINK_TYPE_TRACING_MULTI,
> + &bpf_tracing_multi_link_lops, prog, prog->expected_attach_type);
bpf_link_init() sets link->link.attach_type (inside the embedded struct bpf_link),
but struct bpf_tracing_multi_link has a separate attach_type field that remains
zero-initialized from kzalloc.
The show_fdinfo and fill_link_info callbacks read tr_link->attach_type which
will always be 0 (BPF_CGROUP_INET_INGRESS) instead of the actual attach type
(BPF_TRACE_FENTRY_MULTI or BPF_TRACE_FEXIT_MULTI).
Looking at the existing bpf_tracing_link_show_fdinfo() and
bpf_tracing_link_fill_link_info() in kernel/bpf/syscall.c, they use
link->attach_type (the inner struct's field). Should tr_link->attach_type
either be removed and link->attach_type used instead, or should it be
explicitly initialized to prog->expected_attach_type?
---
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
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/21625440628
AI-authorship-score: low
AI-authorship-explanation: Code style and structure are consistent with established kernel BPF patterns, with typical kernel author conventions in commit message and implementation.
issues-found: 2
issue-severity-score: medium
issue-severity-explanation: Uninitialized attach_type field causes wrong data to be returned to userspace via fdinfo and bpf_link_info, affecting observability but not causing crashes.
^ permalink raw reply
* Re: [RFC bpf-next 12/12] selftests/bpf: Add tracing multi benchmark test
From: bot+bpf-ci @ 2026-02-03 10:13 UTC (permalink / raw)
To: jolsa, ast, daniel, andrii
Cc: bpf, linux-trace-kernel, kafai, eddyz87, songliubraving, yhs,
menglong8.dong, rostedt, ast, andrii, daniel, martin.lau, eddyz87,
yonghong.song, clm, ihor.solodrai
In-Reply-To: <20260203093819.2105105-13-jolsa@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 1485 bytes --]
> diff --git a/tools/testing/selftests/bpf/prog_tests/tracing_multi.c b/tools/testing/selftests/bpf/prog_tests/tracing_multi.c
> index 3ccf0d4ed..575454e31 100644
> --- a/tools/testing/selftests/bpf/prog_tests/tracing_multi.c
> +++ b/tools/testing/selftests/bpf/prog_tests/tracing_multi.c
> @@ -6,6 +6,9 @@
> #include <bpf/btf.h>
> #include <linux/btf.h>
> #include <search.h>
> +#include <bpf/btf.h>
> +#include <linux/btf.h>
> +#include <search.h>
These three includes are duplicates of the lines immediately above them.
Were they added by mistake?
[ ... ]
> + t = btf__type_by_id(btf, proto->type);
> + while (t && btf_type_is_modifier(t))
> + t = btf__type_by_id(btf, t->type);
The while line uses spaces for indentation instead of a tab.
---
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
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/21625440628
AI-authorship-score: low
AI-authorship-explanation: The commit shows characteristics typical of human-written code including copy-paste errors (duplicate includes), inconsistent whitespace, informal commit message language, and practical iterative testing with real measured results.
issues-found: 2
issue-severity-score: low
issue-severity-explanation: Both issues are minor code quality problems in test code: duplicate header includes and inconsistent whitespace (spaces vs tabs).
^ permalink raw reply
* Re: [RFC bpf-next 10/12] selftests/bpf: Add fentry tracing multi func test
From: bot+bpf-ci @ 2026-02-03 10:13 UTC (permalink / raw)
To: jolsa, ast, daniel, andrii
Cc: bpf, linux-trace-kernel, kafai, eddyz87, songliubraving, yhs,
menglong8.dong, rostedt, ast, andrii, daniel, martin.lau, eddyz87,
yonghong.song, clm, ihor.solodrai
In-Reply-To: <20260203093819.2105105-11-jolsa@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 1732 bytes --]
> diff --git a/tools/testing/selftests/bpf/progs/tracing_multi_check.c b/tools/testing/selftests/bpf/progs/tracing_multi_check.c
> new file mode 100644
> index 000000000..e5efa9884
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/progs/tracing_multi_check.c
[ ... ]
> + } else if (ip == &bpf_fentry_test3) {
> + char a, b;
^
The commit message states "We need to cast to real arguments types in
multi_arg_check, because the checked value can be shorter than u64."
Should variable b be declared as int instead of char?
The kernel function signature is:
noinline int bpf_fentry_test3(char a, int b, u64 c)
The second parameter is int, not char. While the test passes with the
current test value of 5, this appears inconsistent with the stated goal
of matching argument types.
> + __u64 c;
[ ... ]
> + } else if (ip == &bpf_fentry_test6) {
[ ... ]
> + e = (void*) value;;
> + if (bpf_get_func_arg(ctx, 5, &value))
> + return;
> + f = value;;
^^
This isn't a bug, but there are extra semicolons on these two lines.
---
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
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/21625440628
AI-authorship-score: low
AI-authorship-explanation: The commit follows standard kernel conventions with minor human-typical inconsistencies, and the author is a known BPF subsystem developer.
issues-found: 2
issue-severity-score: low
issue-severity-explanation: Minor code quality issues in test code: a type mismatch in variable declaration and extraneous semicolons, neither affecting test functionality.
^ permalink raw reply
* Re: [RFC bpf-next 05/12] bpf: Add multi tracing attach types
From: bot+bpf-ci @ 2026-02-03 10:13 UTC (permalink / raw)
To: jolsa, ast, daniel, andrii
Cc: bpf, linux-trace-kernel, kafai, eddyz87, songliubraving, yhs,
menglong8.dong, rostedt, ast, andrii, daniel, martin.lau, eddyz87,
yonghong.song, clm, ihor.solodrai
In-Reply-To: <20260203093819.2105105-6-jolsa@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 1386 bytes --]
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 6b62b6d57..fb52ba2f7 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
[ ... ]
> @@ -25069,7 +25074,8 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
> return 0;
> } else if (prog->expected_attach_type == BPF_TRACE_ITER) {
> return bpf_iter_prog_supported(prog);
> - }
> + } else if (is_tracing_multi(prog->expected_attach_type))
> + return prog->type == BPF_PROG_TYPE_TRACING ? 0 : -EINVAL;
This isn't a bug, but should this branch have braces for consistency with the
preceding branches in the same if/else chain? The BPF_TRACE_RAW_TP and
BPF_TRACE_ITER branches both use braces.
---
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
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/21625440628
AI-authorship-score: low
AI-authorship-explanation: The commit message contains natural colloquial language and personal attribution typical of human kernel developers, and the code follows established BPF patterns with typical human oversights in style consistency.
issues-found: 1
issue-severity-score: low
issue-severity-explanation: Minor coding style inconsistency with missing braces in an else-if branch that does not affect functionality.
^ permalink raw reply
* Re: [PATCH v2] tracing: Fix funcgraph_exit calltime/rettime offset for 32-bit ARM
From: jempty.liang @ 2026-02-03 10:04 UTC (permalink / raw)
To: Steven Rostedt
Cc: mhiramat, mark.rutland, mathieu.desnoyers, linux-kernel,
linux-trace-kernel
In-Reply-To: <20260202110828.440c8d44@gandalf.local.home>
At 2026-02-03 00:08:28, "Steven Rostedt" <rostedt@goodmis.org> wrote:
>On Mon, 2 Feb 2026 10:38:04 -0500
>Steven Rostedt <rostedt@goodmis.org> wrote:
>
>> Can you try this patch to see if it fixes the issue for you?
>
>Ignore that patch, try this one instead. This was fixed for trace_events a
>while ago, but the same fix wasn't done for ftrace events.
>
>-- Steve
>
>diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c
>index 1698fc22afa0..5b96ac750049 100644
>--- a/kernel/trace/trace_export.c
>+++ b/kernel/trace/trace_export.c
>@@ -14,6 +14,9 @@
>
> #include "trace_output.h"
>
>+/* The alignment of a type when in a structure */
>+#define ALIGN_STRUCTFIELD(type) ((int)(__alignof__(struct {type b;})))
>+
> /* Stub function for events with triggers */
> static int ftrace_event_register(struct trace_event_call *call,
> enum trace_reg type, void *data)
>@@ -88,7 +91,7 @@ static void __always_unused ____ftrace_check_##name(void) \
> #undef __field_ext
> #define __field_ext(_type, _item, _filter_type) { \
> .type = #_type, .name = #_item, \
>- .size = sizeof(_type), .align = __alignof__(_type), \
>+ .size = sizeof(_type), .align = ALIGN_STRUCTFIELD(_type), \
> is_signed_type(_type), .filter_type = _filter_type },
>
On the 32-bit ARM platform, when _type is unsigned long long, the resulting align value is 8 instead of the expected 4.
>
^ permalink raw reply
* Re: [PATCH v2] tracing: Fix funcgraph_exit calltime/rettime offset for 32-bit ARM
From: jempty.liang @ 2026-02-03 9:42 UTC (permalink / raw)
To: Steven Rostedt
Cc: mhiramat, mark.rutland, mathieu.desnoyers, linux-kernel,
linux-trace-kernel
In-Reply-To: <20260202103804.40cbaa27@gandalf.local.home>
At 2026-02-02 23:38:04, "Steven Rostedt" <rostedt@goodmis.org> wrote:
>On Mon, 2 Feb 2026 12:33:42 +0000
>"jempty.liang" <imntjempty@163.com> wrote:
>
>> Commit <66611c0475709607f398e2a5d691b1fc72fe9dfc>
>> (fgraph: Remove calltime and rettime from generic)
>> incorrectly modified the offset values for calltime and rettime fields
>> in the funcgraph_exit traceevent on 32-bit ARM, which are used to parse
>> the corresponding values fromtrace rawdata. The actual memory offset of
>> calltime is 20 (not 24), and rettime is 28 (not 32) for the
>> funcgraph_exit event.
>
>OK, so this is a 32bit issue and not an ARM one. I was able to reproduce it
>on 32bit x86 too.
>
>Basically the problem is that the structure used to output the field offset
>is out of sync with the actual fields of the structure.
>
>>
>> Before the fix,the funcgraph_exit format was:
>>
>> ~# cat /sys/kernel/tracing/events/ftrace/funcgraph_exit/format
>>
>> name: funcgraph_exit
>> ID: 10
>> format:
>> ...
>> field:unsigned long long calltime; offset:24; size:8; signed:0;
>> field:unsigned long long rettime; offset:32; size:8; signed:0;
>>
>> After the fix, the correct funcgraph_exit format is:
>>
>> name: funcgraph_exit
>> ID: 10
>> format:
>> ...
>> field:unsigned long long calltime; offset:20; size:8; signed:0;
>> field:unsigned long long rettime; offset:28; size:8; signed:0;
>>
>
>Thus, the way the calltime and rettime are defined is via:
>
>
>> --- a/kernel/trace/trace_entries.h
>> +++ b/kernel/trace/trace_entries.h
>> @@ -127,8 +127,8 @@ FTRACE_ENTRY_PACKED(funcgraph_exit, ftrace_graph_ret_entry,
>> __field_packed( unsigned long, ret, retval )
>> __field_packed( unsigned int, ret, depth )
>> __field_packed( unsigned int, ret, overrun )
>> - __field(unsigned long long, calltime )
>> - __field(unsigned long long, rettime )
>
>The __field() macro.
>
>> + __field_packed(unsigned long long, ret, calltime)
>> + __field_packed(unsigned long long, ret, rettime)
>
>You converted it to a __field_packed() macro. The reason this worked is
>because fields within a structure defined by __field_packed() has an
>alignment of "1" to pack it.
>
>Thus, your "fix" is simply hiding the real bug, which is that the alignment
>algorithm is wrong.
>
>Can you try this patch to see if it fixes the issue for you?
>
>Thanks,
>
>-- Steve
>
>diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c
>index 1698fc22afa0..68ef39cf0710 100644
>--- a/kernel/trace/trace_export.c
>+++ b/kernel/trace/trace_export.c
>@@ -88,7 +88,9 @@ static void __always_unused ____ftrace_check_##name(void) \
> #undef __field_ext
> #define __field_ext(_type, _item, _filter_type) { \
> .type = #_type, .name = #_item, \
>- .size = sizeof(_type), .align = __alignof__(_type), \
>+ .size = sizeof(_type), \
>+ .align = __alignof__(_type) > __alignof__(long) ? __alignof__(long) :\
>+ __alignof__(_type), \
> is_signed_type(_type), .filter_type = _filter_type },
>
>
It works on the 32-bit ARM platform.
^ permalink raw reply
* [RFC bpf-next 12/12] selftests/bpf: Add tracing multi benchmark test
From: Jiri Olsa @ 2026-02-03 9:38 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: bpf, linux-trace-kernel, Martin KaFai Lau, Eduard Zingerman,
Song Liu, Yonghong Song, Menglong Dong, Steven Rostedt
In-Reply-To: <20260203093819.2105105-1-jolsa@kernel.org>
Adding benchmark for attaching 20k functions.
# ./test_progs -t tracing_multi/fentry/bench -v
bpf_testmod.ko is already unloaded.
Loading bpf_testmod.ko...
Successfully loaded bpf_testmod.ko.
multi_fentry_bench_test:PASS:btf__load_vmlinux_btf 0 nsec
multi_fentry_bench_test:PASS:fentry_multi_skel_load 0 nsec
multi_fentry_bench_test:PASS:get_syms 0 nsec
multi_fentry_bench_test:PASS:bpf_program__attach_tracing_multi 0 nsec
multi_fentry_bench_test: found 20000 functions
multi_fentry_bench_test: attached in 0.466s
multi_fentry_bench_test: detached in 0.066s
#500/3 tracing_multi_test/fentry/bench:OK
#500 tracing_multi_test:OK
Summary: 1/1 PASSED, 0 SKIPPED, 0 FAILED
Successfully unloaded bpf_testmod.ko.
I tried also for 40k:
multi_fentry_bench_test: found 40000 functions
multi_fentry_bench_test: attached in 0.964s
multi_fentry_bench_test: detached in 0.170s
and for 60k (50995 of attachable functions):
multi_fentry_bench_test: found 50995 functions
multi_fentry_bench_test: attached in 1.256s
multi_fentry_bench_test: detached in 0.241s
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
.../selftests/bpf/prog_tests/tracing_multi.c | 186 ++++++++++++++++++
.../bpf/progs/tracing_multi_fentry.c | 6 +
2 files changed, 192 insertions(+)
diff --git a/tools/testing/selftests/bpf/prog_tests/tracing_multi.c b/tools/testing/selftests/bpf/prog_tests/tracing_multi.c
index 3ccf0d4ed1af..575454e31bf6 100644
--- a/tools/testing/selftests/bpf/prog_tests/tracing_multi.c
+++ b/tools/testing/selftests/bpf/prog_tests/tracing_multi.c
@@ -6,6 +6,9 @@
#include <bpf/btf.h>
#include <linux/btf.h>
#include <search.h>
+#include <bpf/btf.h>
+#include <linux/btf.h>
+#include <search.h>
#include "tracing_multi_fentry_test.skel.h"
#include "trace_helpers.h"
#include "bpf/libbpf_internal.h"
@@ -157,12 +160,195 @@ static void multi_fentry_intersected_test(void)
tracing_multi_fentry_test__destroy(skel);
}
+static bool skip_entry(char *name)
+{
+ /*
+ * We attach to almost all kernel functions and some of them
+ * will cause 'suspicious RCU usage' when fprobe is attached
+ * to them. Filter out the current culprits - arch_cpu_idle
+ * default_idle and rcu_* functions.
+ */
+ if (!strcmp(name, "arch_cpu_idle"))
+ return true;
+ if (!strcmp(name, "default_idle"))
+ return true;
+ if (!strncmp(name, "rcu_", 4))
+ return true;
+ if (!strcmp(name, "bpf_dispatcher_xdp_func"))
+ return true;
+ if (!strncmp(name, "__ftrace_invalid_address__",
+ sizeof("__ftrace_invalid_address__") - 1))
+ return true;
+ return false;
+}
+
+#define MAX_BPF_FUNC_ARGS 12
+
+static bool btf_type_is_modifier(const struct btf_type *t)
+{
+ switch (BTF_INFO_KIND(t->info)) {
+ case BTF_KIND_TYPEDEF:
+ case BTF_KIND_VOLATILE:
+ case BTF_KIND_CONST:
+ case BTF_KIND_RESTRICT:
+ case BTF_KIND_TYPE_TAG:
+ return true;
+ }
+ return false;
+}
+
+static bool is_allowed_func(const struct btf *btf, const struct btf_type *t)
+{
+ const struct btf_type *proto;
+ const struct btf_param *args;
+ __u32 i, nargs;
+ __s64 ret;
+
+ proto = btf_type_by_id(btf, t->type);
+ if (BTF_INFO_KIND(proto->info) != BTF_KIND_FUNC_PROTO)
+ return false;
+
+ args = (const struct btf_param *)(proto + 1);
+ nargs = btf_vlen(proto);
+ if (nargs > MAX_BPF_FUNC_ARGS)
+ return false;
+
+ t = btf__type_by_id(btf, proto->type);
+ while (t && btf_type_is_modifier(t))
+ t = btf__type_by_id(btf, t->type);
+
+ if (btf_is_struct(t))
+ return false;
+
+ for (i = 0; i < nargs; i++) {
+ /* No support for variable args */
+ if (i == nargs - 1 && args[i].type == 0)
+ return false;
+
+ /* No support of struct argument size greater than 16 bytes */
+ ret = btf__resolve_size(btf, args[i].type);
+ if (ret < 0 || ret > 16)
+ return false;
+ }
+
+ return true;
+}
+
+static void multi_fentry_bench_test(void)
+{
+ struct tracing_multi_fentry_test *skel = NULL;
+ long attach_start_ns, attach_end_ns;
+ long detach_start_ns, detach_end_ns;
+ double attach_delta, detach_delta;
+ struct bpf_link *link = NULL;
+ size_t i, syms_cnt;
+ char **syms;
+ void *root = NULL;
+ __u32 nr, type_id;
+ struct btf *btf;
+ __u32 *ids = NULL;
+ size_t cap = 0, cnt = 0;
+ int err;
+ LIBBPF_OPTS(bpf_tracing_multi_opts, opts);
+
+ btf = btf__load_vmlinux_btf();
+ if (!ASSERT_OK_PTR(btf, "btf__load_vmlinux_btf"))
+ return;
+
+ skel = tracing_multi_fentry_test__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "fentry_multi_skel_load"))
+ goto cleanup;
+
+ if (!ASSERT_OK(bpf_get_ksyms(&syms, &syms_cnt, true), "get_syms"))
+ goto cleanup;
+
+ for (i = 0; i < syms_cnt; i++) {
+ if (strstr(syms[i], "rcu"))
+ continue;
+ if (strstr(syms[i], "trace"))
+ continue;
+ if (strstr(syms[i], "irq"))
+ continue;
+ if (strstr(syms[i], "bpf_lsm_"))
+ continue;
+ if (!strcmp("migrate_enable", syms[i]))
+ continue;
+ if (!strcmp("migrate_disable", syms[i]))
+ continue;
+ if (!strcmp("__bpf_prog_enter_recur", syms[i]))
+ continue;
+ if (!strcmp("__bpf_prog_exit_recur", syms[i]))
+ continue;
+ if (!strcmp("preempt_count_sub", syms[i]))
+ continue;
+ if (!strcmp("preempt_count_add", syms[i]))
+ continue;
+ if (skip_entry(syms[i]))
+ continue;
+ tsearch(syms[i], &root, compare);
+ }
+
+ nr = btf__type_cnt(btf);
+ for (type_id = 1; type_id < nr && cnt < 20000; type_id++) {
+ const struct btf_type *type;
+ const char *str;
+
+ type = btf__type_by_id(btf, type_id);
+ if (!type)
+ break;
+
+ if (BTF_INFO_KIND(type->info) != BTF_KIND_FUNC)
+ continue;
+
+ str = btf__name_by_offset(btf, type->name_off);
+ if (!str)
+ break;
+
+ if (!tfind(str, &root, compare))
+ continue;
+
+ if (!is_allowed_func(btf, type))
+ continue;
+
+ err = libbpf_ensure_mem((void **) &ids, &cap, sizeof(*ids), cnt + 1);
+ if (err)
+ break;
+
+ ids[cnt++] = type_id;
+ }
+
+ opts.btf_ids = ids;
+ opts.cnt = cnt;
+
+ attach_start_ns = get_time_ns();
+ link = bpf_program__attach_tracing_multi(skel->progs.bench, NULL, &opts);
+ attach_end_ns = get_time_ns();
+ if (!ASSERT_OK_PTR(link, "bpf_program__attach_tracing_multi"))
+ goto cleanup;
+
+ detach_start_ns = get_time_ns();
+ bpf_link__destroy(link);
+ detach_end_ns = get_time_ns();
+
+ attach_delta = (attach_end_ns - attach_start_ns) / 1000000000.0;
+ detach_delta = (detach_end_ns - detach_start_ns) / 1000000000.0;
+
+ printf("%s: found %lu functions\n", __func__, cnt);
+ printf("%s: attached in %7.3lfs\n", __func__, attach_delta);
+ printf("%s: detached in %7.3lfs\n", __func__, detach_delta);
+
+cleanup:
+ tracing_multi_fentry_test__destroy(skel);
+}
+
void __test_tracing_multi_test(void)
{
if (test__start_subtest("fentry/simple"))
multi_fentry_test();
if (test__start_subtest("fentry/intersected"))
multi_fentry_intersected_test();
+ if (test__start_subtest("fentry/bench"))
+ multi_fentry_bench_test();
}
#else
void __test_tracing_multi_test(void)
diff --git a/tools/testing/selftests/bpf/progs/tracing_multi_fentry.c b/tools/testing/selftests/bpf/progs/tracing_multi_fentry.c
index 47857209bf9f..0f39c446792d 100644
--- a/tools/testing/selftests/bpf/progs/tracing_multi_fentry.c
+++ b/tools/testing/selftests/bpf/progs/tracing_multi_fentry.c
@@ -31,3 +31,9 @@ int BPF_PROG(test_2, __u64 a, __u64 b, __u64 c, __u64 d, __u64 e, __u64 f)
multi_arg_check(ctx, &test_result_3);
return 0;
}
+
+SEC("fentry.multi")
+int BPF_PROG(bench, __u64 a, __u64 b, __u64 c, __u64 d, __u64 e, __u64 f)
+{
+ return 0;
+}
--
2.52.0
^ permalink raw reply related
* [RFC bpf-next 11/12] selftests/bpf: Add fentry intersected tracing multi func test
From: Jiri Olsa @ 2026-02-03 9:38 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: bpf, linux-trace-kernel, Martin KaFai Lau, Eduard Zingerman,
Song Liu, Yonghong Song, Menglong Dong, Steven Rostedt
In-Reply-To: <20260203093819.2105105-1-jolsa@kernel.org>
Adding test for attachment of 2 multi tracing links attached
to intersecting functions and making sure both programs are
called properly with proper arguments.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
.../selftests/bpf/prog_tests/tracing_multi.c | 129 ++++++++++++++++++
.../bpf/progs/tracing_multi_fentry.c | 16 +++
2 files changed, 145 insertions(+)
diff --git a/tools/testing/selftests/bpf/prog_tests/tracing_multi.c b/tools/testing/selftests/bpf/prog_tests/tracing_multi.c
index 6d45147f0730..3ccf0d4ed1af 100644
--- a/tools/testing/selftests/bpf/prog_tests/tracing_multi.c
+++ b/tools/testing/selftests/bpf/prog_tests/tracing_multi.c
@@ -3,8 +3,12 @@
#include <test_progs.h>
#ifdef __x86_64__
+#include <bpf/btf.h>
+#include <linux/btf.h>
+#include <search.h>
#include "tracing_multi_fentry_test.skel.h"
#include "trace_helpers.h"
+#include "bpf/libbpf_internal.h"
static void multi_fentry_test(void)
{
@@ -30,10 +34,135 @@ static void multi_fentry_test(void)
tracing_multi_fentry_test__destroy(skel);
}
+static int compare(const void *pa, const void *pb)
+{
+ return strcmp((char *) pa, (char *) pb);
+}
+
+static __u32 *get_ids(const char *funcs[], int funcs_cnt)
+{
+ size_t cap = 0, cnt = 0;
+ __u32 nr, type_id;
+ void *root = NULL;
+ __u32 *ids = NULL;
+ struct btf *btf;
+ int i, err = -1;
+
+ btf = btf__load_vmlinux_btf();
+ if (!ASSERT_OK_PTR(btf, "btf__load_vmlinux_btf"))
+ return NULL;
+
+ for (i = 0; i < funcs_cnt; i++)
+ tsearch(funcs[i], &root, compare);
+
+ nr = btf__type_cnt(btf);
+ for (type_id = 1; type_id < nr; type_id++) {
+ const struct btf_type *type;
+ const char *str;
+
+ type = btf__type_by_id(btf, type_id);
+ if (!type) {
+ err = -1;
+ break;
+ }
+
+ if (BTF_INFO_KIND(type->info) != BTF_KIND_FUNC)
+ continue;
+
+ str = btf__name_by_offset(btf, type->name_off);
+ if (!str) {
+ err = -1;
+ break;
+ }
+
+ if (!tfind(str, &root, compare))
+ continue;
+
+ err = libbpf_ensure_mem((void **) &ids, &cap, sizeof(*ids), cnt + 1);
+ if (err)
+ break;
+
+ ids[cnt++] = type_id;
+ }
+
+ if (err)
+ free(ids);
+ btf__free(btf);
+ return ids;
+}
+
+static void multi_fentry_intersected_test(void)
+{
+ struct tracing_multi_fentry_test *skel = NULL;
+ LIBBPF_OPTS(bpf_tracing_multi_opts, opts);
+ LIBBPF_OPTS(bpf_test_run_opts, topts);
+ const char *funcs_1[] = {
+ "bpf_fentry_test1",
+ "bpf_fentry_test2",
+ "bpf_fentry_test3",
+ "bpf_fentry_test4",
+ "bpf_fentry_test5",
+ };
+ const char *funcs_2[] = {
+ "bpf_fentry_test4",
+ "bpf_fentry_test5",
+ "bpf_fentry_test6",
+ "bpf_fentry_test7",
+ "bpf_fentry_test8",
+ };
+ __u32 *ids_1 = NULL, *ids_2 = NULL;
+ size_t cnt_1 = ARRAY_SIZE(funcs_1);
+ size_t cnt_2 = ARRAY_SIZE(funcs_2);
+ struct bpf_link *link_1 = NULL;
+ struct bpf_link *link_2 = NULL;
+ int err, prog_fd;
+
+ skel = tracing_multi_fentry_test__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "fentry_multi_skel_load"))
+ goto cleanup;
+
+ ids_1 = get_ids(funcs_1, cnt_1);
+ if (!ASSERT_OK_PTR(ids_1, "get_ids"))
+ goto cleanup;
+ ids_2 = get_ids(funcs_2, cnt_2);
+ if (!ASSERT_OK_PTR(ids_2, "get_ids"))
+ goto cleanup;
+
+ opts.btf_ids = ids_1;
+ opts.cnt = cnt_1;
+
+ link_1 = bpf_program__attach_tracing_multi(skel->progs.test_1, NULL, &opts);
+ if (!ASSERT_OK_PTR(link_1, "bpf_program__attach_tracing_multi"))
+ goto cleanup;
+
+ opts.btf_ids = ids_2;
+ opts.cnt = cnt_2;
+
+ link_2 = bpf_program__attach_tracing_multi(skel->progs.test_2, NULL, &opts);
+ if (!ASSERT_OK_PTR(link_2, "bpf_program__attach_tracing_multi"))
+ goto cleanup;
+
+ prog_fd = bpf_program__fd(skel->progs.test);
+ err = bpf_prog_test_run_opts(prog_fd, &topts);
+ ASSERT_OK(err, "test_run");
+
+ ASSERT_EQ(skel->bss->test_result_2, 5, "test_result");
+ ASSERT_EQ(skel->bss->test_result_3, 5, "test_result");
+
+cleanup:
+ free(ids_1);
+ free(ids_2);
+ bpf_link__destroy(link_1);
+ bpf_link__destroy(link_2);
+ tracing_multi_fentry_test__destroy(skel);
+}
+
void __test_tracing_multi_test(void)
{
if (test__start_subtest("fentry/simple"))
multi_fentry_test();
+ if (test__start_subtest("fentry/intersected"))
+ multi_fentry_intersected_test();
}
#else
void __test_tracing_multi_test(void)
diff --git a/tools/testing/selftests/bpf/progs/tracing_multi_fentry.c b/tools/testing/selftests/bpf/progs/tracing_multi_fentry.c
index 628734596114..47857209bf9f 100644
--- a/tools/testing/selftests/bpf/progs/tracing_multi_fentry.c
+++ b/tools/testing/selftests/bpf/progs/tracing_multi_fentry.c
@@ -6,6 +6,8 @@
char _license[] SEC("license") = "GPL";
__u64 test_result_1 = 0;
+__u64 test_result_2 = 0;
+__u64 test_result_3 = 0;
__hidden extern void multi_arg_check(__u64 *ctx, __u64 *test_result);
@@ -15,3 +17,17 @@ int BPF_PROG(test, __u64 a, __u64 b, __u64 c, __u64 d, __u64 e, __u64 f)
multi_arg_check(ctx, &test_result_1);
return 0;
}
+
+SEC("fentry.multi")
+int BPF_PROG(test_1, __u64 a, __u64 b, __u64 c, __u64 d, __u64 e, __u64 f)
+{
+ multi_arg_check(ctx, &test_result_2);
+ return 0;
+}
+
+SEC("fentry.multi")
+int BPF_PROG(test_2, __u64 a, __u64 b, __u64 c, __u64 d, __u64 e, __u64 f)
+{
+ multi_arg_check(ctx, &test_result_3);
+ return 0;
+}
--
2.52.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox