forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <[email protected]> Signed-off-by: Matt Helsley <[email protected]> Acked-by: Serge E. Hallyn <[email protected]> Tested-by: Matt Helsley <[email protected]> Cc: "Rafael J. Wysocki" <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
- Loading branch information
Showing
5 changed files
with
137 additions
and
119 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters