scx_layered: Work around older kernels choking on function calls from sleepable progs

Verifier in older kernels choke on function calls from sleepable progs
triggering non-sensical RCU state error:

   frame1: R1_w=scalar(id=674,smin=smin32=0,smax=umax=smax32=umax32=51,var_off=(0x0; 0x3f)) R10=; return *llc_ptr;
  1072: (61) r0 = *(u32 *)(r2 +0)       ; frame1: R0_w=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff)) R2_w=map_value(map=bpf_bpf.rodata,ks=4,vs=9570,off=4400,smin=smin32=0,smax=umax=smax32=umax32=204,var_off=(0x0; 0xfc)) refs=13,647
  ; }
  1073: (95) exit
  bpf_rcu_read_unlock is missing
  processed 10663 insns (limit 1000000) max_states_per_insn 8 total_states 615 peak_states 281 mark_read 20
  -- END PROG LOAD LOG --

Work around by adding and using __always_inline variant of cpu_to_llc_id()
from layered_init(). Note that we can't switch everyone to __always_inline
as that can lead to verification failure due to ins limit.
This commit is contained in:
Tejun Heo 2024-11-08 08:47:57 -10:00
parent 5280206fed
commit bb91ad0084

View File

@ -104,7 +104,12 @@ static __noinline u64 layer_dsq_id(u32 layer_id, u32 llc_id)
return (layer_id * nr_llcs) + llc_id;
}
static __noinline u32 cpu_to_llc_id(s32 cpu_id)
// XXX - cpu_to_llc_id() must not be inlined to not blow past ins limit when
// topo is enabled but older kernels get confused by RCU state when subprogs are
// called from sleepable functions. Use __always_inline variant from
// layered_init() and __noinline from everywhere else. Remove this once we can
// ignore the older kernels.
static __always_inline u32 __cpu_to_llc_id(s32 cpu_id)
{
const volatile u32 *llc_ptr;
@ -116,6 +121,11 @@ static __noinline u32 cpu_to_llc_id(s32 cpu_id)
return *llc_ptr;
}
static __noinline u32 cpu_to_llc_id(u32 cpu_id)
{
return __cpu_to_llc_id(cpu_id);
}
u32 llc_node_id(u32 llc_id)
{
const volatile u32 *llc_ptr;
@ -1777,7 +1787,7 @@ static s32 create_cache(u32 cache_id)
return -ENOENT;
}
llc_id = cpu_to_llc_id(cpu);
llc_id = __cpu_to_llc_id(cpu);
if (llc_id != cache_id)
continue;