Split the freezing of threads according to whether they're userspace or
kernelspace threads. We use separate completion handlers, thereby allowing
for the possibility of thawing kernel space without thawing userspace.
This will be used to allow memory to be freed without it racing against
userspace.
Signed-off-by: Nigel Cunningham <[email protected]>
kernel/power/process.c | 71 +++++++++++++++++++++++++++++++++++-------------
1 files changed, 52 insertions(+), 19 deletions(-)
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 444a163..a3aca9a 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -45,8 +45,11 @@
*/
#define TIMEOUT (6 * HZ)
-DECLARE_COMPLETION(thaw);
-static atomic_t nr_frozen;
+
+DECLARE_COMPLETION(kernelspace_thaw);
+DECLARE_COMPLETION(userspace_thaw);
+static atomic_t nr_userspace_frozen;
+static atomic_t nr_kernelspace_frozen;
struct frozen_fs
{
@@ -120,32 +123,62 @@ static int freezeable(struct task_struct
return 1;
}
+static void __freeze_process(struct completion *completion_handler,
+ atomic_t *nr_frozen)
+{
+ long save;
+
+ freezer_message("%s (%d) frozen.\n",
+ current->comm, current->pid);
+ save = current->state;
+
+ atomic_inc(nr_frozen);
+ wait_for_completion(completion_handler);
+ atomic_dec(nr_frozen);
+
+ current->state = save;
+ freezer_message("%s (%d) leaving freezer.\n",
+ current->comm, current->pid);
+}
+
/*
* Invoked by the task todo list notifier when the task to be
* frozen is running.
*/
static int freeze_process(struct notifier_block *nl, unsigned long x, void *v)
{
- /* Hmm, should we be allowed to suspend when there are realtime
- processes around? */
- long save;
- save = current->state;
- pr_debug("%s frozen\n", current->comm);
+ unsigned long flags;
+
+ might_sleep();
+
+ /* Locking to handle race against waking the process in
+ * freeze threads. */
+ spin_lock_irqsave(¤t->sighand->siglock, flags);
current->flags |= PF_FROZEN;
- notifier_chain_unregister(¤t->todo, nl);
- kfree(nl);
- freezer_message("=");
-
- spin_lock_irq(¤t->sighand->siglock);
- recalc_sigpending(); /* We sent fake signal, clean it up */
- atomic_inc(&nr_frozen);
- spin_unlock_irq(¤t->sighand->siglock);
- wait_for_completion(&thaw);
+ if (nl)
+ notifier_chain_unregister(¤t->todo, nl);
+
+ recalc_sigpending();
+ spin_unlock_irqrestore(¤t->sighand->siglock, flags);
+
+ if (nl)
+ kfree(nl);
+
+ if (test_freezer_state(FREEZER_ON)) {
+ if (current->mm)
+ __freeze_process(&userspace_thaw, &nr_userspace_frozen);
+ else
+ __freeze_process(&kernelspace_thaw,
+ &nr_kernelspace_frozen);
+ }
+
+ spin_lock_irqsave(¤t->sighand->siglock, flags);
+ recalc_sigpending();
+ spin_unlock_irqrestore(¤t->sighand->siglock, flags);
+
current->flags &= ~PF_FROZEN;
- atomic_dec(&nr_frozen);
- pr_debug("%s thawed\n", current->comm);
- current->state = save;
+
return 0;
}
--
Nigel Cunningham nigel at suspend2 dot net
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]