FAILED: patch "[PATCH] bpf: Disable preemption in bpf_get_stackid" failed to apply to 6.18-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 6.18-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.18.y
git checkout FETCH_HEAD
git cherry-pick -x 15f1bd8574662f1b7b26aaa2e23ebf4066f0117d
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026090347-bodacious-studio-93ee@gregkh' --subject-prefix 'PATCH 6.18.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 15f1bd8574662f1b7b26aaa2e23ebf4066f0117d Mon Sep 17 00:00:00 2001
From: Jiri Olsa <[email protected]>
Date: Mon, 3 Aug 2026 23:01:42 +0200
Subject: [PATCH] bpf: Disable preemption in bpf_get_stackid
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.
kernel/bpf/stackmap.c +13 -11
@@ -632,20 +632,22 @@ BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, struct bpf_map *, map,return -EINVAL ; max_depth =stack_map_calculate_max_depth (map->value_size, elem_size, flags); - trace =get_perf_callchain (regs, kernel, user, max_depth, - false, false,0 ); -if (unlikely (!trace)) -/* couldn't fetch the stack trace */ -return -EFAULT ; +scoped_guard (preempt) { + trace =get_perf_callchain (regs, kernel, user, max_depth, + false, false,0 ); +if (unlikely (!trace)) +/* couldn't fetch the stack trace */ +return -EFAULT ; - err =stackid_fastpath (&stackid, map, trace, flags); -if (err != -ENOENT ) -return 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 ; + new_bucket =stackid_new_bucket (&stackid, map); +if (!new_bucket) +return -ENOMEM ; + }return stackid_install (&stackid, map, new_bucket, flags); }
Sasha Levin
maintainerPATCH 1/5 bpf: Factor stackid_init function from __bpf_get_stackid
From: Jiri Olsa <[email protected]>
[ Upstream commit 15b837759a97237d647962f9943afe0d55af615a ]
The new stackid_init function stores all the necessary bits for stackid trace and it will be used by other functions in following changes.
Stable-dep-of: 15f1bd857466 ("bpf: Disable preemption in bpf_get_stackid")
--- kernel/bpf/stackmap.c | 95 +++++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 36 deletions(-)
kernel/bpf/stackmap.c +59 -36
@@ -246,33 +246,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;
@@ -282,42 +303,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,
@@ -326,6 +347,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;
@@ -341,7 +363,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 = {
@@ -370,6 +392,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;
@@ -395,7 +418,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 ;
@@ -404,7 +427,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 */
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/5 bpf: Factor stackid_fastpath function from __bpf_get_stackid
From: Jiri Olsa <[email protected]>
[ Upstream commit 0ca56befcffec3a6c9d1842eae06c74e1cf41f11 ]
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.
Stable-dep-of: 15f1bd857466 ("bpf: Disable preemption in bpf_get_stackid")
--- kernel/bpf/stackmap.c | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-)
kernel/bpf/stackmap.c +28 -15
@@ -253,6 +253,7 @@ struct stackid {u32 len;u32 hash;u32 id; +bool hash_matches; }; static int stackid_init(struct stackid *stackid, struct bpf_map *map,
@@ -273,28 +274,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;
@@ -309,7 +328,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;
@@ -319,12 +338,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))
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/5 bpf: Factor stackid_new_bucket from __bpf_get_stackid
In reply to Sasha LevinFrom: Jiri Olsa <[email protected]>
[ Upstream commit bb4e6f4e1b68fe60c04ca04c564c6624e837dbf4 ]
The new stackid_new_bucket allocates the new bucket and initializes it with the trace data.
Stable-dep-of: 15f1bd857466 ("bpf: Disable preemption in bpf_get_stackid")
--- kernel/bpf/stackmap.c | 48 +++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 18 deletions(-)
kernel/bpf/stackmap.c +30 -18
@@ -301,31 +301,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 &&
@@ -337,17 +358,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);
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 4/5 bpf: Use stack id functions instead of __bpf_get_stackid
In reply to Sasha LevinFrom: Jiri Olsa <[email protected]>
[ Upstream commit 09b3fd6caa0b57f8a39254ee5db3af30bdd53c18 ]
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.
Stable-dep-of: 15f1bd857466 ("bpf: Disable preemption in bpf_get_stackid")
--- kernel/bpf/stackmap.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-)
kernel/bpf/stackmap.c +27 -16
@@ -326,22 +326,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;
@@ -371,10 +362,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 )))
@@ -388,7 +381,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 = {
@@ -416,6 +417,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;
@@ -443,7 +445,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 ;
@@ -452,12 +453,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 out; + + new_bucket =stackid_new_bucket (&stackid, map); +if (new_bucket) { + trace->nr = nr; +return stackid_install (&stackid, map, new_bucket, flags); + } + ret = -ENOMEM ; + +out:/* restore nr */ trace->nr = nr; -return ret; }
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 5/5 bpf: Disable preemption in bpf_get_stackid
In reply to Sasha LevinFrom: Jiri Olsa <[email protected]>
[ Upstream commit 15f1bd8574662f1b7b26aaa2e23ebf4066f0117d ]
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.
--- kernel/bpf/stackmap.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-)
kernel/bpf/stackmap.c +13 -11
@@ -374,20 +374,22 @@ BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, struct bpf_map *, map,return -EINVAL ; max_depth =stack_map_calculate_max_depth (map->value_size, elem_size, flags); - trace =get_perf_callchain (regs, kernel, user, max_depth, - false, false); -if (unlikely (!trace)) -/* couldn't fetch the stack trace */ -return -EFAULT ; +scoped_guard (preempt) { + trace =get_perf_callchain (regs, kernel, user, max_depth, + false, false); +if (unlikely (!trace)) +/* couldn't fetch the stack trace */ +return -EFAULT ; - err =stackid_fastpath (&stackid, map, trace, flags); -if (err != -ENOENT ) -return 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 ; + new_bucket =stackid_new_bucket (&stackid, map); +if (!new_bucket) +return -ENOMEM ; + }return stackid_install (&stackid, map, new_bucket, flags); }
Signature · 1 line
2.53.0