[PATCHSET cgroup/for-7.4] cgroup: Make the offline drain interruptible
From: Tejun Heo
Date: Wed Sep 02 2026 - 19:29:30 EST
Hello,
syzbot has been reporting "task hung in cgroup_subtree_control_write".
The underlying problem is an indefinite wait in a place where indefinite
waits should not happen. A task past exit_signals() can block in its exit
path for as long as, say, a FUSE daemon takes to answer a flush.
That wait is interruptible in name only. Once a thread group is exiting,
prepare_signal() drops every signal sent to it, so nothing can wake the
task. It still shows as TASK_INTERRUPTIBLE, and the hung task detector only
looks at TASK_UNINTERRUPTIBLE, so the stuck task never appears in any
report.
Since 1dffd95575eb ("cgroup: Defer kill_css_finish() in
cgroup_apply_control_disable()"), a disabled css offlines only after every
such task pinning it has exited, and the re-enable path waits for that
offline in TASK_UNINTERRUPTIBLE. The writer inherits the unkillable wait,
sits in D state, and is the only thing the hung task report shows.
This patchset makes the drain interruptible so that the writer can be
killed. The wait in the exit path remains a separate problem.
Tao Yu posted a patch that rejects the re-enable with -EBUSY while csses are
dying:
https://lore.kernel.org/all/20260901012342.855056-1-tao1.yu@xxxxxxxxx/
That fails re-enables that would have succeeded and keys off a counter that
also covers removed cgroups and offlined-but-pinned csses, so this takes the
interruptible wait instead.
0001-cgroup-Return-ENODEV-consistently-for-a-dead-cgroup.patch
0002-cgroup-Return-ERR_PTR-from-cgroup_kn_lock_live.patch
0003-cgroup-Make-the-offline-drain-interruptible.patch
0001 unifies the errno the interface file writers return for a removed
cgroup. 0002 makes cgroup_kn_lock_live() return ERR_PTR so that it can
report the interrupted drain. 0003 is the actual change.
This is against v7.3-rc1 (cee9395acd80) and also available in the following
git branch:
https://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git cgroup-drain-interruptible
diffstat follows.
kernel/cgroup/cgroup-internal.h | 2 +-
kernel/cgroup/cgroup-v1.c | 16 ++++---
kernel/cgroup/cgroup.c | 98 ++++++++++++++++++++++++-----------------
kernel/cgroup/debug.c | 10 ++---
4 files changed, 74 insertions(+), 52 deletions(-)
--
tejun