container freezer: make refrigerator always available
Now that the TIF_FREEZE flag is available in all architectures, extract the refrigerator() and freeze_task() from kernel/power/process.c and make it available to all. The refrigerator() can now be used in a control group subsystem implementing a control group freezer. Signed-off-by: Cedric Le Goater <clg@fr.ibm.com> Signed-off-by: Matt Helsley <matthltc@us.ibm.com> Acked-by: Serge E. Hallyn <serue@us.ibm.com> Tested-by: Matt Helsley <matthltc@us.ibm.com> Cc: "Rafael J. Wysocki" <rjw@sisk.pl> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
committed by
Linus Torvalds
parent
83224b0837
commit
8174f1503f
122
kernel/freezer.c
Normal file
122
kernel/freezer.c
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* kernel/freezer.c - Function to freeze a process
|
||||
*
|
||||
* Originally from kernel/power/process.c
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/freezer.h>
|
||||
|
||||
/*
|
||||
* freezing is complete, mark current process as frozen
|
||||
*/
|
||||
static inline void frozen_process(void)
|
||||
{
|
||||
if (!unlikely(current->flags & PF_NOFREEZE)) {
|
||||
current->flags |= PF_FROZEN;
|
||||
wmb();
|
||||
}
|
||||
clear_freeze_flag(current);
|
||||
}
|
||||
|
||||
/* Refrigerator is place where frozen processes are stored :-). */
|
||||
void refrigerator(void)
|
||||
{
|
||||
/* Hmm, should we be allowed to suspend when there are realtime
|
||||
processes around? */
|
||||
long save;
|
||||
|
||||
task_lock(current);
|
||||
if (freezing(current)) {
|
||||
frozen_process();
|
||||
task_unlock(current);
|
||||
} else {
|
||||
task_unlock(current);
|
||||
return;
|
||||
}
|
||||
save = current->state;
|
||||
pr_debug("%s entered refrigerator\n", current->comm);
|
||||
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
recalc_sigpending(); /* We sent fake signal, clean it up */
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
for (;;) {
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
if (!frozen(current))
|
||||
break;
|
||||
schedule();
|
||||
}
|
||||
pr_debug("%s left refrigerator\n", current->comm);
|
||||
__set_current_state(save);
|
||||
}
|
||||
EXPORT_SYMBOL(refrigerator);
|
||||
|
||||
static void fake_signal_wake_up(struct task_struct *p)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&p->sighand->siglock, flags);
|
||||
signal_wake_up(p, 0);
|
||||
spin_unlock_irqrestore(&p->sighand->siglock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* freeze_task - send a freeze request to given task
|
||||
* @p: task to send the request to
|
||||
* @sig_only: if set, the request will only be sent if the task has the
|
||||
* PF_FREEZER_NOSIG flag unset
|
||||
* Return value: 'false', if @sig_only is set and the task has
|
||||
* PF_FREEZER_NOSIG set or the task is frozen, 'true', otherwise
|
||||
*
|
||||
* The freeze request is sent by setting the tasks's TIF_FREEZE flag and
|
||||
* either sending a fake signal to it or waking it up, depending on whether
|
||||
* or not it has PF_FREEZER_NOSIG set. If @sig_only is set and the task
|
||||
* has PF_FREEZER_NOSIG set (ie. it is a typical kernel thread), its
|
||||
* TIF_FREEZE flag will not be set.
|
||||
*/
|
||||
bool freeze_task(struct task_struct *p, bool sig_only)
|
||||
{
|
||||
/*
|
||||
* We first check if the task is freezing and next if it has already
|
||||
* been frozen to avoid the race with frozen_process() which first marks
|
||||
* the task as frozen and next clears its TIF_FREEZE.
|
||||
*/
|
||||
if (!freezing(p)) {
|
||||
rmb();
|
||||
if (frozen(p))
|
||||
return false;
|
||||
|
||||
if (!sig_only || should_send_signal(p))
|
||||
set_freeze_flag(p);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
if (should_send_signal(p)) {
|
||||
if (!signal_pending(p))
|
||||
fake_signal_wake_up(p);
|
||||
} else if (sig_only) {
|
||||
return false;
|
||||
} else {
|
||||
wake_up_state(p, TASK_INTERRUPTIBLE);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void cancel_freezing(struct task_struct *p)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (freezing(p)) {
|
||||
pr_debug(" clean up: %s\n", p->comm);
|
||||
clear_freeze_flag(p);
|
||||
spin_lock_irqsave(&p->sighand->siglock, flags);
|
||||
recalc_sigpending_and_wake(p);
|
||||
spin_unlock_irqrestore(&p->sighand->siglock, flags);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user