diff options
-rw-r--r-- | kernel/cgroup_freezer.c | 2 | ||||
-rw-r--r-- | kernel/freezer.c | 42 | ||||
-rw-r--r-- | kernel/power/process.c | 3 |
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); |
30 | repeat: | ||
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 | */ | ||
149 | void __thaw_task(struct task_struct *p) | 152 | void __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); |