mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 20:54: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;
|
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)
|
static void scx_cgroup_lock(void)
|
||||||
{
|
{
|
||||||
|
cgroup_lock();
|
||||||
#ifdef CONFIG_EXT_GROUP_SCHED
|
#ifdef CONFIG_EXT_GROUP_SCHED
|
||||||
percpu_down_write(&scx_cgroup_ops_rwsem);
|
percpu_down_write(&scx_cgroup_ops_rwsem);
|
||||||
#endif
|
#endif
|
||||||
cgroup_lock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scx_cgroup_unlock(void)
|
static void scx_cgroup_unlock(void)
|
||||||
{
|
{
|
||||||
cgroup_unlock();
|
|
||||||
#ifdef CONFIG_EXT_GROUP_SCHED
|
#ifdef CONFIG_EXT_GROUP_SCHED
|
||||||
percpu_up_write(&scx_cgroup_ops_rwsem);
|
percpu_up_write(&scx_cgroup_ops_rwsem);
|
||||||
#endif
|
#endif
|
||||||
|
cgroup_unlock();
|
||||||
}
|
}
|
||||||
#else /* CONFIG_EXT_GROUP_SCHED || CONFIG_EXT_SUB_SCHED */
|
#else /* CONFIG_EXT_GROUP_SCHED || CONFIG_EXT_SUB_SCHED */
|
||||||
static inline struct cgroup *root_cgroup(void) { return NULL; }
|
static inline struct cgroup *root_cgroup(void) { return NULL; }
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user