aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/cgroup_freezer.c2
-rw-r--r--kernel/freezer.c42
-rw-r--r--kernel/power/process.c3
3 files changed, 27 insertions, 20 deletions
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c
index a6d405a86ee0..cd27b0825560 100644
--- a/kernel/cgroup_freezer.c
+++ b/kernel/cgroup_freezer.c
@@ -231,7 +231,7 @@ static void update_if_frozen(struct cgroup *cgroup,
231 cgroup_iter_start(cgroup, &it); 231 cgroup_iter_start(cgroup, &it);
232 while ((task = cgroup_iter_next(cgroup, &it))) { 232 while ((task = cgroup_iter_next(cgroup, &it))) {
233 ntotal++; 233 ntotal++;
234 if (frozen(task)) 234 if (freezing(task) && frozen(task))
235 nfrozen++; 235 nfrozen++;
236 } 236 }
237 237
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}
diff --git a/kernel/power/process.c b/kernel/power/process.c
index bd420ca48261..e6e2739190b5 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -118,7 +118,8 @@ static int try_to_freeze_tasks(bool sig_only)
118 118
119 read_lock(&tasklist_lock); 119 read_lock(&tasklist_lock);
120 do_each_thread(g, p) { 120 do_each_thread(g, p) {
121 if (!wakeup && freezing(p) && !freezer_should_skip(p)) 121 if (!wakeup && !freezer_should_skip(p) &&
122 freezing(p) && !frozen(p))
122 sched_show_task(p); 123 sched_show_task(p);
123 cancel_freezing(p); 124 cancel_freezing(p);
124 } while_each_thread(g, p); 125 } while_each_thread(g, p);