Skip to content

Commit e2d072d

Browse files
author
Alexei Starovoitov
committed
Merge branch 'fix-bpf_link-grace-period-wait-for-tracepoints'
Kumar Kartikeya Dwivedi says: ==================== Fix bpf_link grace period wait for tracepoints A recent change to non-faultable tracepoints switched from preempt-disabled critical sections to SRCU-fast, which breaks assumptions in the bpf_link_free() path. Use call_srcu() to fix the breakage. Changelog: ---------- v3 -> v4 v3: https://lore.kernel.org/bpf/20260331005215.2813492-1-memxor@gmail.com * Introduce call_tracepoint_unregister_{atomic,syscall} instead. (Alexei, Steven) v2 -> v3 v2: https://lore.kernel.org/bpf/20260330143102.1265391-1-memxor@gmail.com * Introduce and switch to call_tracepoint_unregister_non_faultable(). (Steven) * Address Andrii's comment and add Acked-by. (Andrii) * Drop rcu_trace_implies_rcu_gp() conversion. (Alexei) v1 -> v2 v1: https://lore.kernel.org/bpf/20260330032124.3141001-1-memxor@gmail.com * Add Reviewed-by tags. (Paul, Puranjay) * Adjust commit descriptions and comments to clarify intent. (Puranjay) ==================== Link: https://patch.msgid.link/20260331211021.1632902-1-memxor@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2 parents a8502a7 + c76fef7 commit e2d072d

3 files changed

Lines changed: 47 additions & 2 deletions

File tree

include/linux/bpf.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,6 +1854,10 @@ struct bpf_link_ops {
18541854
* target hook is sleepable, we'll go through tasks trace RCU GP and
18551855
* then "classic" RCU GP; this need for chaining tasks trace and
18561856
* classic RCU GPs is designated by setting bpf_link->sleepable flag
1857+
*
1858+
* For non-sleepable tracepoint links we go through SRCU gp instead,
1859+
* since RCU is not used in that case. Sleepable tracepoints still
1860+
* follow the scheme above.
18571861
*/
18581862
void (*dealloc_deferred)(struct bpf_link *link);
18591863
int (*detach)(struct bpf_link *link);

include/linux/tracepoint.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,33 @@ static inline bool tracepoint_is_faultable(struct tracepoint *tp)
122122
{
123123
return tp->ext && tp->ext->faultable;
124124
}
125+
/*
126+
* Run RCU callback with the appropriate grace period wait for non-faultable
127+
* tracepoints, e.g., those used in atomic context.
128+
*/
129+
static inline void call_tracepoint_unregister_atomic(struct rcu_head *rcu, rcu_callback_t func)
130+
{
131+
call_srcu(&tracepoint_srcu, rcu, func);
132+
}
133+
/*
134+
* Run RCU callback with the appropriate grace period wait for faultable
135+
* tracepoints, e.g., those used in syscall context.
136+
*/
137+
static inline void call_tracepoint_unregister_syscall(struct rcu_head *rcu, rcu_callback_t func)
138+
{
139+
call_rcu_tasks_trace(rcu, func);
140+
}
125141
#else
126142
static inline void tracepoint_synchronize_unregister(void)
127143
{ }
128144
static inline bool tracepoint_is_faultable(struct tracepoint *tp)
129145
{
130146
return false;
131147
}
148+
static inline void call_tracepoint_unregister_atomic(struct rcu_head *rcu, rcu_callback_t func)
149+
{ }
150+
static inline void call_tracepoint_unregister_syscall(struct rcu_head *rcu, rcu_callback_t func)
151+
{ }
132152
#endif
133153

134154
#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS

kernel/bpf/syscall.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3261,6 +3261,18 @@ static void bpf_link_defer_dealloc_rcu_gp(struct rcu_head *rcu)
32613261
bpf_link_dealloc(link);
32623262
}
32633263

3264+
static bool bpf_link_is_tracepoint(struct bpf_link *link)
3265+
{
3266+
/*
3267+
* Only these combinations support a tracepoint bpf_link.
3268+
* BPF_LINK_TYPE_TRACING raw_tp progs are hardcoded to use
3269+
* bpf_raw_tp_link_lops and thus dealloc_deferred(), see
3270+
* bpf_raw_tp_link_attach().
3271+
*/
3272+
return link->type == BPF_LINK_TYPE_RAW_TRACEPOINT ||
3273+
(link->type == BPF_LINK_TYPE_TRACING && link->attach_type == BPF_TRACE_RAW_TP);
3274+
}
3275+
32643276
static void bpf_link_defer_dealloc_mult_rcu_gp(struct rcu_head *rcu)
32653277
{
32663278
if (rcu_trace_implies_rcu_gp())
@@ -3279,16 +3291,25 @@ static void bpf_link_free(struct bpf_link *link)
32793291
if (link->prog)
32803292
ops->release(link);
32813293
if (ops->dealloc_deferred) {
3282-
/* Schedule BPF link deallocation, which will only then
3294+
/*
3295+
* Schedule BPF link deallocation, which will only then
32833296
* trigger putting BPF program refcount.
32843297
* If underlying BPF program is sleepable or BPF link's target
32853298
* attach hookpoint is sleepable or otherwise requires RCU GPs
32863299
* to ensure link and its underlying BPF program is not
32873300
* reachable anymore, we need to first wait for RCU tasks
3288-
* trace sync, and then go through "classic" RCU grace period
3301+
* trace sync, and then go through "classic" RCU grace period.
3302+
*
3303+
* For tracepoint BPF links, we need to go through SRCU grace
3304+
* period wait instead when non-faultable tracepoint is used. We
3305+
* don't need to chain SRCU grace period waits, however, for the
3306+
* faultable case, since it exclusively uses RCU Tasks Trace.
32893307
*/
32903308
if (link->sleepable || (link->prog && link->prog->sleepable))
32913309
call_rcu_tasks_trace(&link->rcu, bpf_link_defer_dealloc_mult_rcu_gp);
3310+
/* We need to do a SRCU grace period wait for non-faultable tracepoint BPF links. */
3311+
else if (bpf_link_is_tracepoint(link))
3312+
call_tracepoint_unregister_atomic(&link->rcu, bpf_link_defer_dealloc_rcu_gp);
32923313
else
32933314
call_rcu(&link->rcu, bpf_link_defer_dealloc_rcu_gp);
32943315
} else if (ops->dealloc) {

0 commit comments

Comments
 (0)