]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
sched_ext: Defer sub_kset base put to scx_sched_free_rcu_work
authorTejun Heo <tj@kernel.org>
Mon, 11 May 2026 23:18:23 +0000 (13:18 -1000)
committerTejun Heo <tj@kernel.org>
Tue, 12 May 2026 21:28:56 +0000 (11:28 -1000)
scx_sub_enable_workfn() pins parent->kobj before dropping scx_sched_lock,
but that does not pin parent->sub_kset. Concurrent disable can
kset_unregister and free sub_kset before scx_alloc_and_add_sched()
dereferences it.

Split sub_kset teardown: kobject_del() at disable keeps sysfs removal; defer
kobject_put() to scx_sched_free_rcu_work so the memory survives. A racing
child sees state_in_sysfs=0 with valid memory, sysfs_create_dir() fails, and
the existing exit_kind gate in scx_link_sched() turns it away with -ENOENT.

Fixes: 411d3ef1a705 ("sched_ext: Unregister sub_kset on scheduler disable")
Signed-off-by: Tejun Heo <tj@kernel.org>
kernel/sched/ext.c

index 6d69ba29cfd77c3943fb9328d4084a4d16e643f6..23f7b3f63b09b2651c1e87bd31e1128a7c5251f1 100644 (file)
@@ -4821,6 +4821,8 @@ static void scx_sched_free_rcu_work(struct work_struct *work)
        kfree(sch->cgrp_path);
        if (sch_cgroup(sch))
                cgroup_put(sch_cgroup(sch));
+       if (sch->sub_kset)
+               kobject_put(&sch->sub_kset->kobj);
 #endif /* CONFIG_EXT_SUB_SCHED */
 
        for_each_possible_cpu(cpu) {
@@ -5861,7 +5863,7 @@ static void scx_sub_disable(struct scx_sched *sch)
        if (sch->ops.exit)
                SCX_CALL_OP(sch, exit, NULL, sch->exit_info);
        if (sch->sub_kset)
-               kset_unregister(sch->sub_kset);
+               kobject_del(&sch->sub_kset->kobj);
        kobject_del(&sch->kobj);
 }
 #else  /* CONFIG_EXT_SUB_SCHED */
@@ -5995,7 +5997,7 @@ static void scx_root_disable(struct scx_sched *sch)
         */
 #ifdef CONFIG_EXT_SUB_SCHED
        if (sch->sub_kset)
-               kset_unregister(sch->sub_kset);
+               kobject_del(&sch->sub_kset->kobj);
 #endif
        kobject_del(&sch->kobj);