* [PATCHv2 bpf-next 00/11] bpf: Disable preemption in stack map code
@ 2026-07-29 8:37 Jiri Olsa
2026-07-29 8:37 ` [PATCHv2 bpf-next 01/11] bpf: Factor stackid_init function from __bpf_get_stackid Jiri Olsa
` (10 more replies)
0 siblings, 11 replies; 16+ messages in thread
From: Jiri Olsa @ 2026-07-29 8:37 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: bpf, Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
Quentin Monnet, Tao Chen, STAR Labs SG, Arnaud Lecomte
hi,
we need to disable preemption for get_perf_callchain and keep it disabled
as long as we are accessing its returned trace entries buffer.
This patchset refactors both bpf_get_stack and bpf_get_stackid helpers as
suggested by Andrii [1] before applying the actual preemption fix.
Note the initial fix was sent by Tao Chen [2], but there was no follow up
on this since February, hence this post.
thanks,
jirka
v1: https://lore.kernel.org/bpf/20260720085351.655075-1-jolsa@kernel.org/
v2 changes:
- removed several unused functions arguments [sashiko]
- restore trace-nr value fix in bpf_get_stack_pe [sashiko]
- kept rcu locking together with preemption disable in __bpf_get_stack [sashiko]
- clear buf on error paths in __bpf_get_task_stack [sashiko]
[1] https://lore.kernel.org/bpf/CAEf4BzZwvAUgLwz-M0Y_NJLTmedyY9U6s7LrSmn751hQdTP4Uw@mail.gmail.com/
[2] https://lore.kernel.org/bpf/20260206090653.1336687-1-chen.dylane@linux.dev/
---
Daniel Borkmann (1):
bpf: Disable preemption in __bpf_get_stack
Jiri Olsa (10):
bpf: Factor stackid_init function from __bpf_get_stackid
bpf: Factor stackid_fastpath function from __bpf_get_stackid
bpf: Factor stackid_new_bucket from __bpf_get_stackid
bpf: Use stack id functions instead of __bpf_get_stackid
bpf: Disable preemption in bpf_get_stackid
bpf: Factor callchain_store function from __bpf_get_stack
bpf: Factor callchain_finalize function from __bpf_get_stack
bpf: Restore trace->nr value properly in bpf_get_stack_pe
bpf: Remove trace_in argument from __bpf_get_stack
bpf: Clear buf on error in __bpf_get_task_stack
kernel/bpf/stackmap.c | 302 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------
1 file changed, 206 insertions(+), 96 deletions(-)
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCHv2 bpf-next 01/11] bpf: Factor stackid_init function from __bpf_get_stackid
2026-07-29 8:37 [PATCHv2 bpf-next 00/11] bpf: Disable preemption in stack map code Jiri Olsa
@ 2026-07-29 8:37 ` Jiri Olsa
2026-07-29 8:51 ` sashiko-bot
2026-07-29 8:37 ` [PATCHv2 bpf-next 02/11] bpf: Factor stackid_fastpath " Jiri Olsa
` (9 subsequent siblings)
10 siblings, 1 reply; 16+ messages in thread
From: Jiri Olsa @ 2026-07-29 8:37 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: bpf, Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
Quentin Monnet, Tao Chen, STAR Labs SG, Arnaud Lecomte
The new stackid_init function stores all the necessary bits for stackid
trace and it will be used by other functions in following changes.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
kernel/bpf/stackmap.c | 95 +++++++++++++++++++++++++++----------------
1 file changed, 59 insertions(+), 36 deletions(-)
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index 41fe87d7302f..0eafe55b1828 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -504,33 +504,54 @@ get_callchain_entry_for_task(struct task_struct *task, u32 max_depth)
#endif
}
-static long __bpf_get_stackid(struct bpf_map *map,
- struct perf_callchain_entry *trace, u64 flags)
+struct stackid {
+ struct stack_map_bucket *bucket;
+ u64 *ips;
+ u32 nr;
+ u32 len;
+ u32 hash;
+ u32 id;
+};
+
+static int stackid_init(struct stackid *stackid, struct bpf_map *map,
+ struct perf_callchain_entry *trace, u64 flags)
{
struct bpf_stack_map *smap = container_of(map, struct bpf_stack_map, map);
- struct stack_map_bucket *bucket, *new_bucket, *old_bucket;
- u32 hash, id, trace_nr, trace_len, i, max_depth;
u32 skip = flags & BPF_F_SKIP_FIELD_MASK;
- bool user = flags & BPF_F_USER_STACK;
- u64 *ips;
- bool hash_matches;
+ u32 max_depth;
if (trace->nr <= skip)
/* skipping more than usable stack trace */
return -EFAULT;
max_depth = stack_map_calculate_max_depth(map->value_size, stack_map_data_size(map), flags);
- trace_nr = min_t(u32, trace->nr - skip, max_depth - skip);
- trace_len = trace_nr * sizeof(u64);
- ips = trace->ip + skip;
- hash = jhash2((u32 *)ips, trace_len / sizeof(u32), 0);
- id = hash & (smap->n_buckets - 1);
- bucket = READ_ONCE(smap->buckets[id]);
+ stackid->nr = min_t(u32, trace->nr - skip, max_depth - skip);
+ stackid->len = stackid->nr * sizeof(u64);
+ stackid->ips = trace->ip + skip;
+ stackid->hash = jhash2((u32 *)stackid->ips, stackid->len / sizeof(u32), 0);
+ stackid->id = stackid->hash & (smap->n_buckets - 1);
+ stackid->bucket = READ_ONCE(smap->buckets[stackid->id]);
+ return 0;
+}
- hash_matches = bucket && bucket->hash == hash;
+static long __bpf_get_stackid(struct stackid *stackid, struct bpf_map *map,
+ struct perf_callchain_entry *trace, u64 flags)
+{
+ struct bpf_stack_map *smap = container_of(map, struct bpf_stack_map, map);
+ struct stack_map_bucket *new_bucket, *old_bucket;
+ bool user = flags & BPF_F_USER_STACK;
+ bool hash_matches;
+ u32 trace_len, i;
+ int err;
+
+ err = stackid_init(stackid, map, trace, flags);
+ if (err)
+ return err;
+
+ hash_matches = stackid->bucket && stackid->bucket->hash == stackid->hash;
/* fast cmp */
if (hash_matches && flags & BPF_F_FAST_STACK_CMP)
- return id;
+ return stackid->id;
if (stack_map_use_build_id(map)) {
struct bpf_stack_build_id *id_offs;
@@ -540,42 +561,42 @@ static long __bpf_get_stackid(struct bpf_map *map,
pcpu_freelist_pop(&smap->freelist);
if (unlikely(!new_bucket))
return -ENOMEM;
- new_bucket->nr = trace_nr;
+ new_bucket->nr = stackid->nr;
id_offs = (struct bpf_stack_build_id *)new_bucket->data;
- for (i = 0; i < trace_nr; i++)
- id_offs[i].ip = ips[i];
- stack_map_get_build_id_offset(id_offs, trace_nr, user, false /* !may_fault */);
- trace_len = trace_nr * sizeof(struct bpf_stack_build_id);
- if (hash_matches && bucket->nr == trace_nr &&
- memcmp(bucket->data, new_bucket->data, trace_len) == 0) {
+ for (i = 0; i < stackid->nr; i++)
+ id_offs[i].ip = stackid->ips[i];
+ stack_map_get_build_id_offset(id_offs, stackid->nr, user, false /* !may_fault */);
+ trace_len = stackid->nr * sizeof(struct bpf_stack_build_id);
+ if (hash_matches && stackid->bucket->nr == stackid->nr &&
+ memcmp(stackid->bucket->data, new_bucket->data, trace_len) == 0) {
pcpu_freelist_push(&smap->freelist, &new_bucket->fnode);
- return id;
+ return stackid->id;
}
- if (bucket && !(flags & BPF_F_REUSE_STACKID)) {
+ if (stackid->bucket && !(flags & BPF_F_REUSE_STACKID)) {
pcpu_freelist_push(&smap->freelist, &new_bucket->fnode);
return -EEXIST;
}
} else {
- if (hash_matches && bucket->nr == trace_nr &&
- memcmp(bucket->data, ips, trace_len) == 0)
- return id;
- if (bucket && !(flags & BPF_F_REUSE_STACKID))
+ if (hash_matches && stackid->bucket->nr == stackid->nr &&
+ memcmp(stackid->bucket->data, stackid->ips, stackid->len) == 0)
+ return stackid->id;
+ if (stackid->bucket && !(flags & BPF_F_REUSE_STACKID))
return -EEXIST;
new_bucket = (struct stack_map_bucket *)
pcpu_freelist_pop(&smap->freelist);
if (unlikely(!new_bucket))
return -ENOMEM;
- memcpy(new_bucket->data, ips, trace_len);
+ memcpy(new_bucket->data, stackid->ips, stackid->len);
}
- new_bucket->hash = hash;
- new_bucket->nr = trace_nr;
+ new_bucket->hash = stackid->hash;
+ new_bucket->nr = stackid->nr;
- old_bucket = xchg(&smap->buckets[id], new_bucket);
+ old_bucket = xchg(&smap->buckets[stackid->id], new_bucket);
if (old_bucket)
pcpu_freelist_push(&smap->freelist, &old_bucket->fnode);
- return id;
+ return stackid->id;
}
BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, struct bpf_map *, map,
@@ -584,6 +605,7 @@ BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, struct bpf_map *, map,
u32 elem_size = stack_map_data_size(map);
bool user = flags & BPF_F_USER_STACK;
struct perf_callchain_entry *trace;
+ struct stackid stackid;
bool kernel = !user;
u32 max_depth;
@@ -599,7 +621,7 @@ BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, struct bpf_map *, map,
/* couldn't fetch the stack trace */
return -EFAULT;
- return __bpf_get_stackid(map, trace, flags);
+ return __bpf_get_stackid(&stackid, map, trace, flags);
}
const struct bpf_func_proto bpf_get_stackid_proto = {
@@ -628,6 +650,7 @@ BPF_CALL_3(bpf_get_stackid_pe, struct bpf_perf_event_data_kern *, ctx,
{
struct perf_event *event = ctx->event;
struct perf_callchain_entry *trace;
+ struct stackid stackid;
bool kernel, user;
__u64 nr_kernel;
int ret;
@@ -653,7 +676,7 @@ BPF_CALL_3(bpf_get_stackid_pe, struct bpf_perf_event_data_kern *, ctx,
if (kernel) {
trace->nr = nr_kernel;
- ret = __bpf_get_stackid(map, trace, flags);
+ ret = __bpf_get_stackid(&stackid, map, trace, flags);
} else { /* user */
u64 skip = flags & BPF_F_SKIP_FIELD_MASK;
@@ -662,7 +685,7 @@ BPF_CALL_3(bpf_get_stackid_pe, struct bpf_perf_event_data_kern *, ctx,
return -EFAULT;
flags = (flags & ~BPF_F_SKIP_FIELD_MASK) | skip;
- ret = __bpf_get_stackid(map, trace, flags);
+ ret = __bpf_get_stackid(&stackid, map, trace, flags);
}
/* restore nr */
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCHv2 bpf-next 02/11] bpf: Factor stackid_fastpath function from __bpf_get_stackid
2026-07-29 8:37 [PATCHv2 bpf-next 00/11] bpf: Disable preemption in stack map code Jiri Olsa
2026-07-29 8:37 ` [PATCHv2 bpf-next 01/11] bpf: Factor stackid_init function from __bpf_get_stackid Jiri Olsa
@ 2026-07-29 8:37 ` Jiri Olsa
2026-07-29 8:37 ` [PATCHv2 bpf-next 03/11] bpf: Factor stackid_new_bucket " Jiri Olsa
` (8 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Jiri Olsa @ 2026-07-29 8:37 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: bpf, Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
Quentin Monnet, Tao Chen, STAR Labs SG, Arnaud Lecomte
The new stackid_fastpath does the fast stack hash and trace check, that
does not need new bucket allocation. It covers both just-ip and buildid
code paths.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
kernel/bpf/stackmap.c | 43 ++++++++++++++++++++++++++++---------------
1 file changed, 28 insertions(+), 15 deletions(-)
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index 0eafe55b1828..7bc2a966e3e8 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -511,6 +511,7 @@ struct stackid {
u32 len;
u32 hash;
u32 id;
+ bool hash_matches;
};
static int stackid_init(struct stackid *stackid, struct bpf_map *map,
@@ -531,28 +532,46 @@ static int stackid_init(struct stackid *stackid, struct bpf_map *map,
stackid->hash = jhash2((u32 *)stackid->ips, stackid->len / sizeof(u32), 0);
stackid->id = stackid->hash & (smap->n_buckets - 1);
stackid->bucket = READ_ONCE(smap->buckets[stackid->id]);
+ stackid->hash_matches = stackid->bucket && stackid->bucket->hash == stackid->hash;
return 0;
}
+static int stackid_fastpath(struct stackid *stackid, struct bpf_map *map,
+ struct perf_callchain_entry *trace, u64 flags)
+{
+ int err;
+
+ err = stackid_init(stackid, map, trace, flags);
+ if (err)
+ return err;
+
+ /* fast cmp */
+ if (stackid->hash_matches && flags & BPF_F_FAST_STACK_CMP)
+ return stackid->id;
+
+ if (stack_map_use_build_id(map))
+ return -ENOENT;
+ if (stackid->hash_matches && stackid->bucket->nr == stackid->nr &&
+ memcmp(stackid->bucket->data, stackid->ips, stackid->len) == 0)
+ return stackid->id;
+ if (stackid->bucket && !(flags & BPF_F_REUSE_STACKID))
+ return -EEXIST;
+ return -ENOENT;
+}
+
static long __bpf_get_stackid(struct stackid *stackid, struct bpf_map *map,
struct perf_callchain_entry *trace, u64 flags)
{
struct bpf_stack_map *smap = container_of(map, struct bpf_stack_map, map);
struct stack_map_bucket *new_bucket, *old_bucket;
bool user = flags & BPF_F_USER_STACK;
- bool hash_matches;
u32 trace_len, i;
int err;
- err = stackid_init(stackid, map, trace, flags);
- if (err)
+ err = stackid_fastpath(stackid, map, trace, flags);
+ if (err != -ENOENT)
return err;
- hash_matches = stackid->bucket && stackid->bucket->hash == stackid->hash;
- /* fast cmp */
- if (hash_matches && flags & BPF_F_FAST_STACK_CMP)
- return stackid->id;
-
if (stack_map_use_build_id(map)) {
struct bpf_stack_build_id *id_offs;
@@ -567,7 +586,7 @@ static long __bpf_get_stackid(struct stackid *stackid, struct bpf_map *map,
id_offs[i].ip = stackid->ips[i];
stack_map_get_build_id_offset(id_offs, stackid->nr, user, false /* !may_fault */);
trace_len = stackid->nr * sizeof(struct bpf_stack_build_id);
- if (hash_matches && stackid->bucket->nr == stackid->nr &&
+ if (stackid->hash_matches && stackid->bucket->nr == stackid->nr &&
memcmp(stackid->bucket->data, new_bucket->data, trace_len) == 0) {
pcpu_freelist_push(&smap->freelist, &new_bucket->fnode);
return stackid->id;
@@ -577,12 +596,6 @@ static long __bpf_get_stackid(struct stackid *stackid, struct bpf_map *map,
return -EEXIST;
}
} else {
- if (hash_matches && stackid->bucket->nr == stackid->nr &&
- memcmp(stackid->bucket->data, stackid->ips, stackid->len) == 0)
- return stackid->id;
- if (stackid->bucket && !(flags & BPF_F_REUSE_STACKID))
- return -EEXIST;
-
new_bucket = (struct stack_map_bucket *)
pcpu_freelist_pop(&smap->freelist);
if (unlikely(!new_bucket))
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCHv2 bpf-next 03/11] bpf: Factor stackid_new_bucket from __bpf_get_stackid
2026-07-29 8:37 [PATCHv2 bpf-next 00/11] bpf: Disable preemption in stack map code Jiri Olsa
2026-07-29 8:37 ` [PATCHv2 bpf-next 01/11] bpf: Factor stackid_init function from __bpf_get_stackid Jiri Olsa
2026-07-29 8:37 ` [PATCHv2 bpf-next 02/11] bpf: Factor stackid_fastpath " Jiri Olsa
@ 2026-07-29 8:37 ` Jiri Olsa
2026-07-29 8:38 ` [PATCHv2 bpf-next 04/11] bpf: Use stack id functions instead of __bpf_get_stackid Jiri Olsa
` (7 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Jiri Olsa @ 2026-07-29 8:37 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: bpf, Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
Quentin Monnet, Tao Chen, STAR Labs SG, Arnaud Lecomte
The new stackid_new_bucket allocates the new bucket and initializes it
with the trace data.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
kernel/bpf/stackmap.c | 48 +++++++++++++++++++++++++++----------------
1 file changed, 30 insertions(+), 18 deletions(-)
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index 7bc2a966e3e8..366195b08c79 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -559,31 +559,52 @@ static int stackid_fastpath(struct stackid *stackid, struct bpf_map *map,
return -ENOENT;
}
+static struct stack_map_bucket *
+stackid_new_bucket(struct stackid *stackid, struct bpf_map *map)
+{
+ struct bpf_stack_map *smap = container_of(map, struct bpf_stack_map, map);
+ struct bpf_stack_build_id *id_offs;
+ struct stack_map_bucket *bucket;
+ u32 i;
+
+ bucket = (struct stack_map_bucket *) pcpu_freelist_pop(&smap->freelist);
+ if (unlikely(!bucket))
+ return NULL;
+
+ if (stack_map_use_build_id(map)) {
+ id_offs = (struct bpf_stack_build_id *)bucket->data;
+ for (i = 0; i < stackid->nr; i++)
+ id_offs[i].ip = stackid->ips[i];
+ } else {
+ memcpy(bucket->data, stackid->ips, stackid->len);
+ }
+
+ bucket->hash = stackid->hash;
+ bucket->nr = stackid->nr;
+ return bucket;
+}
+
static long __bpf_get_stackid(struct stackid *stackid, struct bpf_map *map,
struct perf_callchain_entry *trace, u64 flags)
{
struct bpf_stack_map *smap = container_of(map, struct bpf_stack_map, map);
struct stack_map_bucket *new_bucket, *old_bucket;
bool user = flags & BPF_F_USER_STACK;
- u32 trace_len, i;
+ u32 trace_len;
int err;
err = stackid_fastpath(stackid, map, trace, flags);
if (err != -ENOENT)
return err;
+ new_bucket = stackid_new_bucket(stackid, map);
+ if (!new_bucket)
+ return -ENOMEM;
+
if (stack_map_use_build_id(map)) {
struct bpf_stack_build_id *id_offs;
- /* for build_id+offset, pop a bucket before slow cmp */
- new_bucket = (struct stack_map_bucket *)
- pcpu_freelist_pop(&smap->freelist);
- if (unlikely(!new_bucket))
- return -ENOMEM;
- new_bucket->nr = stackid->nr;
id_offs = (struct bpf_stack_build_id *)new_bucket->data;
- for (i = 0; i < stackid->nr; i++)
- id_offs[i].ip = stackid->ips[i];
stack_map_get_build_id_offset(id_offs, stackid->nr, user, false /* !may_fault */);
trace_len = stackid->nr * sizeof(struct bpf_stack_build_id);
if (stackid->hash_matches && stackid->bucket->nr == stackid->nr &&
@@ -595,17 +616,8 @@ static long __bpf_get_stackid(struct stackid *stackid, struct bpf_map *map,
pcpu_freelist_push(&smap->freelist, &new_bucket->fnode);
return -EEXIST;
}
- } else {
- new_bucket = (struct stack_map_bucket *)
- pcpu_freelist_pop(&smap->freelist);
- if (unlikely(!new_bucket))
- return -ENOMEM;
- memcpy(new_bucket->data, stackid->ips, stackid->len);
}
- new_bucket->hash = stackid->hash;
- new_bucket->nr = stackid->nr;
-
old_bucket = xchg(&smap->buckets[stackid->id], new_bucket);
if (old_bucket)
pcpu_freelist_push(&smap->freelist, &old_bucket->fnode);
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCHv2 bpf-next 04/11] bpf: Use stack id functions instead of __bpf_get_stackid
2026-07-29 8:37 [PATCHv2 bpf-next 00/11] bpf: Disable preemption in stack map code Jiri Olsa
` (2 preceding siblings ...)
2026-07-29 8:37 ` [PATCHv2 bpf-next 03/11] bpf: Factor stackid_new_bucket " Jiri Olsa
@ 2026-07-29 8:38 ` Jiri Olsa
2026-07-29 9:42 ` bot+bpf-ci
2026-07-29 8:38 ` [PATCHv2 bpf-next 05/11] bpf: Disable preemption in bpf_get_stackid Jiri Olsa
` (6 subsequent siblings)
10 siblings, 1 reply; 16+ messages in thread
From: Jiri Olsa @ 2026-07-29 8:38 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: bpf, Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
Quentin Monnet, Tao Chen, STAR Labs SG, Arnaud Lecomte
Replacing __bpf_get_stackid calls with sequence of following functions:
stackid_fastpath
stackid_new_bucket
stackid_install
This makes code more structured and allows us to easily disable
preemption only in bpf_get_stackid in following changes.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
kernel/bpf/stackmap.c | 43 +++++++++++++++++++++++++++----------------
1 file changed, 27 insertions(+), 16 deletions(-)
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index 366195b08c79..43b1e5436047 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -584,22 +584,13 @@ stackid_new_bucket(struct stackid *stackid, struct bpf_map *map)
return bucket;
}
-static long __bpf_get_stackid(struct stackid *stackid, struct bpf_map *map,
- struct perf_callchain_entry *trace, u64 flags)
+static long stackid_install(struct stackid *stackid, struct bpf_map *map,
+ struct stack_map_bucket *new_bucket, u64 flags)
{
struct bpf_stack_map *smap = container_of(map, struct bpf_stack_map, map);
- struct stack_map_bucket *new_bucket, *old_bucket;
bool user = flags & BPF_F_USER_STACK;
+ struct stack_map_bucket *old_bucket;
u32 trace_len;
- int err;
-
- err = stackid_fastpath(stackid, map, trace, flags);
- if (err != -ENOENT)
- return err;
-
- new_bucket = stackid_new_bucket(stackid, map);
- if (!new_bucket)
- return -ENOMEM;
if (stack_map_use_build_id(map)) {
struct bpf_stack_build_id *id_offs;
@@ -629,10 +620,12 @@ BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, struct bpf_map *, map,
{
u32 elem_size = stack_map_data_size(map);
bool user = flags & BPF_F_USER_STACK;
+ struct stack_map_bucket *new_bucket;
struct perf_callchain_entry *trace;
struct stackid stackid;
bool kernel = !user;
u32 max_depth;
+ int err;
if (unlikely(flags & ~(BPF_F_SKIP_FIELD_MASK | BPF_F_USER_STACK |
BPF_F_FAST_STACK_CMP | BPF_F_REUSE_STACKID)))
@@ -646,7 +639,15 @@ BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, struct bpf_map *, map,
/* couldn't fetch the stack trace */
return -EFAULT;
- return __bpf_get_stackid(&stackid, map, trace, flags);
+ err = stackid_fastpath(&stackid, map, trace, flags);
+ if (err != -ENOENT)
+ return err;
+
+ new_bucket = stackid_new_bucket(&stackid, map);
+ if (!new_bucket)
+ return -ENOMEM;
+
+ return stackid_install(&stackid, map, new_bucket, flags);
}
const struct bpf_func_proto bpf_get_stackid_proto = {
@@ -674,6 +675,7 @@ BPF_CALL_3(bpf_get_stackid_pe, struct bpf_perf_event_data_kern *, ctx,
struct bpf_map *, map, u64, flags)
{
struct perf_event *event = ctx->event;
+ struct stack_map_bucket *new_bucket;
struct perf_callchain_entry *trace;
struct stackid stackid;
bool kernel, user;
@@ -701,7 +703,6 @@ BPF_CALL_3(bpf_get_stackid_pe, struct bpf_perf_event_data_kern *, ctx,
if (kernel) {
trace->nr = nr_kernel;
- ret = __bpf_get_stackid(&stackid, map, trace, flags);
} else { /* user */
u64 skip = flags & BPF_F_SKIP_FIELD_MASK;
@@ -710,12 +711,22 @@ BPF_CALL_3(bpf_get_stackid_pe, struct bpf_perf_event_data_kern *, ctx,
return -EFAULT;
flags = (flags & ~BPF_F_SKIP_FIELD_MASK) | skip;
- ret = __bpf_get_stackid(&stackid, map, trace, flags);
}
+ ret = stackid_fastpath(&stackid, map, trace, flags);
+ if (ret != -ENOENT)
+ goto error;
+
+ new_bucket = stackid_new_bucket(&stackid, map);
+ if (new_bucket) {
+ trace->nr = nr;
+ return stackid_install(&stackid, map, new_bucket, flags);
+ }
+ ret = -ENOMEM;
+
+error:
/* restore nr */
trace->nr = nr;
-
return ret;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCHv2 bpf-next 05/11] bpf: Disable preemption in bpf_get_stackid
2026-07-29 8:37 [PATCHv2 bpf-next 00/11] bpf: Disable preemption in stack map code Jiri Olsa
` (3 preceding siblings ...)
2026-07-29 8:38 ` [PATCHv2 bpf-next 04/11] bpf: Use stack id functions instead of __bpf_get_stackid Jiri Olsa
@ 2026-07-29 8:38 ` Jiri Olsa
2026-07-29 8:38 ` [PATCHv2 bpf-next 06/11] bpf: Factor callchain_store function from __bpf_get_stack Jiri Olsa
` (5 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Jiri Olsa @ 2026-07-29 8:38 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: stable, Tao Chen, bpf, Martin KaFai Lau, Eduard Zingerman,
Song Liu, Yonghong Song, Quentin Monnet, STAR Labs SG,
Arnaud Lecomte
The get_perf_callchain call needs disabled preemption plus we need
it disabled as long as we access its returned trace entries buffer.
Note the bpf_get_stackid_pe function is executed already with
preemption disabled.
Cc: stable@vger.kernel.org
Fixes: d5a3b1f69186 ("bpf: introduce BPF_MAP_TYPE_STACK_TRACE")
Reported-by: Tao Chen <chen.dylane@linux.dev>
Closes: https://lore.kernel.org/bpf/20260206090653.1336687-2-chen.dylane@linux.dev/
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
kernel/bpf/stackmap.c | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index 43b1e5436047..e48ddb4edd47 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -624,30 +624,37 @@ BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, struct bpf_map *, map,
struct perf_callchain_entry *trace;
struct stackid stackid;
bool kernel = !user;
+ int err = -EFAULT;
u32 max_depth;
- int err;
if (unlikely(flags & ~(BPF_F_SKIP_FIELD_MASK | BPF_F_USER_STACK |
BPF_F_FAST_STACK_CMP | BPF_F_REUSE_STACKID)))
return -EINVAL;
max_depth = stack_map_calculate_max_depth(map->value_size, elem_size, flags);
+
+ preempt_disable();
trace = get_perf_callchain(regs, kernel, user, max_depth,
false, false, 0);
if (unlikely(!trace))
/* couldn't fetch the stack trace */
- return -EFAULT;
+ goto out;
err = stackid_fastpath(&stackid, map, trace, flags);
if (err != -ENOENT)
- return err;
+ goto out;
new_bucket = stackid_new_bucket(&stackid, map);
- if (!new_bucket)
- return -ENOMEM;
+ if (new_bucket) {
+ preempt_enable();
+ return stackid_install(&stackid, map, new_bucket, flags);
+ }
+ err = -ENOMEM;
- return stackid_install(&stackid, map, new_bucket, flags);
+out:
+ preempt_enable();
+ return err;
}
const struct bpf_func_proto bpf_get_stackid_proto = {
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCHv2 bpf-next 06/11] bpf: Factor callchain_store function from __bpf_get_stack
2026-07-29 8:37 [PATCHv2 bpf-next 00/11] bpf: Disable preemption in stack map code Jiri Olsa
` (4 preceding siblings ...)
2026-07-29 8:38 ` [PATCHv2 bpf-next 05/11] bpf: Disable preemption in bpf_get_stackid Jiri Olsa
@ 2026-07-29 8:38 ` Jiri Olsa
2026-07-29 8:57 ` sashiko-bot
2026-07-29 8:38 ` [PATCHv2 bpf-next 07/11] bpf: Factor callchain_finalize " Jiri Olsa
` (4 subsequent siblings)
10 siblings, 1 reply; 16+ messages in thread
From: Jiri Olsa @ 2026-07-29 8:38 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: bpf, Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
Quentin Monnet, Tao Chen, STAR Labs SG, Arnaud Lecomte
The new callchain_store function stores trace entries buffer into
user supplied buffer. It covers both just-ip and buildid data.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
kernel/bpf/stackmap.c | 39 +++++++++++++++++++++++++--------------
1 file changed, 25 insertions(+), 14 deletions(-)
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index e48ddb4edd47..18b3db5c1fb9 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -746,6 +746,29 @@ const struct bpf_func_proto bpf_get_stackid_proto_pe = {
.arg3_type = ARG_ANYTHING,
};
+static u32 callchain_store(struct perf_callchain_entry *trace, void *buf,
+ u32 elem_size, u64 flags)
+{
+ bool user_build_id = flags & BPF_F_USER_BUILD_ID;
+ u32 skip = flags & BPF_F_SKIP_FIELD_MASK;
+ u32 trace_nr, copy_len;
+ u64 *ips;
+
+ trace_nr = trace->nr - skip;
+ copy_len = trace_nr * elem_size;
+
+ ips = trace->ip + skip;
+ if (user_build_id) {
+ struct bpf_stack_build_id *id_offs = buf;
+
+ for (u32 i = 0; i < trace_nr; i++)
+ id_offs[i].ip = ips[i];
+ } else {
+ memcpy(buf, ips, copy_len);
+ }
+ return trace_nr;
+}
+
static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
struct perf_callchain_entry *trace_in,
void *buf, u32 size, u64 flags, bool may_fault)
@@ -758,7 +781,6 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
struct perf_callchain_entry *trace;
bool kernel = !user;
int err = -EINVAL;
- u64 *ips;
if (unlikely(flags & ~(BPF_F_SKIP_FIELD_MASK | BPF_F_USER_STACK |
BPF_F_USER_BUILD_ID)))
@@ -803,21 +825,10 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
goto err_fault;
}
- trace_nr = trace->nr - skip;
+ trace_nr = callchain_store(trace, buf, elem_size, flags);
copy_len = trace_nr * elem_size;
- ips = trace->ip + skip;
- if (user_build_id) {
- struct bpf_stack_build_id *id_offs = buf;
- u32 i;
-
- for (i = 0; i < trace_nr; i++)
- id_offs[i].ip = ips[i];
- } else {
- memcpy(buf, ips, copy_len);
- }
-
- /* trace/ips should not be dereferenced after this point */
+ /* trace should not be dereferenced after this point */
if (may_fault)
rcu_read_unlock();
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCHv2 bpf-next 07/11] bpf: Factor callchain_finalize function from __bpf_get_stack
2026-07-29 8:37 [PATCHv2 bpf-next 00/11] bpf: Disable preemption in stack map code Jiri Olsa
` (5 preceding siblings ...)
2026-07-29 8:38 ` [PATCHv2 bpf-next 06/11] bpf: Factor callchain_store function from __bpf_get_stack Jiri Olsa
@ 2026-07-29 8:38 ` Jiri Olsa
2026-07-29 9:41 ` bot+bpf-ci
2026-07-29 8:38 ` [PATCHv2 bpf-next 08/11] bpf: Restore trace->nr value properly in bpf_get_stack_pe Jiri Olsa
` (3 subsequent siblings)
10 siblings, 1 reply; 16+ messages in thread
From: Jiri Olsa @ 2026-07-29 8:38 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: bpf, Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
Quentin Monnet, Tao Chen, STAR Labs SG, Arnaud Lecomte
The new callchain_finalize function calls the build-id retrieval
(if needed) and zeroes the buffer.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
kernel/bpf/stackmap.c | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index 18b3db5c1fb9..05269f2a9e08 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -769,16 +769,29 @@ static u32 callchain_store(struct perf_callchain_entry *trace, void *buf,
return trace_nr;
}
+static long callchain_finalize(void *buf, u32 size, u32 trace_nr, u32 elem_size,
+ bool user_build_id, bool user, bool may_fault)
+{
+ u32 copy_len = trace_nr * elem_size;
+
+ if (user_build_id)
+ stack_map_get_build_id_offset(buf, trace_nr, user, may_fault);
+
+ if (size > copy_len)
+ memset(buf + copy_len, 0, size - copy_len);
+ return copy_len;
+}
+
static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
struct perf_callchain_entry *trace_in,
void *buf, u32 size, u64 flags, bool may_fault)
{
- u32 trace_nr, copy_len, elem_size, max_depth;
bool user_build_id = flags & BPF_F_USER_BUILD_ID;
bool crosstask = task && task != current;
u32 skip = flags & BPF_F_SKIP_FIELD_MASK;
bool user = flags & BPF_F_USER_STACK;
struct perf_callchain_entry *trace;
+ u32 trace_nr, elem_size, max_depth;
bool kernel = !user;
int err = -EINVAL;
@@ -826,18 +839,12 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
}
trace_nr = callchain_store(trace, buf, elem_size, flags);
- copy_len = trace_nr * elem_size;
/* trace should not be dereferenced after this point */
if (may_fault)
rcu_read_unlock();
- if (user_build_id)
- stack_map_get_build_id_offset(buf, trace_nr, user, may_fault);
-
- if (size > copy_len)
- memset(buf + copy_len, 0, size - copy_len);
- return copy_len;
+ return callchain_finalize(buf, size, trace_nr, elem_size, user_build_id, user, may_fault);
err_fault:
err = -EFAULT;
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCHv2 bpf-next 08/11] bpf: Restore trace->nr value properly in bpf_get_stack_pe
2026-07-29 8:37 [PATCHv2 bpf-next 00/11] bpf: Disable preemption in stack map code Jiri Olsa
` (6 preceding siblings ...)
2026-07-29 8:38 ` [PATCHv2 bpf-next 07/11] bpf: Factor callchain_finalize " Jiri Olsa
@ 2026-07-29 8:38 ` Jiri Olsa
2026-07-29 8:38 ` [PATCHv2 bpf-next 09/11] bpf: Remove trace_in argument from __bpf_get_stack Jiri Olsa
` (2 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Jiri Olsa @ 2026-07-29 8:38 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: Sashiko, bpf, Martin KaFai Lau, Eduard Zingerman, Song Liu,
Yonghong Song, Quentin Monnet, Tao Chen, STAR Labs SG,
Arnaud Lecomte
In bpf_get_stack_pe The __bpf_get_stack call changes trace->nr value,
so both kernel and user path need to restore its value back.
Reported-by: Sashiko <sashiko-bot@kernel.org>
Fixes: e17d62fedd10 ("bpf: Refactor stack map trace depth calculation into helper function")
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
kernel/bpf/stackmap.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index 05269f2a9e08..875f530f3597 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -942,9 +942,9 @@ BPF_CALL_4(bpf_get_stack_pe, struct bpf_perf_event_data_kern *, ctx,
struct pt_regs *regs = (struct pt_regs *)(ctx->regs);
struct perf_event *event = ctx->event;
struct perf_callchain_entry *trace;
+ __u64 nr, nr_kernel;
bool kernel, user;
int err = -EINVAL;
- __u64 nr_kernel;
if (!(event->attr.sample_type & PERF_SAMPLE_CALLCHAIN))
return __bpf_get_stack(regs, NULL, NULL, buf, size, flags, false /* !may_fault */);
@@ -962,15 +962,12 @@ BPF_CALL_4(bpf_get_stack_pe, struct bpf_perf_event_data_kern *, ctx,
goto clear;
nr_kernel = count_kernel_ip(trace);
+ nr = trace->nr;
if (kernel) {
- __u64 nr = trace->nr;
-
trace->nr = nr_kernel;
err = __bpf_get_stack(regs, NULL, trace, buf, size, flags, false /* !may_fault */);
- /* restore nr */
- trace->nr = nr;
} else { /* user */
u64 skip = flags & BPF_F_SKIP_FIELD_MASK;
@@ -981,12 +978,13 @@ BPF_CALL_4(bpf_get_stack_pe, struct bpf_perf_event_data_kern *, ctx,
flags = (flags & ~BPF_F_SKIP_FIELD_MASK) | skip;
err = __bpf_get_stack(regs, NULL, trace, buf, size, flags, false /* !may_fault */);
}
- return err;
+ /* restore nr */
+ trace->nr = nr;
clear:
- memset(buf, 0, size);
+ if (err < 0)
+ memset(buf, 0, size);
return err;
-
}
const struct bpf_func_proto bpf_get_stack_proto_pe = {
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCHv2 bpf-next 09/11] bpf: Remove trace_in argument from __bpf_get_stack
2026-07-29 8:37 [PATCHv2 bpf-next 00/11] bpf: Disable preemption in stack map code Jiri Olsa
` (7 preceding siblings ...)
2026-07-29 8:38 ` [PATCHv2 bpf-next 08/11] bpf: Restore trace->nr value properly in bpf_get_stack_pe Jiri Olsa
@ 2026-07-29 8:38 ` Jiri Olsa
2026-07-29 8:38 ` [PATCHv2 bpf-next 10/11] bpf: Disable preemption in __bpf_get_stack Jiri Olsa
2026-07-29 8:38 ` [PATCHv2 bpf-next 11/11] bpf: Clear buf on error in __bpf_get_task_stack Jiri Olsa
10 siblings, 0 replies; 16+ messages in thread
From: Jiri Olsa @ 2026-07-29 8:38 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: bpf, Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
Quentin Monnet, Tao Chen, STAR Labs SG, Arnaud Lecomte
Now with the new callchain_* helper functions we can process trace_in
case directly in bpf_get_stack_pe function and remove it from
__bpf_get_stack which makes things easier for preemption fix in
following change.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
kernel/bpf/stackmap.c | 46 ++++++++++++++++++++++++++++++++-----------
1 file changed, 34 insertions(+), 12 deletions(-)
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index 875f530f3597..bdf48a7ad2e8 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -783,7 +783,6 @@ static long callchain_finalize(void *buf, u32 size, u32 trace_nr, u32 elem_size,
}
static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
- struct perf_callchain_entry *trace_in,
void *buf, u32 size, u64 flags, bool may_fault)
{
bool user_build_id = flags & BPF_F_USER_BUILD_ID;
@@ -822,10 +821,7 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
if (may_fault)
rcu_read_lock(); /* need RCU for perf's callchain below */
- if (trace_in) {
- trace = trace_in;
- trace->nr = min_t(u32, trace->nr, max_depth);
- } else if (kernel && task) {
+ if (kernel && task) {
trace = get_callchain_entry_for_task(task, max_depth);
} else {
trace = get_perf_callchain(regs, kernel, user, max_depth,
@@ -856,7 +852,7 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
BPF_CALL_4(bpf_get_stack, struct pt_regs *, regs, void *, buf, u32, size,
u64, flags)
{
- return __bpf_get_stack(regs, NULL, NULL, buf, size, flags, false /* !may_fault */);
+ return __bpf_get_stack(regs, NULL, buf, size, flags, false /* !may_fault */);
}
const struct bpf_func_proto bpf_get_stack_proto = {
@@ -872,7 +868,7 @@ const struct bpf_func_proto bpf_get_stack_proto = {
BPF_CALL_4(bpf_get_stack_sleepable, struct pt_regs *, regs, void *, buf, u32, size,
u64, flags)
{
- return __bpf_get_stack(regs, NULL, NULL, buf, size, flags, true /* may_fault */);
+ return __bpf_get_stack(regs, NULL, buf, size, flags, true /* may_fault */);
}
const struct bpf_func_proto bpf_get_stack_sleepable_proto = {
@@ -896,7 +892,7 @@ static long __bpf_get_task_stack(struct task_struct *task, void *buf, u32 size,
regs = task_pt_regs(task);
if (regs)
- res = __bpf_get_stack(regs, task, NULL, buf, size, flags, may_fault);
+ res = __bpf_get_stack(regs, task, buf, size, flags, may_fault);
put_task_stack(task);
return res;
@@ -936,6 +932,33 @@ const struct bpf_func_proto bpf_get_task_stack_sleepable_proto = {
.arg4_type = ARG_ANYTHING,
};
+static int __bpf_get_stack_pe(struct perf_callchain_entry *trace, void *buf, u32 size,
+ u64 flags)
+{
+ bool user_build_id = flags & BPF_F_USER_BUILD_ID;
+ u64 skip = flags & BPF_F_SKIP_FIELD_MASK;
+ bool user = flags & BPF_F_USER_STACK;
+ u32 elem_size, max_depth, nr_trace;
+ bool kernel = !user;
+
+ if (kernel && user_build_id)
+ return -EINVAL;
+
+ elem_size = user_build_id ? sizeof(struct bpf_stack_build_id) : sizeof(u64);
+ if (unlikely(size % elem_size))
+ return -EINVAL;
+
+ max_depth = stack_map_calculate_max_depth(size, elem_size, flags);
+ trace->nr = min_t(u32, trace->nr, max_depth);
+
+ if (trace->nr < skip)
+ return -EFAULT;
+
+ nr_trace = callchain_store(trace, buf, elem_size, flags);
+ return callchain_finalize(buf, size, nr_trace, elem_size, user_build_id,
+ user, false /* !may_fault */);
+}
+
BPF_CALL_4(bpf_get_stack_pe, struct bpf_perf_event_data_kern *, ctx,
void *, buf, u32, size, u64, flags)
{
@@ -947,7 +970,7 @@ BPF_CALL_4(bpf_get_stack_pe, struct bpf_perf_event_data_kern *, ctx,
int err = -EINVAL;
if (!(event->attr.sample_type & PERF_SAMPLE_CALLCHAIN))
- return __bpf_get_stack(regs, NULL, NULL, buf, size, flags, false /* !may_fault */);
+ return __bpf_get_stack(regs, NULL, buf, size, flags, false /* !may_fault */);
if (unlikely(flags & ~(BPF_F_SKIP_FIELD_MASK | BPF_F_USER_STACK |
BPF_F_USER_BUILD_ID)))
@@ -966,7 +989,7 @@ BPF_CALL_4(bpf_get_stack_pe, struct bpf_perf_event_data_kern *, ctx,
if (kernel) {
trace->nr = nr_kernel;
- err = __bpf_get_stack(regs, NULL, trace, buf, size, flags, false /* !may_fault */);
+ err = __bpf_get_stack_pe(trace, buf, size, flags);
} else { /* user */
u64 skip = flags & BPF_F_SKIP_FIELD_MASK;
@@ -974,9 +997,8 @@ BPF_CALL_4(bpf_get_stack_pe, struct bpf_perf_event_data_kern *, ctx,
skip += nr_kernel;
if (skip > BPF_F_SKIP_FIELD_MASK)
goto clear;
-
flags = (flags & ~BPF_F_SKIP_FIELD_MASK) | skip;
- err = __bpf_get_stack(regs, NULL, trace, buf, size, flags, false /* !may_fault */);
+ err = __bpf_get_stack_pe(trace, buf, size, flags);
}
/* restore nr */
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCHv2 bpf-next 10/11] bpf: Disable preemption in __bpf_get_stack
2026-07-29 8:37 [PATCHv2 bpf-next 00/11] bpf: Disable preemption in stack map code Jiri Olsa
` (8 preceding siblings ...)
2026-07-29 8:38 ` [PATCHv2 bpf-next 09/11] bpf: Remove trace_in argument from __bpf_get_stack Jiri Olsa
@ 2026-07-29 8:38 ` Jiri Olsa
2026-07-29 8:38 ` [PATCHv2 bpf-next 11/11] bpf: Clear buf on error in __bpf_get_task_stack Jiri Olsa
10 siblings, 0 replies; 16+ messages in thread
From: Jiri Olsa @ 2026-07-29 8:38 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: stable, Tao Chen, STAR Labs SG, bpf, Martin KaFai Lau,
Eduard Zingerman, Song Liu, Yonghong Song, Quentin Monnet,
Arnaud Lecomte
From: Daniel Borkmann <borkmann@iogearbox.net>
get_perf_callchain() returns a per-CPU perf_callchain_entry buffer and
releases its recursion slot via put_callchain_entry() before returning,
so nothing keeps the entry reserved while __bpf_get_stack() consumes
it below.
A preemptible BPF program (e.g. a non-sleepable raw tracepoint program
on a PREEMPT kernel, which runs under migrate_disable() but not
preempt_disable()) can be scheduled out between obtaining the entry
and the copy. Another task scheduled on the same CPU then reuses the
same per-CPU buffer and overwrites trace->nr with a larger value.
copy_len is then computed from the inflated trace->nr and can exceed
the caller's buffer, causing an out-of-bounds write in the memcpy()
and in the build_id path.
The rcu_read_lock() taken here alone does not prevent this. It is
only taken on the may_fault path, and under CONFIG_PREEMPT_RCU it does
not disable preemption; it merely keeps perf's callchain buffer array
alive (freed via call_rcu()) and does nothing to stop another task
from reusing the entry.
Disable preemption around obtaining the callchain entry and copying
it into the caller's buffer, so the entry cannot be reused underneath
us and trace->nr stays bounded by max_depth. Build ID resolution may
fault and is therefore deferred until after preemption is re-enabled;
by then the instruction pointers have already been copied into buf,
so it operates only on that private copy. Note, preempt_disable() also
subsumes the buffer-lifetime guarantee the rcu_read_lock() provided,
since a preempt-disabled section is an RCU read-side critical section
for the callchain buffers' call_rcu() reclaim.
Cc: stable@vger.kernel.org
Fixes: c195651e565a ("bpf: add bpf_get_stack helper")
Reported-by: Tao Chen <chen.dylane@linux.dev>
Closes: https://lore.kernel.org/bpf/20260206090653.1336687-1-chen.dylane@linux.dev/
Reported-by: STAR Labs SG <info@starlabs.sg>
Signed-off-by: Daniel Borkmann <borkmann@iogearbox.net>
[ changed Fixes: commit ]
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
kernel/bpf/stackmap.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index bdf48a7ad2e8..f4827afbfed9 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -820,6 +820,7 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
if (may_fault)
rcu_read_lock(); /* need RCU for perf's callchain below */
+ preempt_disable();
if (kernel && task) {
trace = get_callchain_entry_for_task(task, max_depth);
@@ -831,6 +832,7 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
if (unlikely(!trace) || trace->nr < skip) {
if (may_fault)
rcu_read_unlock();
+ preempt_enable();
goto err_fault;
}
@@ -839,6 +841,7 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
/* trace should not be dereferenced after this point */
if (may_fault)
rcu_read_unlock();
+ preempt_enable();
return callchain_finalize(buf, size, trace_nr, elem_size, user_build_id, user, may_fault);
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCHv2 bpf-next 11/11] bpf: Clear buf on error in __bpf_get_task_stack
2026-07-29 8:37 [PATCHv2 bpf-next 00/11] bpf: Disable preemption in stack map code Jiri Olsa
` (9 preceding siblings ...)
2026-07-29 8:38 ` [PATCHv2 bpf-next 10/11] bpf: Disable preemption in __bpf_get_stack Jiri Olsa
@ 2026-07-29 8:38 ` Jiri Olsa
10 siblings, 0 replies; 16+ messages in thread
From: Jiri Olsa @ 2026-07-29 8:38 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: Sashiko, bpf, Martin KaFai Lau, Eduard Zingerman, Song Liu,
Yonghong Song, Quentin Monnet, Tao Chen, STAR Labs SG,
Arnaud Lecomte
Both bpf_get_task_stack and bpf_get_task_stack helpers that use
__bpf_get_task_stack have buf defined as ARG_PTR_TO_UNINIT_MEM
argument, and we should initialize the buf on every return path.
Adding missing buf memset for __bpf_get_task_stack fail paths.
The __bpf_get_stack call does clear the buf properly.
Fixes: 06ab134ce8ec ("bpf: Refcount task stack in bpf_get_task_stack")
Fixes: b992f01e6615 ("bpf: Guard against accessing NULL pt_regs in bpf_get_task_stack()")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
kernel/bpf/stackmap.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index f4827afbfed9..9ab0c2523a41 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -890,14 +890,17 @@ static long __bpf_get_task_stack(struct task_struct *task, void *buf, u32 size,
struct pt_regs *regs;
long res = -EINVAL;
- if (!try_get_task_stack(task))
+ if (!try_get_task_stack(task)) {
+ memset(buf, 0, size);
return -EFAULT;
+ }
regs = task_pt_regs(task);
if (regs)
res = __bpf_get_stack(regs, task, buf, size, flags, may_fault);
+ else
+ memset(buf, 0, size);
put_task_stack(task);
-
return res;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCHv2 bpf-next 01/11] bpf: Factor stackid_init function from __bpf_get_stackid
2026-07-29 8:37 ` [PATCHv2 bpf-next 01/11] bpf: Factor stackid_init function from __bpf_get_stackid Jiri Olsa
@ 2026-07-29 8:51 ` sashiko-bot
0 siblings, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-07-29 8:51 UTC (permalink / raw)
To: Jiri Olsa; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] A TOCTOU race with `sysctl_perf_event_max_stack` causes an integer underflow in the `max_depth - skip` calculation, leading to a massive heap buffer overflow when copying stack traces.
--
--- Patch [1]: [PATCHv2 bpf-next 01/11] bpf: Factor stackid_init function from __bpf_get_stackid ---
commit 94626e7c900d701c2d2326e06f48ebc28e1f6e93
Author: Jiri Olsa <jolsa@kernel.org>
bpf: Factor stackid_init function from __bpf_get_stackid
The new stackid_init function stores all the necessary bits for stackid
trace and it will be used by other functions in following changes.
> diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
> index 41fe87d7302f2..0eafe55b18289 100644
> --- a/kernel/bpf/stackmap.c
> +++ b/kernel/bpf/stackmap.c
> @@ -504,33 +504,54 @@ get_callchain_entry_for_task(struct task_struct *task, u32 max_depth)
[ ... ]
> +static int stackid_init(struct stackid *stackid, struct bpf_map *map,
> + struct perf_callchain_entry *trace, u64 flags)
> {
> struct bpf_stack_map *smap = container_of(map, struct bpf_stack_map, map);
> - struct stack_map_bucket *bucket, *new_bucket, *old_bucket;
> - u32 hash, id, trace_nr, trace_len, i, max_depth;
> u32 skip = flags & BPF_F_SKIP_FIELD_MASK;
> - bool user = flags & BPF_F_USER_STACK;
> - u64 *ips;
> - bool hash_matches;
> + u32 max_depth;
>
> if (trace->nr <= skip)
> /* skipping more than usable stack trace */
> return -EFAULT;
>
> max_depth = stack_map_calculate_max_depth(map->value_size, stack_map_data_size(map), flags);
> - trace_nr = min_t(u32, trace->nr - skip, max_depth - skip);
> - trace_len = trace_nr * sizeof(u64);
> - ips = trace->ip + skip;
> - hash = jhash2((u32 *)ips, trace_len / sizeof(u32), 0);
> - id = hash & (smap->n_buckets - 1);
> - bucket = READ_ONCE(smap->buckets[id]);
> + stackid->nr = min_t(u32, trace->nr - skip, max_depth - skip);
[Severity: High]
This is a pre-existing issue, but can this max_depth - skip calculation
underflow?
If a BPF program is attached to a perf event using bpf_get_stackid_pe(),
the callchain is generated using the current sysctl_perf_event_max_stack
limit. If an administrator concurrently reduces sysctl_perf_event_max_stack to
a value smaller than the skip parameter, stack_map_calculate_max_depth()
clamps max_depth to this new smaller sysctl value:
kernel/bpf/stackmap.c:stack_map_calculate_max_depth() {
...
u32 curr_sysctl_max_stack = READ_ONCE(sysctl_perf_event_max_stack);
...
if (max_depth > curr_sysctl_max_stack)
return curr_sysctl_max_stack;
return max_depth;
}
This would cause max_depth - skip to underflow into a huge u32 value. Since
min_t() is used with u32, a large trace->nr - skip could be selected, which
might exceed the stackmap bucket capacity and lead to a heap buffer overflow
when copying the stack trace later in __bpf_get_stackid():
memcpy(new_bucket->data, stackid->ips, stackid->len);
Does this sequence need to be protected against sysctl changes between trace
gathering and max_depth calculation?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260729083807.1588544-2-jolsa@kernel.org?part=1
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCHv2 bpf-next 06/11] bpf: Factor callchain_store function from __bpf_get_stack
2026-07-29 8:38 ` [PATCHv2 bpf-next 06/11] bpf: Factor callchain_store function from __bpf_get_stack Jiri Olsa
@ 2026-07-29 8:57 ` sashiko-bot
0 siblings, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-07-29 8:57 UTC (permalink / raw)
To: Jiri Olsa; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [Critical] Preemption can cause `trace->nr` to be modified concurrently, leading to an integer underflow in `trace_nr = trace->nr - skip` and a massive out-of-bounds `memcpy`.
--
--- Patch [1]: [PATCHv2 bpf-next 06/11] bpf: Factor callchain_store function from __bpf_get_stack ---
commit 41f5133836d848295ac407c006940d4f0641b50f
Author: Jiri Olsa <jolsa@kernel.org>
bpf: Factor callchain_store function from __bpf_get_stack
This commit factors out the callchain storage logic from __bpf_get_stack
into a new callchain_store function. The new function handles both IP and
build ID data copying.
> diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
> index 41fe87d7302f2..18d1a10bf76e5 100644
> --- a/kernel/bpf/stackmap.c
> +++ b/kernel/bpf/stackmap.c
> @@ -680,6 +680,29 @@ const struct bpf_func_proto bpf_get_stackid_proto_pe = {
> .arg3_type = ARG_ANYTHING,
> };
>
> +static u32 callchain_store(struct perf_callchain_entry *trace, void *buf,
> + u32 elem_size, u64 flags)
> +{
> + bool user_build_id = flags & BPF_F_USER_BUILD_ID;
> + u32 skip = flags & BPF_F_SKIP_FIELD_MASK;
> + u32 trace_nr, copy_len;
> + u64 *ips;
> +
> + trace_nr = trace->nr - skip;
[Severity: Critical]
This is a pre-existing issue, but could this calculation underflow if
trace->nr is modified concurrently?
Looking at __bpf_get_stack(), when called from a sleepable BPF program via
bpf_get_stack_sleepable(), it calls get_perf_callchain(). This allocates
a per-CPU recursion buffer but unpins it by calling put_callchain_entry()
before returning.
__bpf_get_stack() then checks if trace->nr is less than skip:
if (unlikely(!trace) || trace->nr < skip) {
if (may_fault)
rcu_read_unlock();
goto err_fault;
}
If the task is preempted immediately after this check (which is possible for
sleepable BPF programs under CONFIG_PREEMPT_RCU, as rcu_read_lock() does not
prevent preemption), could a new task on the same CPU trigger a BPF program
that reacquires the same level-0 recursion buffer and overwrites trace->nr
to 0?
When the original task resumes and calls callchain_store(), it re-reads
trace->nr. If it is now 0, wouldn't 0 - skip underflow to a massive unsigned
value?
> + copy_len = trace_nr * elem_size;
> +
> + ips = trace->ip + skip;
> + if (user_build_id) {
> + struct bpf_stack_build_id *id_offs = buf;
> +
> + for (u32 i = 0; i < trace_nr; i++)
> + id_offs[i].ip = ips[i];
> + } else {
> + memcpy(buf, ips, copy_len);
If the underflow occurs, would this result in a massive out-of-bounds memcpy
that could overwrite the BPF stack buffer or map value and cause memory
corruption?
> + }
> + return trace_nr;
> +}
> +
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260729083807.1588544-7-jolsa@kernel.org?part=1
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCHv2 bpf-next 07/11] bpf: Factor callchain_finalize function from __bpf_get_stack
2026-07-29 8:38 ` [PATCHv2 bpf-next 07/11] bpf: Factor callchain_finalize " Jiri Olsa
@ 2026-07-29 9:41 ` bot+bpf-ci
0 siblings, 0 replies; 16+ messages in thread
From: bot+bpf-ci @ 2026-07-29 9:41 UTC (permalink / raw)
To: jolsa, ast, daniel, andrii
Cc: bpf, martin.lau, eddyz87, songliubraving, yhs, qmo, chen.dylane,
info, contact, ast, andrii, daniel, martin.lau, eddyz87,
yonghong.song, clm, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 3655 bytes --]
> diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
> index 18b3db5c1fb9f..05269f2a9e085 100644
> --- a/kernel/bpf/stackmap.c
> +++ b/kernel/bpf/stackmap.c
> @@ -769,16 +769,29 @@ static u32 callchain_store(struct perf_callchain_entry *trace, void *buf,
> return trace_nr;
> }
>
> +static long callchain_finalize(void *buf, u32 size, u32 trace_nr, u32 elem_size,
> + bool user_build_id, bool user, bool may_fault)
> +{
> + u32 copy_len = trace_nr * elem_size;
> +
> + if (user_build_id)
> + stack_map_get_build_id_offset(buf, trace_nr, user, may_fault);
> +
> + if (size > copy_len)
> + memset(buf + copy_len, 0, size - copy_len);
> + return copy_len;
> +}
This isn't a bug, but would it read better if callchain_finalize took the
raw flags the way callchain_store does, deriving user_build_id, user, and
elem_size internally?
The new helper takes seven positional parameters, three of which are
adjacent bools (user_build_id, user, may_fault) that could be transposed
at the call site without the compiler catching it. Two of the parameters
are also derivable: elem_size is exactly sizeof(struct bpf_stack_build_id)
or sizeof(u64) depending on user_build_id, and both user_build_id and user
come straight out of flags.
The sibling helper factored one commit earlier, callchain_store(), takes
the raw u64 flags and decodes user_build_id and skip itself, so the two
new helpers in the same series decode flags in opposite directions.
[ ... ]
> static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
> struct perf_callchain_entry *trace_in,
> void *buf, u32 size, u64 flags, bool may_fault)
> {
> - u32 trace_nr, copy_len, elem_size, max_depth;
> bool user_build_id = flags & BPF_F_USER_BUILD_ID;
> bool crosstask = task && task != current;
> u32 skip = flags & BPF_F_SKIP_FIELD_MASK;
> bool user = flags & BPF_F_USER_STACK;
> struct perf_callchain_entry *trace;
> + u32 trace_nr, elem_size, max_depth;
> bool kernel = !user;
> int err = -EINVAL;
>
> @@ -826,18 +839,12 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
> }
>
> trace_nr = callchain_store(trace, buf, elem_size, flags);
> - copy_len = trace_nr * elem_size;
>
> /* trace should not be dereferenced after this point */
> if (may_fault)
> rcu_read_unlock();
>
> - if (user_build_id)
> - stack_map_get_build_id_offset(buf, trace_nr, user, may_fault);
> -
> - if (size > copy_len)
> - memset(buf + copy_len, 0, size - copy_len);
> - return copy_len;
> + return callchain_finalize(buf, size, trace_nr, elem_size, user_build_id, user, may_fault);
>
> err_fault:
> err = -EFAULT;
This isn't a bug, but could the changelog mention that this is preparation
for moving the faultable build-id work out of the preempt-disabled section
later in the series?
The commit message says:
> bpf: Factor callchain_finalize function from __bpf_get_stack
>
> The new callchain_finalize function calls the build-id retrieval
> (if needed) and zeroes the buffer.
It restates what the new function body does but not why the factoring is
wanted, and does not state that no functional change is intended. The later
commit in the same series does spell out its motivation ("makes things
easier for preemption fix in following change"), and the preemption fix
does depend on callchain_finalize sitting outside the preempt-disabled
region.
---
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/30437558115
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCHv2 bpf-next 04/11] bpf: Use stack id functions instead of __bpf_get_stackid
2026-07-29 8:38 ` [PATCHv2 bpf-next 04/11] bpf: Use stack id functions instead of __bpf_get_stackid Jiri Olsa
@ 2026-07-29 9:42 ` bot+bpf-ci
0 siblings, 0 replies; 16+ messages in thread
From: bot+bpf-ci @ 2026-07-29 9:42 UTC (permalink / raw)
To: jolsa, ast, daniel, andrii
Cc: bpf, martin.lau, eddyz87, songliubraving, yhs, qmo, chen.dylane,
info, contact, ast, andrii, daniel, martin.lau, eddyz87,
yonghong.song, clm, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 2042 bytes --]
> diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
> index 366195b08c79a..43b1e5436047d 100644
> --- a/kernel/bpf/stackmap.c
> +++ b/kernel/bpf/stackmap.c
[ ... ]
> @@ -674,6 +675,7 @@ BPF_CALL_3(bpf_get_stackid_pe, struct bpf_perf_event_data_kern *, ctx,
> struct bpf_map *, map, u64, flags)
> {
> struct perf_event *event = ctx->event;
> + struct stack_map_bucket *new_bucket;
> struct perf_callchain_entry *trace;
> struct stackid stackid;
> bool kernel, user;
> @@ -701,7 +703,6 @@ BPF_CALL_3(bpf_get_stackid_pe, struct bpf_perf_event_data_kern *, ctx,
>
> if (kernel) {
> trace->nr = nr_kernel;
> - ret = __bpf_get_stackid(&stackid, map, trace, flags);
> } else { /* user */
> u64 skip = flags & BPF_F_SKIP_FIELD_MASK;
>
> @@ -710,12 +711,22 @@ BPF_CALL_3(bpf_get_stackid_pe, struct bpf_perf_event_data_kern *, ctx,
> return -EFAULT;
>
> flags = (flags & ~BPF_F_SKIP_FIELD_MASK) | skip;
> - ret = __bpf_get_stackid(&stackid, map, trace, flags);
> }
>
> + ret = stackid_fastpath(&stackid, map, trace, flags);
> + if (ret != -ENOENT)
> + goto error;
> +
> + new_bucket = stackid_new_bucket(&stackid, map);
> + if (new_bucket) {
> + trace->nr = nr;
> + return stackid_install(&stackid, map, new_bucket, flags);
> + }
> + ret = -ENOMEM;
> +
> +error:
> /* restore nr */
> trace->nr = nr;
> -
> return ret;
> }
This isn't a bug, but since the goto error label is reached when
stackid_fastpath() succeeds and returns a valid stack id, would out: read
better here? The next patch in the series uses out: for the same pattern
in bpf_get_stackid().
Also, stackid_install() doesn't look at trace, so could the trace->nr = nr
restoration be done in just one place? Right now it appears both inside
the if (new_bucket) branch and under the label.
---
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/30437558115
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-07-29 9:42 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-29 8:37 [PATCHv2 bpf-next 00/11] bpf: Disable preemption in stack map code Jiri Olsa
2026-07-29 8:37 ` [PATCHv2 bpf-next 01/11] bpf: Factor stackid_init function from __bpf_get_stackid Jiri Olsa
2026-07-29 8:51 ` sashiko-bot
2026-07-29 8:37 ` [PATCHv2 bpf-next 02/11] bpf: Factor stackid_fastpath " Jiri Olsa
2026-07-29 8:37 ` [PATCHv2 bpf-next 03/11] bpf: Factor stackid_new_bucket " Jiri Olsa
2026-07-29 8:38 ` [PATCHv2 bpf-next 04/11] bpf: Use stack id functions instead of __bpf_get_stackid Jiri Olsa
2026-07-29 9:42 ` bot+bpf-ci
2026-07-29 8:38 ` [PATCHv2 bpf-next 05/11] bpf: Disable preemption in bpf_get_stackid Jiri Olsa
2026-07-29 8:38 ` [PATCHv2 bpf-next 06/11] bpf: Factor callchain_store function from __bpf_get_stack Jiri Olsa
2026-07-29 8:57 ` sashiko-bot
2026-07-29 8:38 ` [PATCHv2 bpf-next 07/11] bpf: Factor callchain_finalize " Jiri Olsa
2026-07-29 9:41 ` bot+bpf-ci
2026-07-29 8:38 ` [PATCHv2 bpf-next 08/11] bpf: Restore trace->nr value properly in bpf_get_stack_pe Jiri Olsa
2026-07-29 8:38 ` [PATCHv2 bpf-next 09/11] bpf: Remove trace_in argument from __bpf_get_stack Jiri Olsa
2026-07-29 8:38 ` [PATCHv2 bpf-next 10/11] bpf: Disable preemption in __bpf_get_stack Jiri Olsa
2026-07-29 8:38 ` [PATCHv2 bpf-next 11/11] bpf: Clear buf on error in __bpf_get_task_stack Jiri Olsa
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox