cgroup: Wait for dying tasks to leave on rmdir
Tejun Heo
maintainerPATCH v2 1/1 cgroup: Wait for dying tasks to leave on rmdir
a72f73c4dd9b ("cgroup: Don't expose dead tasks in cgroup") hid PF_EXITING tasks from cgroup.procs so that systemd doesn't see tasks that have already been reaped via waitpid(). However, the populated counter (nr_populated_csets) is only decremented when the task later passes through cgroup_task_dead() in finish_task_switch(). This means cgroup.procs can appear empty while the cgroup is still populated, causing rmdir to fail with -EBUSY.
Fix this by making cgroup_rmdir() wait for dying tasks to fully leave. If the cgroup is populated but all remaining tasks have PF_EXITING set (the task iterator returns none due to the existing filter), wait for a kick from cgroup_task_dead() and retry. The wait is brief as tasks are removed from the cgroup's css_set between PF_EXITING assertion in do_exit() and cgroup_task_dead() in finish_task_switch().
v2: cgroup_is_populated() true to false transition happens under css_set_lock
not cgroup_mutex, so retest under css_set_lock before sleeping to avoid missed wakeups (Sebastian).
--- include/linux/cgroup-defs.h | 3 ++ kernel/cgroup/cgroup.c | 86 +++++++++++++++++++++++++++++++++++-- 2 files changed, 86 insertions(+), 3 deletions(-)
include/linux/cgroup-defs.h +3 -0
@@ -609,6 +609,9 @@ struct cgroup {/* used to wait for offlining of csses */ wait_queue_head_t offline_waitq; +/* used by cgroup_rmdir() to wait for dying tasks to leave */ +wait_queue_head_t dying_populated_waitq; +/* used to schedule release agent */ struct work_struct release_agent_work;
kernel/cgroup/cgroup.c +83 -3
116 lines not on this page · raw message
Signature · 1 line
2.53.0
Quoted 18 lines · Tejun Heo
a72f73c4dd9b("cgroup: Don't expose dead tasks in cgroup") hidPF_EXITINGtasks from cgroup.procs so that systemd doesn't see tasks that have already been reaped viawaitpid(). However, the populated counter (nr_populated_csets) is only decremented when the task later passes throughcgroup_task_dead()infinish_task_switch(). This means cgroup.procs can appear empty while the cgroup is still populated, causing rmdir to fail with-EBUSY.Fix this by making
cgroup_rmdir()wait for dying tasks to fully leave. If the cgroup is populated but all remaining tasks havePF_EXITINGset (the task iterator returns none due to the existing filter), wait for a kick fromcgroup_task_dead()and retry. The wait is brief as tasks are removed from the cgroup'scss_setbetweenPF_EXITINGassertion indo_exit()andcgroup_task_dead()infinish_task_switch().v2:
cgroup_is_populated()true to false transition happens undercss_set_lock
notcgroup_mutex, so retest undercss_set_lockbefore sleeping to avoid missed wakeups (Sebastian).
Quoted 8 lines
Fixes a72f73c4dd9b ("cgroup: Don't expose dead tasks in cgroup")Reported-by kernel test robot <[email protected]>Reported-by Sebastian Andrzej Siewior <[email protected]>Signed-off-by Tejun Heo <[email protected]>Cc Bert Karwatzki <[email protected]>Cc Michal Koutny <[email protected]>
As mentioned in the other email, if I
- irq_work_queue(this_cpu_ptr(&cgrp_dead_tasks_iwork));
+ schedule_delayed_work(this_cpu_ptr(&cgrp_delayed_tasks_iwork), 1 * HZ);
then I hung at boot because it rmdir() a cgroup with a task in Z. It might suggest a race because systemd might missed a task. But this fixes the other issue so.
Sebastian
Tejun Heo
maintainerHello,
On Tue, Mar 24, 2026 at 10:04:02AM +0100, Sebastian Andrzej Siewior wrote:
...
Quoted 7 lines
As mentioned in the other email, if I
(quoted diff) +1
-1- irq_work_queue(this_cpu_ptr(&cgrp_dead_tasks_iwork)); + schedule_delayed_work(this_cpu_ptr(&cgrp_delayed_tasks_iwork), 1 * HZ);then I hung at boot because it
rmdir()a cgroup with a task in Z. It might suggest a race because systemd might missed a task. But this fixes the other issue so.
Just did 100 boot test w/ 1s delay added as above but the problem didn't reproduce. Can't reproduce with cgroup create / populate / depopulate / rmdir stress tests either. I did hit 1s delay propagating through but that wasn't a dead lock. The code is not great. It'd be better to just keep css_set_lock held while iterating too.
I'll apply this for now. Can you please try to reproduce the problem with the patches applied? How reliably does it reproduce? How is it stuck? Are tasks waiting on the waitq indefinitely with populated stuck at 1?
Thanks.
Signature · 1 line
tejun
Quoted 1 line · Tejun Heo
Hello,
Hi,
Quoted 3 lines
I'll apply this for now. Can you please try to reproduce the problem with the patches applied? How reliably does it reproduce? How is it stuck? Are tasks waiting on the waitq indefinitely with populated stuck at 1?
With the patches applied the test suite works. But now I accidentally did poweroff :
| [ OK ] Finished systemd-poweroff.service - System Power Off. | [ OK ] Reached target poweroff.target - System Power Off. | INFO: task systemd:1 blocked for more than 10 seconds. | Not tainted 7.0.0-rc5+ #167 | "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. | task:systemd state:D stack:0 pid:1 tgid:1 ppid:0 task_flags:0x400100 flags:0x00080000 | Call Trace: | <TASK> | __schedule+0x3d4/0xf80 | schedule+0x27/0xd0 | cgroup_drain_dying+0xb7/0x1b0 | cgroup_rmdir+0x2f/0x100 | kernfs_iop_rmdir+0x6a/0xd0 | vfs_rmdir+0x11a/0x280 | filename_rmdir+0x16f/0x1e0 | __x64_sys_unlinkat+0x58/0x70 | do_syscall_64+0x119/0x5a0 | entry_SYSCALL_64_after_hwframe+0x76/0x7e | RIP: 0033:0x7f06b8b7fc17 | RSP: 002b:00007ffe37f96c98 EFLAGS: 00000206 ORIG_RAX: 0000000000000107 | RAX: ffffffffffffffda RBX: 000055ee562eba40 RCX: 00007f06b8b7fc17 | RDX: 0000000000000200 RSI: 000055ee562eba53 RDI: 000000000000000c | RBP: 000000000000000d R08: 000055ee562eba40 R09: 0000000000000000 | R10: 00000000000007a0 R11: 0000000000000206 R12: 000055ee5639daa0 | R13: 0000000000000000 R14: 000055ee562eba53 R15: 000055ee562ec030 | </TASK>
This is not PREEMPT_RT and I can reproduce it also as of commit 6680c162b4850 ("selftests/cgroup: Don't require synchronous populated update on task exit").
The reboot command is also affected in the same way. systemd is 260-1 in case it should matter.
Quoted 2 lines
Thanks.
Sebastian
Applied to cgroup/for-7.0-fixes.
Thanks.
Signature · 1 line
tejun