mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
sched_ext: Take cgroup_lock() first in scx_cgroup_lock()
scx_cgroup_lock() write-locks scx_cgroup_ops_rwsem and then takes
cgroup_lock(), which can deadlock through kernfs:
scx enable/disable cgroup rmdir cpu.weight write
------------------ ------------ ----------------
cgroup_lock()
percpu_down_write(rwsem)
cgroup_lock()
kernfs_get_active()
percpu_down_read(rwsem)
kernfs_drain()
The enable path waits for the rmdir to release cgroup_mutex. The rmdir,
deactivating the cpu controller's files, waits in kernfs_drain() for the
write's active reference. The write, in scx_group_set_weight(), waits for
the rwsem behind the pending writer.
Take cgroup_lock() first. The set_* paths take no cgroup locks inside the
read side, so a pending write-lock then only waits for read sections that
always run to completion, and no dependency from the rwsem back to
cgroup_mutex remains.
Fixes: a5bd6ba30b ("sched_ext: Use cgroup_lock/unlock() to synchronize against cgroup operations")
Cc: stable@vger.kernel.org # v6.18+
Signed-off-by: Tejun Heo <tj@kernel.org>
Reviewed-by: Andrea Righi <arighi@nvidia.com>
This commit is contained in:
parent
477869bfaf
commit
5f8b69642d
|
|
@ -4580,20 +4580,25 @@ static struct cgroup *root_cgroup(void)
|
|||
return &cgrp_dfl_root.cgrp;
|
||||
}
|
||||
|
||||
/*
|
||||
* cgroup_lock() must nest outside the rwsem write side: a writer waiting
|
||||
* for cgroup_mutex deadlocks with cgroup teardown, which holds it while
|
||||
* draining a set_* file write blocked on the rwsem behind the writer.
|
||||
*/
|
||||
static void scx_cgroup_lock(void)
|
||||
{
|
||||
cgroup_lock();
|
||||
#ifdef CONFIG_EXT_GROUP_SCHED
|
||||
percpu_down_write(&scx_cgroup_ops_rwsem);
|
||||
#endif
|
||||
cgroup_lock();
|
||||
}
|
||||
|
||||
static void scx_cgroup_unlock(void)
|
||||
{
|
||||
cgroup_unlock();
|
||||
#ifdef CONFIG_EXT_GROUP_SCHED
|
||||
percpu_up_write(&scx_cgroup_ops_rwsem);
|
||||
#endif
|
||||
cgroup_unlock();
|
||||
}
|
||||
#else /* CONFIG_EXT_GROUP_SCHED || CONFIG_EXT_SUB_SCHED */
|
||||
static inline struct cgroup *root_cgroup(void) { return NULL; }
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user