summaryrefslogtreecommitdiff
path: root/kernel/freezer.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/freezer.c')
-rw-r--r--kernel/freezer.c42
1 files changed, 24 insertions, 18 deletions
diff --git a/kernel/freezer.c b/kernel/freezer.c
index 4130e48649bb..a8822be43da0 100644
--- a/kernel/freezer.c
+++ b/kernel/freezer.c
@@ -22,14 +22,19 @@ bool __refrigerator(bool check_kthr_stop)
bool was_frozen = false;
long save;
+ /*
+ * Enter FROZEN. If NOFREEZE, schedule immediate thawing by
+ * clearing freezing.
+ */
spin_lock_irq(&freezer_lock);
+repeat:
if (!freezing(current)) {
spin_unlock_irq(&freezer_lock);
return was_frozen;
}
- if (!(current->flags & PF_NOFREEZE))
- current->flags |= PF_FROZEN;
- clear_freeze_flag(current);
+ if (current->flags & PF_NOFREEZE)
+ clear_freeze_flag(current);
+ current->flags |= PF_FROZEN;
spin_unlock_irq(&freezer_lock);
save = current->state;
@@ -44,7 +49,7 @@ bool __refrigerator(bool check_kthr_stop)
for (;;) {
set_current_state(TASK_UNINTERRUPTIBLE);
- if (!frozen(current) ||
+ if (!freezing(current) ||
(check_kthr_stop && kthread_should_stop()))
break;
was_frozen = true;
@@ -54,6 +59,13 @@ bool __refrigerator(bool check_kthr_stop)
/* Remove the accounting blocker */
current->flags &= ~PF_FREEZING;
+ /* leave FROZEN */
+ spin_lock_irq(&freezer_lock);
+ if (freezing(current))
+ goto repeat;
+ current->flags &= ~PF_FROZEN;
+ spin_unlock_irq(&freezer_lock);
+
pr_debug("%s left refrigerator\n", current->comm);
/*
@@ -137,25 +149,19 @@ void cancel_freezing(struct task_struct *p)
spin_unlock_irqrestore(&freezer_lock, flags);
}
-/*
- * Wake up a frozen task
- *
- * task_lock() is needed to prevent the race with refrigerator() which may
- * occur if the freezing of tasks fails. Namely, without the lock, if the
- * freezing of tasks failed, thaw_tasks() might have run before a task in
- * refrigerator() could call frozen_process(), in which case the task would be
- * frozen and no one would thaw it.
- */
void __thaw_task(struct task_struct *p)
{
unsigned long flags;
+ /*
+ * Clear freezing and kick @p if FROZEN. Clearing is guaranteed to
+ * be visible to @p as waking up implies wmb. Waking up inside
+ * freezer_lock also prevents wakeups from leaking outside
+ * refrigerator.
+ */
spin_lock_irqsave(&freezer_lock, flags);
- if (frozen(p)) {
- p->flags &= ~PF_FROZEN;
+ clear_freeze_flag(p);
+ if (frozen(p))
wake_up_process(p);
- } else {
- clear_freeze_flag(p);
- }
spin_unlock_irqrestore(&freezer_lock, flags);
}