cgroup scheduling: Adding kthreadd to a non-RT cgroup can deadlock the kernel
Hi,
I've found a bug where, on CONFIG_RT_GROUP_SCHED systems, adding the kthreadd task to a cgroup with cpu.rt_runtime_us = 0 (as some cgroup configuration scripts do, when they move all processes into a default cgroup), can result in deadlocks in the kernel.
On 2.6.37, the problem can be triggered via CPU hotplug. The following sequence of events will deadlock on an SMP system:
1. Add kthreadd to a cpu cgroup with rt_runtime_us = 0
2. echo 0 > /sys/devices/system/cpu/cpu1/online
3. echo 1 > /sys/devices/system/cpu/cpu1/online
4. echo 0 > /sys/devices/system/cpu/cpu1/online
5. echo 1 > /sys/devices/system/cpu/cpu1/online
In line (3), the CPU hotplug will cause us to create a new ksoftirqd/1 thread. Since that thread is forked from kthreadd, it will end up in the same cgroup, also without any realtime access.
In step (4), cpu_callback in softirq.c will attempt to kill ksoftirqd by setting it to SCHED_FIFO and using kthread_stop(). It does this with 'sched_setscheduler_nocheck', which bypasses the usual checks that prevent setting a process to an SCHED_FIFO if it is in a cgroup that would prevent it from running.
Thus, ksoftirqd ends up at SCHED_FIFO but with a zero rt_runtime_us, and is never scheduled again, and kthread_stop blocks waiting on it.
In (5), we try to call the CPU notifier chain again, but it is still locked from (4), and we deadlock.
For reasons I don't fully understand, just adding ksoftirqd/1 to a cgroup and then taking CPU 1 offline doesn't result in a hang, so I think there may be some detail of this situation I don't fully understand, but I'm pretty confident in the general analysis.
Before 2.6.34, we can trigger a similar problem just by adding kthreadd to a cgroup and then calling stop_machine (e.g. by removing a module), since stop_machine created a new RT workqueue on each invocation. This is how I first found this problem: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/693594
- Nelson
Quoted 1 line · Nelson Elhage
Hi,
Greetings,
Quoted 24 lines
I've found a bug where, on
CONFIG_RT_GROUP_SCHEDsystems, adding the kthreadd task to a cgroup with cpu.rt_runtime_us = 0 (as some cgroup configuration scripts do, when they move all processes into a default cgroup), can result in deadlocks in the kernel.On 2.6.37, the problem can be triggered via CPU hotplug. The following sequence of events will deadlock on an SMP system:
1. Add kthreadd to a cpu cgroup with
rt_runtime_us= 0
2. echo 0 >/sys/devices/system/cpu/cpu1/online
3. echo 1 >/sys/devices/system/cpu/cpu1/online
4. echo 0 >/sys/devices/system/cpu/cpu1/online
5. echo 1 >/sys/devices/system/cpu/cpu1/onlineIn line (3), the CPU hotplug will cause us to create a new ksoftirqd/1 thread. Since that thread is forked from kthreadd, it will end up in the same cgroup, also without any realtime access.
In step (4),
cpu_callbackinsoftirq.cwill attempt to kill ksoftirqd by setting it toSCHED_FIFOand usingkthread_stop(). It does this with 'sched_setscheduler_nocheck', which bypasses the usual checks that prevent setting a process to anSCHED_FIFOif it is in a cgroup that would prevent it from running.
Quoted 5 lines
Thus, ksoftirqd ends up at
SCHED_FIFObut with a zerort_runtime_us, and is never scheduled again, andkthread_stopblocks waiting on it.In (5), we try to call the CPU notifier chain again, but it is still locked from (4), and we deadlock.
Hm. Seems to me this is just another of the myriad ways a privileged user can shoot himself in the foot.
-Mike
Quoted 6 lines · Nelson Elhage
Hi,
I've found a bug where, on
CONFIG_RT_GROUP_SCHEDsystems, adding the kthreadd task to a cgroup with cpu.rt_runtime_us = 0 (as some cgroup configuration scripts do, when they move all processes into a default cgroup), can result in deadlocks in the kernel.
IMHO its a bug to move kthreadd into a cgroup. Simply don't do that.
Ok. I bothered reporting this here since the kernel /does/ try to prevent you from shooting yourself in the foot in related ways, by moving existing SCHED_FIFO tasks into a cgroup without any RT runtime, so I figured it might make sense to add a check here. libcgroup, for example, will try to move all processes into a default cgroup, ignoring errors, and relies on the kernel to prevent it from shooting itself in the foot.
It sounds like you consider that behavior a bug, though, so I'll go report this bug there.
- Nelson
Quoted 12 lines · Peter Zijlstra
Quoted 6 lines · Nelson Elhage
Hi,
I've found a bug where, on
CONFIG_RT_GROUP_SCHEDsystems, adding the kthreadd task to a cgroup with cpu.rt_runtime_us = 0 (as some cgroup configuration scripts do, when they move all processes into a default cgroup), can result in deadlocks in the kernel.IMHO its a bug to move kthreadd into a cgroup. Simply don't do that.
Quoted 9 lines · Nelson Elhage
Ok. I bothered reporting this here since the kernel /does/ try to prevent you from shooting yourself in the foot in related ways, by moving existing
SCHED_FIFOtasks into a cgroup without any RT runtime, so I figured it might make sense to add a check here. libcgroup, for example, will try to move all processes into a default cgroup, ignoring errors, and relies on the kernel to prevent it from shooting itself in the foot.It sounds like you consider that behavior a bug, though, so I'll go report this bug there.
Right, so we try to catch obvious cases, but its near impossible to catch all cases.
And its not only the scheduler controller, I bet you can get into trouble with some of the other controllers as well.