cgroup_attach_lock(9)

πŸ“¦ version 7.3.1, in nixpkgs unstable

πŸ’… cgroup_attach_lock(9) β€” a Kernel API Manual moment

okay so bestie, you're in the Kernel API Manual, and today's main character is cgroup_attach_lock. yes, the lock for ->attach(). let's get into it πŸ’–


✨ NAME ✨

cgroup_attach_lock β€” the lock for ->attach() πŸŽ€


✨ SYNOPSIS ✨

void cgroup_attach_lock (enum cgroup_attach_lock_mode lock_mode , struct
task_struct *tsk );

✨ ARGUMENTS ✨

  • lock_mode β€” tells us whether to acquire a rwsem, and which rwsem to acquire. yes it's doing both jobs, she's multitasking πŸ’…
  • tsk β€” the thread group to lock 🫢

✨ DESCRIPTION ✨

so, cgroup migration sometimes needs to stabilize threadgroups against forks and exits by write-locking cgroup_threadgroup_rwsem. makes sense, right? you're moving stuff around, you don't want the threadgroup wiggling out from under you.

but here's the plot twist 😭 β€” some ->attach implementations (looking at you, cpuset) also need to disable CPU hotplug. and unfortunately, letting ->attach operations acquire cpus_read_lock can lead to deadlocks. not cute. not slay. genuinely bad vibes.

here's why, bestie, because the nesting goes the wrong way πŸ‘€:

bringing up a CPU may involve creating and destroying tasks, and that requires read-locking threadgroup_rwsem. so threadgroup_rwsem nests inside cpus_read_lock. if we call an ->attach which acquires the cpus lock while write-locking threadgroup_rwsem, the locking order is reversed and we end up waiting for an on-going CPU hotplug operation β€” which in turn is waiting for the threadgroup_rwsem to be released so it can create new tasks. deadlock city, population: us πŸ’€

for more details:

http://lkml.kernel.org/r/20220711174629.uehfmqegcwn2lqzuwubuntu

so how do we resolve the situation? πŸ’‘ by always acquiring cpus_read_lock before optionally write-locking cgroup_threadgroup_rwsem. that's it, that's the fix. this allows ->attach to assume that CPU hotplug is disabled on entry. iconic behavior, honestly πŸ‘‘

also! when favordynmods is enabled, take per threadgroup rwsem to reduce overhead on dynamic cgroup modifications. see the comment above the CGRP_ROOT_FAVOR_DYNMODS definition 🌸

and one last little note: tsk is not NULL only when writing to cgroup.procs. no cap. πŸ™ˆ


✨ SEE ALSO ✨

kernel file ./kernel/cgroup/cgroup.c 🌈 β€” and here's the whole friend group, everybody say hi:

cgroup_ssid_enabled(9), cgroup_on_dfl(9), cgroup_e_css_by_mask(9), cgroup_e_css(9), cgroup_get_e_css(9), __cgroup_task_count(9), cgroup_task_count(9), for_each_css(9), do_each_subsys_mask(9), css_set_populated(9), css_update_populated(9), css_set_update_populated(9), css_set_move_task(9), compare_css_sets(9), find_existing_css_set(9), allocate_cgrp_cset_links(9), link_css_set(9), find_css_set(9), cgroup_file_mode(9), cgroup_calc_subtree_ss_mask(9), cgroup_kn_unlock(9), cgroup_kn_lock_live(9), css_clear_dir(9), css_populate_dir(9), cgroup_attach_unlock(9), cgroup_migrate_add_task(9), cgroup_taskset_first(9), cgroup_taskset_next(9), cgroup_migrate_execute(9), cgroup_migrate_vet_dst(9), cgroup_migrate_finish(9), cgroup_migrate_add_src(9), cgroup_migrate_prepare_dst(9), cgroup_migrate(9), cgroup_attach_task(9), cgroup_update_dfl_csses(9), cgroup_lock_and_drain_offline(9), cgroup_save_control(9), cgroup_propagate_control(9), cgroup_restore_control(9), cgroup_apply_control_enable(9), cgroup_apply_control_disable(9), cgroup_apply_control(9), cgroup_finalize_control(9), cgroup_enable_threaded(9), cgroup_tryget_css(9), cgroup_addrm_files(9), cgroup_rm_cftypes(9), cgroup_add_cftypes(9), cgroup_add_dfl_cftypes(9), cgroup_add_legacy_cftypes(9), cgroup_file_notify(9), cgroup_file_show(9), css_next_child(9), css_next_descendant_pre(9), css_rightmost_descendant(9), css_next_descendant_post(9), css_has_online_children(9), css_task_iter_advance_css_set(9), css_task_iter_start(9), css_task_iter_next(9), css_task_iter_end(9), css_create(9), kill_css_sync(9), kill_css_finish(9), cgroup_destroy_locked(9), cgroup_init_early(9), cgroup_init(9), cgroup_fork(9), cgroup_v1v2_get_from_file(9), cgroup_get_from_file(9), cgroup_css_set_fork(9), cgroup_css_set_put_fork(9), cgroup_can_fork(9), cgroup_cancel_fork(9), cgroup_post_fork(9), cgroup_task_exit(9), css_tryget_online_from_dir(9), css_from_id(9), cgroup_get_from_path(9), cgroup_v1v2_get_from_fd(9), cgroup_get_from_fd(9), cgroup_parse_float(9)


bestie please remember: release the rwsem, respect the locking order, and never let ->attach grab the cpus lock while you're holding the write lock. that's the whole personality of this function πŸ’œ

and that's a wrap, babe πŸ¦‹ this page came from the source ./kernel/cgroup, dated October 2026, and it's filed under cgroup_attach_lock(9). mwah πŸ’‹

πŸ“¦ where this page comes from