Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

sched_ext: Disable preemption between scx_claim_exit() and kicking helper work

scx_claim_exit() atomically sets exit_kind, which prevents scx_error() from
triggering further error handling. After claiming exit, the caller must kick
the helper kthread work which initiates bypass mode and teardown.

If the calling task gets preempted between claiming exit and kicking the
helper work, and the BPF scheduler fails to schedule it back (since error
handling is now disabled), the helper work is never queued, bypass mode
never activates, tasks stop being dispatched, and the system wedges.

Disable preemption across scx_claim_exit() and the subsequent work kicking
in all callers - scx_disable() and scx_vexit(). Add
lockdep_assert_preemption_disabled() to scx_claim_exit() to enforce the
requirement.

Fixes: f0e1a0643a59 ("sched_ext: Implement BPF extensible scheduler class")
Cc: stable@vger.kernel.org # v6.12+
Reviewed-by: Andrea Righi <arighi@nvidia.com>
Signed-off-by: Tejun Heo <tj@kernel.org>

Tejun Heo 83236b2e ee0ff669

+12
+12
kernel/sched/ext.c
··· 4423 4423 scx_bypass(false); 4424 4424 } 4425 4425 4426 + /* 4427 + * Claim the exit on @sch. The caller must ensure that the helper kthread work 4428 + * is kicked before the current task can be preempted. Once exit_kind is 4429 + * claimed, scx_error() can no longer trigger, so if the current task gets 4430 + * preempted and the BPF scheduler fails to schedule it back, the helper work 4431 + * will never be kicked and the whole system can wedge. 4432 + */ 4426 4433 static bool scx_claim_exit(struct scx_sched *sch, enum scx_exit_kind kind) 4427 4434 { 4428 4435 int none = SCX_EXIT_NONE; 4436 + 4437 + lockdep_assert_preemption_disabled(); 4429 4438 4430 4439 if (!atomic_try_cmpxchg(&sch->exit_kind, &none, kind)) 4431 4440 return false; ··· 4458 4449 rcu_read_lock(); 4459 4450 sch = rcu_dereference(scx_root); 4460 4451 if (sch) { 4452 + guard(preempt)(); 4461 4453 scx_claim_exit(sch, kind); 4462 4454 kthread_queue_work(sch->helper, &sch->disable_work); 4463 4455 } ··· 4780 4770 const char *fmt, va_list args) 4781 4771 { 4782 4772 struct scx_exit_info *ei = sch->exit_info; 4773 + 4774 + guard(preempt)(); 4783 4775 4784 4776 if (!scx_claim_exit(sch, kind)) 4785 4777 return false;