aboutsummaryrefslogtreecommitdiffstats
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)
22 bool was_frozen = false; 22 bool was_frozen = false;
23 long save; 23 long save;
24 24
25 /*
26 * Enter FROZEN. If NOFREEZE, schedule immediate thawing by
27 * clearing freezing.
28 */
25 spin_lock_irq(&freezer_lock); 29 spin_lock_irq(&freezer_lock);
30repeat:
26 if (!freezing(current)) { 31 if (!freezing(current)) {
27 spin_unlock_irq(&freezer_lock); 32 spin_unlock_irq(&freezer_lock);
28 return was_frozen; 33 return was_frozen;
29 } 34 }
30 if (!(current->flags & PF_NOFREEZE)) 35 if (current->flags & PF_NOFREEZE)
31 current->flags |= PF_FROZEN; 36 clear_freeze_flag(current);
32 clear_freeze_flag(current); 37 current->flags |= PF_FROZEN;
33 spin_unlock_irq(&freezer_lock); 38 spin_unlock_irq(&freezer_lock);
34 39
35 save = current->state; 40 save = current->state;
@@ -44,7 +49,7 @@ bool __refrigerator(bool check_kthr_stop)
44 49
45 for (;;) { 50 for (;;) {
46 set_current_state(TASK_UNINTERRUPTIBLE); 51 set_current_state(TASK_UNINTERRUPTIBLE);
47 if (!frozen(current) || 52 if (!freezing(current) ||
48 (check_kthr_stop && kthread_should_stop())) 53 (check_kthr_stop && kthread_should_stop()))
49 break; 54 break;
50 was_frozen = true; 55 was_frozen = true;
@@ -54,6 +59,13 @@ bool __refrigerator(bool check_kthr_stop)
54 /* Remove the accounting blocker */ 59 /* Remove the accounting blocker */
55 current->flags &= ~PF_FREEZING; 60 current->flags &= ~PF_FREEZING;
56 61
62 /* leave FROZEN */
63 spin_lock_irq(&freezer_lock);
64 if (freezing(current))
65 goto repeat;
66 current->flags &= ~PF_FROZEN;
67 spin_unlock_irq(&freezer_lock);
68
57 pr_debug("%s left refrigerator\n", current->comm); 69 pr_debug("%s left refrigerator\n", current->comm);
58 70
59 /* 71 /*
@@ -137,25 +149,19 @@ void cancel_freezing(struct task_struct *p)
137 spin_unlock_irqrestore(&freezer_lock, flags); 149 spin_unlock_irqrestore(&freezer_lock, flags);
138} 150}
139 151
140/*
141 * Wake up a frozen task
142 *
143 * task_lock() is needed to prevent the race with refrigerator() which may
144 * occur if the freezing of tasks fails. Namely, without the lock, if the
145 * freezing of tasks failed, thaw_tasks() might have run before a task in
146 * refrigerator() could call frozen_process(), in which case the task would be
147 * frozen and no one would thaw it.
148 */
149void __thaw_task(struct task_struct *p) 152void __thaw_task(struct task_struct *p)
150{ 153{
151 unsigned long flags; 154 unsigned long flags;
152 155
156 /*
157 * Clear freezing and kick @p if FROZEN. Clearing is guaranteed to
158 * be visible to @p as waking up implies wmb. Waking up inside
159 * freezer_lock also prevents wakeups from leaking outside
160 * refrigerator.
161 */
153 spin_lock_irqsave(&freezer_lock, flags); 162 spin_lock_irqsave(&freezer_lock, flags);
154 if (frozen(p)) { 163 clear_freeze_flag(p);
155 p->flags &= ~PF_FROZEN; 164 if (frozen(p))
156 wake_up_process(p); 165 wake_up_process(p);
157 } else {
158 clear_freeze_flag(p);
159 }
160 spin_unlock_irqrestore(&freezer_lock, flags); 166 spin_unlock_irqrestore(&freezer_lock, flags);
161} 167}