cgroup: prevent spurious transition into non-frozen state
If freezing of a cgroup races with waking of a task from the frozen state (like waiting in vfork() or in do_signal_stop()), a spurious transition of the cgroup state can happen. The task enters cgroup_leave_frozen(true), the cgroup->nr_frozen_tasks counter decrements, and the cgroup is switched to the unfrozen state. To prevent it, let's reserve cgroup_leave_frozen(true) for terminating processes and use cgroup_leave_frozen(false) otherwise. To avoid busy-looping in the signal handling loop waiting for JOBCTL_TRAP_FREEZE set from the cgroup freezing path, let's do it explicitly in cgroup_leave_frozen(), if the task is going to stay frozen. Suggested-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Roman Gushchin <guro@fb.com> Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
parent
533307dc20
commit
cb2c4cd878
|
@ -139,19 +139,13 @@ void cgroup_leave_frozen(bool always_leave)
|
|||
cgroup_update_frozen(cgrp);
|
||||
WARN_ON_ONCE(!current->frozen);
|
||||
current->frozen = false;
|
||||
} else if (!(current->jobctl & JOBCTL_TRAP_FREEZE)) {
|
||||
spin_lock(¤t->sighand->siglock);
|
||||
current->jobctl |= JOBCTL_TRAP_FREEZE;
|
||||
set_thread_flag(TIF_SIGPENDING);
|
||||
spin_unlock(¤t->sighand->siglock);
|
||||
}
|
||||
spin_unlock_irq(&css_set_lock);
|
||||
|
||||
if (unlikely(current->frozen)) {
|
||||
/*
|
||||
* If the task remained in the frozen state,
|
||||
* make sure it won't reach userspace without
|
||||
* entering the signal handling loop.
|
||||
*/
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -2514,7 +2514,7 @@ bool get_signal(struct ksignal *ksig)
|
|||
*/
|
||||
if (unlikely(cgroup_task_frozen(current))) {
|
||||
spin_unlock_irq(&sighand->siglock);
|
||||
cgroup_leave_frozen(true);
|
||||
cgroup_leave_frozen(false);
|
||||
goto relock;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue