@@ -60,6 +60,7 @@ const volatile s32 central_cpu;
6060const volatile u32 nr_cpu_ids = 1 ; /* !0 for veristat, set during init */
6161const volatile u64 slice_ns = SCX_SLICE_DFL ;
6262
63+ bool timer_pinned = true;
6364u64 nr_total , nr_locals , nr_queued , nr_lost_pids ;
6465u64 nr_timers , nr_dispatches , nr_mismatches , nr_retries ;
6566u64 nr_overflows ;
@@ -255,7 +256,7 @@ static int central_timerfn(void *map, int *key, struct bpf_timer *timer)
255256 s32 i , curr_cpu ;
256257
257258 curr_cpu = bpf_get_smp_processor_id ();
258- if (curr_cpu != central_cpu ) {
259+ if (timer_pinned && ( curr_cpu != central_cpu ) ) {
259260 scx_bpf_error ("Central timer ran on CPU %d, not central CPU %d" ,
260261 curr_cpu , central_cpu );
261262 return 0 ;
@@ -308,12 +309,28 @@ int BPF_STRUCT_OPS_SLEEPABLE(central_init)
308309 if (!timer )
309310 return - ESRCH ;
310311
311- if (bpf_get_smp_processor_id () != central_cpu )
312+ if (bpf_get_smp_processor_id () != central_cpu ) {
313+ scx_bpf_error ("init from non-central CPU" );
312314 return - EINVAL ;
315+ }
313316
314317 bpf_timer_init (timer , & central_timer , CLOCK_MONOTONIC );
315318 bpf_timer_set_callback (timer , central_timerfn );
319+
316320 ret = bpf_timer_start (timer , TIMER_INTERVAL_NS , BPF_F_TIMER_CPU_PIN );
321+ /*
322+ * BPF_F_TIMER_CPU_PIN is pretty new (>=6.7). If we're running in a
323+ * kernel which doesn't have it, bpf_timer_start() will return -EINVAL.
324+ * Retry without the PIN. This would be the perfect use case for
325+ * bpf_core_enum_value_exists() but the enum type doesn't have a name
326+ * and can't be used with bpf_core_enum_value_exists(). Oh well...
327+ */
328+ if (ret == - EINVAL ) {
329+ timer_pinned = false;
330+ ret = bpf_timer_start (timer , TIMER_INTERVAL_NS , 0 );
331+ }
332+ if (ret )
333+ scx_bpf_error ("bpf_timer_start failed (%d)" , ret );
317334 return ret ;
318335}
319336
0 commit comments