[Devel] [PATCH vz10 17/24] ve/cgroup: take cgroup_mutex + threadgroup lock around vz.slice attach
Pavel Tikhomirov
ptikhomirov at virtuozzo.com
Fri Jul 24 17:07:04 MSK 2026
This is also fixed by:
ve/cgroup: Grab missing locks in cgroup_(join|leave)_vz_slice
On 7/6/26 12:59, Konstantin Khorenko wrote:
> cgroup_leave_vz_slice() tail-called cgroup_attach_task(cgrp, current, true)
> with no locks at all, and cgroup_join_vz_slice() called it holding only
> cgroup_mutex (via cgroup_kn_lock_live()) but without the threadgroup lock.
> cgroup_attach_task() requires cgroup_mutex AND cgroup_threadgroup_rwsem
> (and, for the ->attach() callbacks, cpus_read_lock()); see its kerneldoc.
>
> Because the leave path is a tail call, its frame is absent from the
> backtrace, so on a PROVE_LOCKING kernel the splat looked like it came from
> ve_start_container() directly:
>
> WARNING: at kernel/cgroup/cgroup.c:535 find_existing_css_set
> lockdep_assert_held(&cgroup_mutex)
> cgroup_attach_task <- ve_start_container <- ve_state_write
>
> and fired ~200 times on every single container start/stop. Beyond the
> annotation, this is a real race on production kernels: find_css_set() /
> cgroup_migrate_prepare_dst() / cgroup_migrate_finish() manipulate the
> per-cset mg_src_cgrp/mg_dst_cgrp and mg_*_preload_node fields that are
> serialized only by cgroup_mutex, so a concurrent migration (any host
> cgroup.procs write, another CT start, or a subtree_control update) can
> corrupt the migration preload lists; the missing threadgroup lock can also
> leave a thread forked mid-migration on the old cset.
>
> Take cgroup_mutex (leave path) and cgroup_attach_lock(true) (both paths)
> around cgroup_attach_task(), mirroring cgroup_attach_task_all() and
> __cgroup_procs_write(); the attach_lock nests inside cgroup_mutex, and the
> ve->op_sem -> cgroup_mutex order already used by the join path is preserved.
>
> Fixes: 20a5affcf263 ("ve/cgroup: add vz.slice cgroup to put kernel threads to")
> Feature: ve: ve generic structures
> https://virtuozzo.atlassian.net/browse/VSTOR-137234
> Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>
> ---
> kernel/cgroup/cgroup.c | 10 +++++++++-
> 1 file changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
> index 5585545304a3..4db77090f1be 100644
> --- a/kernel/cgroup/cgroup.c
> +++ b/kernel/cgroup/cgroup.c
> @@ -2276,7 +2276,9 @@ int cgroup_join_vz_slice(struct ve_struct *ve)
> return -ENODEV;
> }
>
> + cgroup_attach_lock(true);
> ret = cgroup_attach_task(cgrp, current, true);
> + cgroup_attach_unlock(true);
> cgroup_kn_unlock(kn);
> kernfs_put(kn);
> return ret;
> @@ -2286,6 +2288,7 @@ int cgroup_leave_vz_slice(struct ve_struct *ve)
> {
> struct css_set *cset;
> struct cgroup *cgrp;
> + int ret;
>
> cset = rcu_dereference_protected(ve->ve_nsproxy, 1)->cgroup_ns->root_cset;
> cgrp = __cset_cgroup_from_root(cset, &cgrp_dfl_root);
> @@ -2294,7 +2297,12 @@ int cgroup_leave_vz_slice(struct ve_struct *ve)
> !test_bit(CGRP_VE_ROOT, &cgrp->flags))
> return 0;
>
> - return cgroup_attach_task(cgrp, current, true);
> + cgroup_lock();
> + cgroup_attach_lock(true);
> + ret = cgroup_attach_task(cgrp, current, true);
> + cgroup_attach_unlock(true);
> + cgroup_unlock();
> + return ret;
> }
>
> struct cgroup_subsys_state *css_ve_root1(struct cgroup_subsys_state *css)
--
Best regards, Pavel Tikhomirov
Senior Software Developer, Virtuozzo.
More information about the Devel
mailing list