|
@@ -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);
|
|
|
}
|