Skip to content

Commit 582f700

Browse files
committed
sched_ext: Hook up hardlockup detector
A poorly behaving BPF scheduler can trigger hard lockup. For example, on a large system with many tasks pinned to different subsets of CPUs, if the BPF scheduler puts all tasks in a single DSQ and lets all CPUs at it, the DSQ lock can be contended to the point where hardlockup triggers. Unfortunately, hardlockup can be the first signal out of such situations, thus requiring hardlockup handling. Hook scx_hardlockup() into the hardlockup detector to try kicking out the current scheduler in an attempt to recover the system to a good state. The handling strategy can delay watchdog taking its own action by one polling period; however, given that the only remediation for hardlockup is crash, this is likely an acceptable trade-off. v2: Add missing dummy scx_hardlockup() definition for !CONFIG_SCHED_CLASS_EXT (kernel test bot). Reported-by: Dan Schatzberg <schatzberg.dan@gmail.com> Cc: Emil Tsalapatis <etsal@meta.com> Cc: Douglas Anderson <dianders@chromium.org> Cc: Andrew Morton <akpm@linux-foundation.org> Reviewed-by: Andrea Righi <arighi@nvidia.com> Signed-off-by: Tejun Heo <tj@kernel.org>
1 parent 7ed8df0 commit 582f700

3 files changed

Lines changed: 29 additions & 0 deletions

File tree

include/linux/sched/ext.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,13 +223,15 @@ struct sched_ext_entity {
223223
void sched_ext_dead(struct task_struct *p);
224224
void print_scx_info(const char *log_lvl, struct task_struct *p);
225225
void scx_softlockup(u32 dur_s);
226+
bool scx_hardlockup(void);
226227
bool scx_rcu_cpu_stall(void);
227228

228229
#else /* !CONFIG_SCHED_CLASS_EXT */
229230

230231
static inline void sched_ext_dead(struct task_struct *p) {}
231232
static inline void print_scx_info(const char *log_lvl, struct task_struct *p) {}
232233
static inline void scx_softlockup(u32 dur_s) {}
234+
static inline bool scx_hardlockup(void) { return false; }
233235
static inline bool scx_rcu_cpu_stall(void) { return false; }
234236

235237
#endif /* CONFIG_SCHED_CLASS_EXT */

kernel/sched/ext.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3711,6 +3711,24 @@ void scx_softlockup(u32 dur_s)
37113711
smp_processor_id(), dur_s);
37123712
}
37133713

3714+
/**
3715+
* scx_hardlockup - sched_ext hardlockup handler
3716+
*
3717+
* A poorly behaving BPF scheduler can trigger hard lockup by e.g. putting
3718+
* numerous affinitized tasks in a single queue and directing all CPUs at it.
3719+
* Try kicking out the current scheduler in an attempt to recover the system to
3720+
* a good state before taking more drastic actions.
3721+
*/
3722+
bool scx_hardlockup(void)
3723+
{
3724+
if (!handle_lockup("hard lockup - CPU %d", smp_processor_id()))
3725+
return false;
3726+
3727+
printk_deferred(KERN_ERR "sched_ext: Hard lockup - CPU %d, disabling BPF scheduler\n",
3728+
smp_processor_id());
3729+
return true;
3730+
}
3731+
37143732
/**
37153733
* scx_bypass - [Un]bypass scx_ops and guarantee forward progress
37163734
* @bypass: true for bypass, false for unbypass

kernel/watchdog.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,15 @@ void watchdog_hardlockup_check(unsigned int cpu, struct pt_regs *regs)
196196
#ifdef CONFIG_SYSFS
197197
++hardlockup_count;
198198
#endif
199+
/*
200+
* A poorly behaving BPF scheduler can trigger hard lockup by
201+
* e.g. putting numerous affinitized tasks in a single queue and
202+
* directing all CPUs at it. The following call can return true
203+
* only once when sched_ext is enabled and will immediately
204+
* abort the BPF scheduler and print out a warning message.
205+
*/
206+
if (scx_hardlockup())
207+
return;
199208

200209
/* Only print hardlockups once. */
201210
if (per_cpu(watchdog_hardlockup_warned, cpu))

0 commit comments

Comments
 (0)