diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c index e45a3058d2cff..72a75b40e116b 100644 --- a/kernel/sched/ext.c +++ b/kernel/sched/ext.c @@ -3272,7 +3272,7 @@ static const char *scx_exit_reason(enum scx_exit_kind kind) static void scx_ops_disable_workfn(struct kthread_work *work) { - struct scx_exit_info *ei = scx_exit_info; + struct scx_exit_info *ei; struct scx_task_iter sti; struct task_struct *p; struct rhashtable_iter rht_iter; @@ -3291,14 +3291,27 @@ static void scx_ops_disable_workfn(struct kthread_work *work) if (atomic_try_cmpxchg(&scx_exit_kind, &kind, SCX_EXIT_DONE)) break; } + + /* guarantee forward progress by bypassing scx_ops */ + scx_ops_bypass(true); + + /* + * Here, every runnable task is guaranteed to make forward progress and + * we can safely use blocking synchronization constructs. Actually + * disable ops. + */ + mutex_lock(&scx_ops_enable_mutex); + + ei = scx_exit_info; + if (!ei) { + mutex_unlock(&scx_ops_enable_mutex); + goto done; + } ei->kind = kind; ei->reason = scx_exit_reason(ei->kind); cancel_delayed_work_sync(&scx_watchdog_work); - /* guarantee forward progress by bypassing scx_ops */ - scx_ops_bypass(true); - switch (scx_ops_set_enable_state(SCX_OPS_DISABLING)) { case SCX_OPS_DISABLING: WARN_ONCE(true, "sched_ext: duplicate disabling instance?"); @@ -3313,13 +3326,6 @@ static void scx_ops_disable_workfn(struct kthread_work *work) break; } - /* - * Here, every runnable task is guaranteed to make forward progress and - * we can safely use blocking synchronization constructs. Actually - * disable ops. - */ - mutex_lock(&scx_ops_enable_mutex); - static_branch_disable(&__scx_switched_all); WRITE_ONCE(scx_switching_all, false); @@ -3614,13 +3620,13 @@ static int scx_ops_enable(struct sched_ext_ops *ops) scx_create_rt_helper("sched_ext_ops_helper")); if (!scx_ops_helper) { ret = -ENOMEM; - goto err; + goto err_unlock; } } if (scx_ops_enable_state() != SCX_OPS_DISABLED) { ret = -EBUSY; - goto err; + goto err_unlock; } scx_exit_info = alloc_exit_info(); @@ -3868,6 +3874,7 @@ static int scx_ops_enable(struct sched_ext_ops *ops) free_exit_info(scx_exit_info); scx_exit_info = NULL; } +err_unlock: mutex_unlock(&scx_ops_enable_mutex); return ret;