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:
parent
83224b0837
commit
8174f1503f
|
@ -6,7 +6,7 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
#ifdef CONFIG_FREEZER
|
||||
/*
|
||||
* Check if a process has been frozen
|
||||
*/
|
||||
|
@ -39,6 +39,11 @@ static inline void clear_freeze_flag(struct task_struct *p)
|
|||
clear_tsk_thread_flag(p, TIF_FREEZE);
|
||||
}
|
||||
|
||||
static inline bool should_send_signal(struct task_struct *p)
|
||||
{
|
||||
return !(p->flags & PF_FREEZER_NOSIG);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wake up a frozen process
|
||||
*
|
||||
|
@ -75,6 +80,9 @@ static inline int try_to_freeze(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
extern bool freeze_task(struct task_struct *p, bool sig_only);
|
||||
extern void cancel_freezing(struct task_struct *p);
|
||||
|
||||
/*
|
||||
* The PF_FREEZER_SKIP flag should be set by a vfork parent right before it
|
||||
* calls wait_for_completion(&vfork) and reset right after it returns from this
|
||||
|
@ -166,7 +174,7 @@ static inline void set_freezable_with_signal(void)
|
|||
} while (try_to_freeze()); \
|
||||
__retval; \
|
||||
})
|
||||
#else /* !CONFIG_PM_SLEEP */
|
||||
#else /* !CONFIG_FREEZER */
|
||||
static inline int frozen(struct task_struct *p) { return 0; }
|
||||
static inline int freezing(struct task_struct *p) { return 0; }
|
||||
static inline void set_freeze_flag(struct task_struct *p) {}
|
||||
|
@ -191,6 +199,6 @@ static inline void set_freezable_with_signal(void) {}
|
|||
#define wait_event_freezable_timeout(wq, condition, timeout) \
|
||||
wait_event_interruptible_timeout(wq, condition, timeout)
|
||||
|
||||
#endif /* !CONFIG_PM_SLEEP */
|
||||
#endif /* !CONFIG_FREEZER */
|
||||
|
||||
#endif /* FREEZER_H_INCLUDED */
|
||||
|
|
|
@ -24,6 +24,7 @@ CFLAGS_REMOVE_sched_clock.o = -pg
|
|||
CFLAGS_REMOVE_sched.o = -mno-spe -pg
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_FREEZER) += freezer.o
|
||||
obj-$(CONFIG_PROFILING) += profile.o
|
||||
obj-$(CONFIG_SYSCTL_SYSCALL_CHECK) += sysctl_check.o
|
||||
obj-$(CONFIG_STACKTRACE) += stacktrace.o
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -85,6 +85,9 @@ config PM_SLEEP
|
|||
depends on SUSPEND || HIBERNATION || XEN_SAVE_RESTORE
|
||||
default y
|
||||
|
||||
config FREEZER
|
||||
def_bool PM_SLEEP
|
||||
|
||||
config SUSPEND
|
||||
bool "Suspend to RAM and standby"
|
||||
depends on PM && ARCH_SUSPEND_POSSIBLE
|
||||
|
|
|
@ -28,121 +28,6 @@ static inline int freezeable(struct task_struct * p)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static inline bool should_send_signal(struct task_struct *p)
|
||||
{
|
||||
return !(p->flags & PF_FREEZER_NOSIG);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
static 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;
|
||||
}
|
||||
|
||||
static 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);
|
||||
}
|
||||
}
|
||||
|
||||
static int try_to_freeze_tasks(bool sig_only)
|
||||
{
|
||||
struct task_struct *g, *p;
|
||||
|
@ -264,4 +149,3 @@ void thaw_processes(void)
|
|||
printk("done.\n");
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(refrigerator);
|
||||
|
|
Loading…
Reference in New Issue