diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/cgroup_freezer.c | 63 | ||||
-rw-r--r-- | kernel/cpu.c | 4 | ||||
-rw-r--r-- | kernel/exit.c | 3 | ||||
-rw-r--r-- | kernel/fork.c | 1 | ||||
-rw-r--r-- | kernel/freezer.c | 203 | ||||
-rw-r--r-- | kernel/kexec.c | 4 | ||||
-rw-r--r-- | kernel/kmod.c | 27 | ||||
-rw-r--r-- | kernel/kthread.c | 27 | ||||
-rw-r--r-- | kernel/power/hibernate.c | 92 | ||||
-rw-r--r-- | kernel/power/main.c | 10 | ||||
-rw-r--r-- | kernel/power/power.h | 2 | ||||
-rw-r--r-- | kernel/power/process.c | 77 | ||||
-rw-r--r-- | kernel/power/suspend.c | 12 | ||||
-rw-r--r-- | kernel/power/user.c | 184 |
14 files changed, 339 insertions, 370 deletions
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c index 213c0351dad8..fcb93fca782d 100644 --- a/kernel/cgroup_freezer.c +++ b/kernel/cgroup_freezer.c | |||
@@ -48,19 +48,17 @@ static inline struct freezer *task_freezer(struct task_struct *task) | |||
48 | struct freezer, css); | 48 | struct freezer, css); |
49 | } | 49 | } |
50 | 50 | ||
51 | static inline int __cgroup_freezing_or_frozen(struct task_struct *task) | 51 | bool cgroup_freezing(struct task_struct *task) |
52 | { | 52 | { |
53 | enum freezer_state state = task_freezer(task)->state; | 53 | enum freezer_state state; |
54 | return (state == CGROUP_FREEZING) || (state == CGROUP_FROZEN); | 54 | bool ret; |
55 | } | ||
56 | 55 | ||
57 | int cgroup_freezing_or_frozen(struct task_struct *task) | 56 | rcu_read_lock(); |
58 | { | 57 | state = task_freezer(task)->state; |
59 | int result; | 58 | ret = state == CGROUP_FREEZING || state == CGROUP_FROZEN; |
60 | task_lock(task); | 59 | rcu_read_unlock(); |
61 | result = __cgroup_freezing_or_frozen(task); | 60 | |
62 | task_unlock(task); | 61 | return ret; |
63 | return result; | ||
64 | } | 62 | } |
65 | 63 | ||
66 | /* | 64 | /* |
@@ -102,9 +100,6 @@ struct cgroup_subsys freezer_subsys; | |||
102 | * freezer_can_attach(): | 100 | * freezer_can_attach(): |
103 | * cgroup_mutex (held by caller of can_attach) | 101 | * cgroup_mutex (held by caller of can_attach) |
104 | * | 102 | * |
105 | * cgroup_freezing_or_frozen(): | ||
106 | * task->alloc_lock (to get task's cgroup) | ||
107 | * | ||
108 | * freezer_fork() (preserving fork() performance means can't take cgroup_mutex): | 103 | * freezer_fork() (preserving fork() performance means can't take cgroup_mutex): |
109 | * freezer->lock | 104 | * freezer->lock |
110 | * sighand->siglock (if the cgroup is freezing) | 105 | * sighand->siglock (if the cgroup is freezing) |
@@ -130,7 +125,7 @@ struct cgroup_subsys freezer_subsys; | |||
130 | * write_lock css_set_lock (cgroup iterator start) | 125 | * write_lock css_set_lock (cgroup iterator start) |
131 | * task->alloc_lock | 126 | * task->alloc_lock |
132 | * read_lock css_set_lock (cgroup iterator start) | 127 | * read_lock css_set_lock (cgroup iterator start) |
133 | * task->alloc_lock (inside thaw_process(), prevents race with refrigerator()) | 128 | * task->alloc_lock (inside __thaw_task(), prevents race with refrigerator()) |
134 | * sighand->siglock | 129 | * sighand->siglock |
135 | */ | 130 | */ |
136 | static struct cgroup_subsys_state *freezer_create(struct cgroup_subsys *ss, | 131 | static struct cgroup_subsys_state *freezer_create(struct cgroup_subsys *ss, |
@@ -150,7 +145,11 @@ static struct cgroup_subsys_state *freezer_create(struct cgroup_subsys *ss, | |||
150 | static void freezer_destroy(struct cgroup_subsys *ss, | 145 | static void freezer_destroy(struct cgroup_subsys *ss, |
151 | struct cgroup *cgroup) | 146 | struct cgroup *cgroup) |
152 | { | 147 | { |
153 | kfree(cgroup_freezer(cgroup)); | 148 | struct freezer *freezer = cgroup_freezer(cgroup); |
149 | |||
150 | if (freezer->state != CGROUP_THAWED) | ||
151 | atomic_dec(&system_freezing_cnt); | ||
152 | kfree(freezer); | ||
154 | } | 153 | } |
155 | 154 | ||
156 | /* task is frozen or will freeze immediately when next it gets woken */ | 155 | /* task is frozen or will freeze immediately when next it gets woken */ |
@@ -184,13 +183,7 @@ static int freezer_can_attach(struct cgroup_subsys *ss, | |||
184 | 183 | ||
185 | static int freezer_can_attach_task(struct cgroup *cgrp, struct task_struct *tsk) | 184 | static int freezer_can_attach_task(struct cgroup *cgrp, struct task_struct *tsk) |
186 | { | 185 | { |
187 | rcu_read_lock(); | 186 | return cgroup_freezing(tsk) ? -EBUSY : 0; |
188 | if (__cgroup_freezing_or_frozen(tsk)) { | ||
189 | rcu_read_unlock(); | ||
190 | return -EBUSY; | ||
191 | } | ||
192 | rcu_read_unlock(); | ||
193 | return 0; | ||
194 | } | 187 | } |
195 | 188 | ||
196 | static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) | 189 | static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) |
@@ -220,7 +213,7 @@ static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) | |||
220 | 213 | ||
221 | /* Locking avoids race with FREEZING -> THAWED transitions. */ | 214 | /* Locking avoids race with FREEZING -> THAWED transitions. */ |
222 | if (freezer->state == CGROUP_FREEZING) | 215 | if (freezer->state == CGROUP_FREEZING) |
223 | freeze_task(task, true); | 216 | freeze_task(task); |
224 | spin_unlock_irq(&freezer->lock); | 217 | spin_unlock_irq(&freezer->lock); |
225 | } | 218 | } |
226 | 219 | ||
@@ -238,7 +231,7 @@ static void update_if_frozen(struct cgroup *cgroup, | |||
238 | cgroup_iter_start(cgroup, &it); | 231 | cgroup_iter_start(cgroup, &it); |
239 | while ((task = cgroup_iter_next(cgroup, &it))) { | 232 | while ((task = cgroup_iter_next(cgroup, &it))) { |
240 | ntotal++; | 233 | ntotal++; |
241 | if (is_task_frozen_enough(task)) | 234 | if (freezing(task) && is_task_frozen_enough(task)) |
242 | nfrozen++; | 235 | nfrozen++; |
243 | } | 236 | } |
244 | 237 | ||
@@ -286,10 +279,9 @@ static int try_to_freeze_cgroup(struct cgroup *cgroup, struct freezer *freezer) | |||
286 | struct task_struct *task; | 279 | struct task_struct *task; |
287 | unsigned int num_cant_freeze_now = 0; | 280 | unsigned int num_cant_freeze_now = 0; |
288 | 281 | ||
289 | freezer->state = CGROUP_FREEZING; | ||
290 | cgroup_iter_start(cgroup, &it); | 282 | cgroup_iter_start(cgroup, &it); |
291 | while ((task = cgroup_iter_next(cgroup, &it))) { | 283 | while ((task = cgroup_iter_next(cgroup, &it))) { |
292 | if (!freeze_task(task, true)) | 284 | if (!freeze_task(task)) |
293 | continue; | 285 | continue; |
294 | if (is_task_frozen_enough(task)) | 286 | if (is_task_frozen_enough(task)) |
295 | continue; | 287 | continue; |
@@ -307,12 +299,9 @@ static void unfreeze_cgroup(struct cgroup *cgroup, struct freezer *freezer) | |||
307 | struct task_struct *task; | 299 | struct task_struct *task; |
308 | 300 | ||
309 | cgroup_iter_start(cgroup, &it); | 301 | cgroup_iter_start(cgroup, &it); |
310 | while ((task = cgroup_iter_next(cgroup, &it))) { | 302 | while ((task = cgroup_iter_next(cgroup, &it))) |
311 | thaw_process(task); | 303 | __thaw_task(task); |
312 | } | ||
313 | cgroup_iter_end(cgroup, &it); | 304 | cgroup_iter_end(cgroup, &it); |
314 | |||
315 | freezer->state = CGROUP_THAWED; | ||
316 | } | 305 | } |
317 | 306 | ||
318 | static int freezer_change_state(struct cgroup *cgroup, | 307 | static int freezer_change_state(struct cgroup *cgroup, |
@@ -326,20 +315,24 @@ static int freezer_change_state(struct cgroup *cgroup, | |||
326 | spin_lock_irq(&freezer->lock); | 315 | spin_lock_irq(&freezer->lock); |
327 | 316 | ||
328 | update_if_frozen(cgroup, freezer); | 317 | update_if_frozen(cgroup, freezer); |
329 | if (goal_state == freezer->state) | ||
330 | goto out; | ||
331 | 318 | ||
332 | switch (goal_state) { | 319 | switch (goal_state) { |
333 | case CGROUP_THAWED: | 320 | case CGROUP_THAWED: |
321 | if (freezer->state != CGROUP_THAWED) | ||
322 | atomic_dec(&system_freezing_cnt); | ||
323 | freezer->state = CGROUP_THAWED; | ||
334 | unfreeze_cgroup(cgroup, freezer); | 324 | unfreeze_cgroup(cgroup, freezer); |
335 | break; | 325 | break; |
336 | case CGROUP_FROZEN: | 326 | case CGROUP_FROZEN: |
327 | if (freezer->state == CGROUP_THAWED) | ||
328 | atomic_inc(&system_freezing_cnt); | ||
329 | freezer->state = CGROUP_FREEZING; | ||
337 | retval = try_to_freeze_cgroup(cgroup, freezer); | 330 | retval = try_to_freeze_cgroup(cgroup, freezer); |
338 | break; | 331 | break; |
339 | default: | 332 | default: |
340 | BUG(); | 333 | BUG(); |
341 | } | 334 | } |
342 | out: | 335 | |
343 | spin_unlock_irq(&freezer->lock); | 336 | spin_unlock_irq(&freezer->lock); |
344 | 337 | ||
345 | return retval; | 338 | return retval; |
diff --git a/kernel/cpu.c b/kernel/cpu.c index 5ca38d5d238a..2060c6e57027 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
@@ -470,7 +470,7 @@ out: | |||
470 | cpu_maps_update_done(); | 470 | cpu_maps_update_done(); |
471 | } | 471 | } |
472 | 472 | ||
473 | static int alloc_frozen_cpus(void) | 473 | static int __init alloc_frozen_cpus(void) |
474 | { | 474 | { |
475 | if (!alloc_cpumask_var(&frozen_cpus, GFP_KERNEL|__GFP_ZERO)) | 475 | if (!alloc_cpumask_var(&frozen_cpus, GFP_KERNEL|__GFP_ZERO)) |
476 | return -ENOMEM; | 476 | return -ENOMEM; |
@@ -543,7 +543,7 @@ cpu_hotplug_pm_callback(struct notifier_block *nb, | |||
543 | } | 543 | } |
544 | 544 | ||
545 | 545 | ||
546 | int cpu_hotplug_pm_sync_init(void) | 546 | static int __init cpu_hotplug_pm_sync_init(void) |
547 | { | 547 | { |
548 | pm_notifier(cpu_hotplug_pm_callback, 0); | 548 | pm_notifier(cpu_hotplug_pm_callback, 0); |
549 | return 0; | 549 | return 0; |
diff --git a/kernel/exit.c b/kernel/exit.c index d579a459309d..d9eab2e4b430 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -679,8 +679,6 @@ static void exit_mm(struct task_struct * tsk) | |||
679 | tsk->mm = NULL; | 679 | tsk->mm = NULL; |
680 | up_read(&mm->mmap_sem); | 680 | up_read(&mm->mmap_sem); |
681 | enter_lazy_tlb(mm, current); | 681 | enter_lazy_tlb(mm, current); |
682 | /* We don't want this task to be frozen prematurely */ | ||
683 | clear_freeze_flag(tsk); | ||
684 | task_unlock(tsk); | 682 | task_unlock(tsk); |
685 | mm_update_next_owner(mm); | 683 | mm_update_next_owner(mm); |
686 | mmput(mm); | 684 | mmput(mm); |
@@ -1040,6 +1038,7 @@ NORET_TYPE void do_exit(long code) | |||
1040 | exit_rcu(); | 1038 | exit_rcu(); |
1041 | /* causes final put_task_struct in finish_task_switch(). */ | 1039 | /* causes final put_task_struct in finish_task_switch(). */ |
1042 | tsk->state = TASK_DEAD; | 1040 | tsk->state = TASK_DEAD; |
1041 | tsk->flags |= PF_NOFREEZE; /* tell freezer to ignore us */ | ||
1043 | schedule(); | 1042 | schedule(); |
1044 | BUG(); | 1043 | BUG(); |
1045 | /* Avoid "noreturn function does return". */ | 1044 | /* Avoid "noreturn function does return". */ |
diff --git a/kernel/fork.c b/kernel/fork.c index b058c5820ecd..f34f894c4b98 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -992,7 +992,6 @@ static void copy_flags(unsigned long clone_flags, struct task_struct *p) | |||
992 | new_flags |= PF_FORKNOEXEC; | 992 | new_flags |= PF_FORKNOEXEC; |
993 | new_flags |= PF_STARTING; | 993 | new_flags |= PF_STARTING; |
994 | p->flags = new_flags; | 994 | p->flags = new_flags; |
995 | clear_freeze_flag(p); | ||
996 | } | 995 | } |
997 | 996 | ||
998 | SYSCALL_DEFINE1(set_tid_address, int __user *, tidptr) | 997 | SYSCALL_DEFINE1(set_tid_address, int __user *, tidptr) |
diff --git a/kernel/freezer.c b/kernel/freezer.c index 7be56c534397..9815b8d1eed5 100644 --- a/kernel/freezer.c +++ b/kernel/freezer.c | |||
@@ -9,101 +9,114 @@ | |||
9 | #include <linux/export.h> | 9 | #include <linux/export.h> |
10 | #include <linux/syscalls.h> | 10 | #include <linux/syscalls.h> |
11 | #include <linux/freezer.h> | 11 | #include <linux/freezer.h> |
12 | #include <linux/kthread.h> | ||
12 | 13 | ||
13 | /* | 14 | /* total number of freezing conditions in effect */ |
14 | * freezing is complete, mark current process as frozen | 15 | atomic_t system_freezing_cnt = ATOMIC_INIT(0); |
16 | EXPORT_SYMBOL(system_freezing_cnt); | ||
17 | |||
18 | /* indicate whether PM freezing is in effect, protected by pm_mutex */ | ||
19 | bool pm_freezing; | ||
20 | bool pm_nosig_freezing; | ||
21 | |||
22 | /* protects freezing and frozen transitions */ | ||
23 | static DEFINE_SPINLOCK(freezer_lock); | ||
24 | |||
25 | /** | ||
26 | * freezing_slow_path - slow path for testing whether a task needs to be frozen | ||
27 | * @p: task to be tested | ||
28 | * | ||
29 | * This function is called by freezing() if system_freezing_cnt isn't zero | ||
30 | * and tests whether @p needs to enter and stay in frozen state. Can be | ||
31 | * called under any context. The freezers are responsible for ensuring the | ||
32 | * target tasks see the updated state. | ||
15 | */ | 33 | */ |
16 | static inline void frozen_process(void) | 34 | bool freezing_slow_path(struct task_struct *p) |
17 | { | 35 | { |
18 | if (!unlikely(current->flags & PF_NOFREEZE)) { | 36 | if (p->flags & PF_NOFREEZE) |
19 | current->flags |= PF_FROZEN; | 37 | return false; |
20 | smp_wmb(); | 38 | |
21 | } | 39 | if (pm_nosig_freezing || cgroup_freezing(p)) |
22 | clear_freeze_flag(current); | 40 | return true; |
41 | |||
42 | if (pm_freezing && !(p->flags & PF_KTHREAD)) | ||
43 | return true; | ||
44 | |||
45 | return false; | ||
23 | } | 46 | } |
47 | EXPORT_SYMBOL(freezing_slow_path); | ||
24 | 48 | ||
25 | /* Refrigerator is place where frozen processes are stored :-). */ | 49 | /* Refrigerator is place where frozen processes are stored :-). */ |
26 | void refrigerator(void) | 50 | bool __refrigerator(bool check_kthr_stop) |
27 | { | 51 | { |
28 | /* Hmm, should we be allowed to suspend when there are realtime | 52 | /* Hmm, should we be allowed to suspend when there are realtime |
29 | processes around? */ | 53 | processes around? */ |
30 | long save; | 54 | bool was_frozen = false; |
55 | long save = current->state; | ||
31 | 56 | ||
32 | task_lock(current); | ||
33 | if (freezing(current)) { | ||
34 | frozen_process(); | ||
35 | task_unlock(current); | ||
36 | } else { | ||
37 | task_unlock(current); | ||
38 | return; | ||
39 | } | ||
40 | save = current->state; | ||
41 | pr_debug("%s entered refrigerator\n", current->comm); | 57 | pr_debug("%s entered refrigerator\n", current->comm); |
42 | 58 | ||
43 | spin_lock_irq(¤t->sighand->siglock); | ||
44 | recalc_sigpending(); /* We sent fake signal, clean it up */ | ||
45 | spin_unlock_irq(¤t->sighand->siglock); | ||
46 | |||
47 | /* prevent accounting of that task to load */ | ||
48 | current->flags |= PF_FREEZING; | ||
49 | |||
50 | for (;;) { | 59 | for (;;) { |
51 | set_current_state(TASK_UNINTERRUPTIBLE); | 60 | set_current_state(TASK_UNINTERRUPTIBLE); |
52 | if (!frozen(current)) | 61 | |
62 | spin_lock_irq(&freezer_lock); | ||
63 | current->flags |= PF_FROZEN; | ||
64 | if (!freezing(current) || | ||
65 | (check_kthr_stop && kthread_should_stop())) | ||
66 | current->flags &= ~PF_FROZEN; | ||
67 | spin_unlock_irq(&freezer_lock); | ||
68 | |||
69 | if (!(current->flags & PF_FROZEN)) | ||
53 | break; | 70 | break; |
71 | was_frozen = true; | ||
54 | schedule(); | 72 | schedule(); |
55 | } | 73 | } |
56 | 74 | ||
57 | /* Remove the accounting blocker */ | ||
58 | current->flags &= ~PF_FREEZING; | ||
59 | |||
60 | pr_debug("%s left refrigerator\n", current->comm); | 75 | pr_debug("%s left refrigerator\n", current->comm); |
61 | __set_current_state(save); | 76 | |
77 | /* | ||
78 | * Restore saved task state before returning. The mb'd version | ||
79 | * needs to be used; otherwise, it might silently break | ||
80 | * synchronization which depends on ordered task state change. | ||
81 | */ | ||
82 | set_current_state(save); | ||
83 | |||
84 | return was_frozen; | ||
62 | } | 85 | } |
63 | EXPORT_SYMBOL(refrigerator); | 86 | EXPORT_SYMBOL(__refrigerator); |
64 | 87 | ||
65 | static void fake_signal_wake_up(struct task_struct *p) | 88 | static void fake_signal_wake_up(struct task_struct *p) |
66 | { | 89 | { |
67 | unsigned long flags; | 90 | unsigned long flags; |
68 | 91 | ||
69 | spin_lock_irqsave(&p->sighand->siglock, flags); | 92 | if (lock_task_sighand(p, &flags)) { |
70 | signal_wake_up(p, 0); | 93 | signal_wake_up(p, 0); |
71 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | 94 | unlock_task_sighand(p, &flags); |
95 | } | ||
72 | } | 96 | } |
73 | 97 | ||
74 | /** | 98 | /** |
75 | * freeze_task - send a freeze request to given task | 99 | * freeze_task - send a freeze request to given task |
76 | * @p: task to send the request to | 100 | * @p: task to send the request to |
77 | * @sig_only: if set, the request will only be sent if the task has the | 101 | * |
78 | * PF_FREEZER_NOSIG flag unset | 102 | * If @p is freezing, the freeze request is sent by setting %TIF_FREEZE |
79 | * Return value: 'false', if @sig_only is set and the task has | 103 | * flag and either sending a fake signal to it or waking it up, depending |
80 | * PF_FREEZER_NOSIG set or the task is frozen, 'true', otherwise | 104 | * on whether it has %PF_FREEZER_NOSIG set. |
81 | * | 105 | * |
82 | * The freeze request is sent by setting the tasks's TIF_FREEZE flag and | 106 | * RETURNS: |
83 | * either sending a fake signal to it or waking it up, depending on whether | 107 | * %false, if @p is not freezing or already frozen; %true, otherwise |
84 | * or not it has PF_FREEZER_NOSIG set. If @sig_only is set and the task | ||
85 | * has PF_FREEZER_NOSIG set (ie. it is a typical kernel thread), its | ||
86 | * TIF_FREEZE flag will not be set. | ||
87 | */ | 108 | */ |
88 | bool freeze_task(struct task_struct *p, bool sig_only) | 109 | bool freeze_task(struct task_struct *p) |
89 | { | 110 | { |
90 | /* | 111 | unsigned long flags; |
91 | * We first check if the task is freezing and next if it has already | 112 | |
92 | * been frozen to avoid the race with frozen_process() which first marks | 113 | spin_lock_irqsave(&freezer_lock, flags); |
93 | * the task as frozen and next clears its TIF_FREEZE. | 114 | if (!freezing(p) || frozen(p)) { |
94 | */ | 115 | spin_unlock_irqrestore(&freezer_lock, flags); |
95 | if (!freezing(p)) { | 116 | return false; |
96 | smp_rmb(); | ||
97 | if (frozen(p)) | ||
98 | return false; | ||
99 | |||
100 | if (!sig_only || should_send_signal(p)) | ||
101 | set_freeze_flag(p); | ||
102 | else | ||
103 | return false; | ||
104 | } | 117 | } |
105 | 118 | ||
106 | if (should_send_signal(p)) { | 119 | if (!(p->flags & PF_KTHREAD)) { |
107 | fake_signal_wake_up(p); | 120 | fake_signal_wake_up(p); |
108 | /* | 121 | /* |
109 | * fake_signal_wake_up() goes through p's scheduler | 122 | * fake_signal_wake_up() goes through p's scheduler |
@@ -111,56 +124,48 @@ bool freeze_task(struct task_struct *p, bool sig_only) | |||
111 | * TASK_RUNNING transition can't race with task state | 124 | * TASK_RUNNING transition can't race with task state |
112 | * testing in try_to_freeze_tasks(). | 125 | * testing in try_to_freeze_tasks(). |
113 | */ | 126 | */ |
114 | } else if (sig_only) { | ||
115 | return false; | ||
116 | } else { | 127 | } else { |
117 | wake_up_state(p, TASK_INTERRUPTIBLE); | 128 | wake_up_state(p, TASK_INTERRUPTIBLE); |
118 | } | 129 | } |
119 | 130 | ||
131 | spin_unlock_irqrestore(&freezer_lock, flags); | ||
120 | return true; | 132 | return true; |
121 | } | 133 | } |
122 | 134 | ||
123 | void cancel_freezing(struct task_struct *p) | 135 | void __thaw_task(struct task_struct *p) |
124 | { | 136 | { |
125 | unsigned long flags; | 137 | unsigned long flags; |
126 | 138 | ||
127 | if (freezing(p)) { | 139 | /* |
128 | pr_debug(" clean up: %s\n", p->comm); | 140 | * Clear freezing and kick @p if FROZEN. Clearing is guaranteed to |
129 | clear_freeze_flag(p); | 141 | * be visible to @p as waking up implies wmb. Waking up inside |
130 | spin_lock_irqsave(&p->sighand->siglock, flags); | 142 | * freezer_lock also prevents wakeups from leaking outside |
131 | recalc_sigpending_and_wake(p); | 143 | * refrigerator. |
132 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | 144 | */ |
133 | } | 145 | spin_lock_irqsave(&freezer_lock, flags); |
134 | } | 146 | if (frozen(p)) |
135 | 147 | wake_up_process(p); | |
136 | static int __thaw_process(struct task_struct *p) | 148 | spin_unlock_irqrestore(&freezer_lock, flags); |
137 | { | ||
138 | if (frozen(p)) { | ||
139 | p->flags &= ~PF_FROZEN; | ||
140 | return 1; | ||
141 | } | ||
142 | clear_freeze_flag(p); | ||
143 | return 0; | ||
144 | } | 149 | } |
145 | 150 | ||
146 | /* | 151 | /** |
147 | * Wake up a frozen process | 152 | * set_freezable - make %current freezable |
148 | * | 153 | * |
149 | * task_lock() is needed to prevent the race with refrigerator() which may | 154 | * Mark %current freezable and enter refrigerator if necessary. |
150 | * occur if the freezing of tasks fails. Namely, without the lock, if the | ||
151 | * freezing of tasks failed, thaw_tasks() might have run before a task in | ||
152 | * refrigerator() could call frozen_process(), in which case the task would be | ||
153 | * frozen and no one would thaw it. | ||
154 | */ | 155 | */ |
155 | int thaw_process(struct task_struct *p) | 156 | bool set_freezable(void) |
156 | { | 157 | { |
157 | task_lock(p); | 158 | might_sleep(); |
158 | if (__thaw_process(p) == 1) { | 159 | |
159 | task_unlock(p); | 160 | /* |
160 | wake_up_process(p); | 161 | * Modify flags while holding freezer_lock. This ensures the |
161 | return 1; | 162 | * freezer notices that we aren't frozen yet or the freezing |
162 | } | 163 | * condition is visible to try_to_freeze() below. |
163 | task_unlock(p); | 164 | */ |
164 | return 0; | 165 | spin_lock_irq(&freezer_lock); |
166 | current->flags &= ~PF_NOFREEZE; | ||
167 | spin_unlock_irq(&freezer_lock); | ||
168 | |||
169 | return try_to_freeze(); | ||
165 | } | 170 | } |
166 | EXPORT_SYMBOL(thaw_process); | 171 | EXPORT_SYMBOL(set_freezable); |
diff --git a/kernel/kexec.c b/kernel/kexec.c index dc7bc0829286..090ee10d9604 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c | |||
@@ -1523,7 +1523,7 @@ int kernel_kexec(void) | |||
1523 | 1523 | ||
1524 | #ifdef CONFIG_KEXEC_JUMP | 1524 | #ifdef CONFIG_KEXEC_JUMP |
1525 | if (kexec_image->preserve_context) { | 1525 | if (kexec_image->preserve_context) { |
1526 | mutex_lock(&pm_mutex); | 1526 | lock_system_sleep(); |
1527 | pm_prepare_console(); | 1527 | pm_prepare_console(); |
1528 | error = freeze_processes(); | 1528 | error = freeze_processes(); |
1529 | if (error) { | 1529 | if (error) { |
@@ -1576,7 +1576,7 @@ int kernel_kexec(void) | |||
1576 | thaw_processes(); | 1576 | thaw_processes(); |
1577 | Restore_console: | 1577 | Restore_console: |
1578 | pm_restore_console(); | 1578 | pm_restore_console(); |
1579 | mutex_unlock(&pm_mutex); | 1579 | unlock_system_sleep(); |
1580 | } | 1580 | } |
1581 | #endif | 1581 | #endif |
1582 | 1582 | ||
diff --git a/kernel/kmod.c b/kernel/kmod.c index a4bea97c75b6..a0a88543934e 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/resource.h> | 36 | #include <linux/resource.h> |
37 | #include <linux/notifier.h> | 37 | #include <linux/notifier.h> |
38 | #include <linux/suspend.h> | 38 | #include <linux/suspend.h> |
39 | #include <linux/rwsem.h> | ||
39 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
40 | 41 | ||
41 | #include <trace/events/module.h> | 42 | #include <trace/events/module.h> |
@@ -50,6 +51,7 @@ static struct workqueue_struct *khelper_wq; | |||
50 | static kernel_cap_t usermodehelper_bset = CAP_FULL_SET; | 51 | static kernel_cap_t usermodehelper_bset = CAP_FULL_SET; |
51 | static kernel_cap_t usermodehelper_inheritable = CAP_FULL_SET; | 52 | static kernel_cap_t usermodehelper_inheritable = CAP_FULL_SET; |
52 | static DEFINE_SPINLOCK(umh_sysctl_lock); | 53 | static DEFINE_SPINLOCK(umh_sysctl_lock); |
54 | static DECLARE_RWSEM(umhelper_sem); | ||
53 | 55 | ||
54 | #ifdef CONFIG_MODULES | 56 | #ifdef CONFIG_MODULES |
55 | 57 | ||
@@ -275,6 +277,7 @@ static void __call_usermodehelper(struct work_struct *work) | |||
275 | * If set, call_usermodehelper_exec() will exit immediately returning -EBUSY | 277 | * If set, call_usermodehelper_exec() will exit immediately returning -EBUSY |
276 | * (used for preventing user land processes from being created after the user | 278 | * (used for preventing user land processes from being created after the user |
277 | * land has been frozen during a system-wide hibernation or suspend operation). | 279 | * land has been frozen during a system-wide hibernation or suspend operation). |
280 | * Should always be manipulated under umhelper_sem acquired for write. | ||
278 | */ | 281 | */ |
279 | static int usermodehelper_disabled = 1; | 282 | static int usermodehelper_disabled = 1; |
280 | 283 | ||
@@ -282,17 +285,29 @@ static int usermodehelper_disabled = 1; | |||
282 | static atomic_t running_helpers = ATOMIC_INIT(0); | 285 | static atomic_t running_helpers = ATOMIC_INIT(0); |
283 | 286 | ||
284 | /* | 287 | /* |
285 | * Wait queue head used by usermodehelper_pm_callback() to wait for all running | 288 | * Wait queue head used by usermodehelper_disable() to wait for all running |
286 | * helpers to finish. | 289 | * helpers to finish. |
287 | */ | 290 | */ |
288 | static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq); | 291 | static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq); |
289 | 292 | ||
290 | /* | 293 | /* |
291 | * Time to wait for running_helpers to become zero before the setting of | 294 | * Time to wait for running_helpers to become zero before the setting of |
292 | * usermodehelper_disabled in usermodehelper_pm_callback() fails | 295 | * usermodehelper_disabled in usermodehelper_disable() fails |
293 | */ | 296 | */ |
294 | #define RUNNING_HELPERS_TIMEOUT (5 * HZ) | 297 | #define RUNNING_HELPERS_TIMEOUT (5 * HZ) |
295 | 298 | ||
299 | void read_lock_usermodehelper(void) | ||
300 | { | ||
301 | down_read(&umhelper_sem); | ||
302 | } | ||
303 | EXPORT_SYMBOL_GPL(read_lock_usermodehelper); | ||
304 | |||
305 | void read_unlock_usermodehelper(void) | ||
306 | { | ||
307 | up_read(&umhelper_sem); | ||
308 | } | ||
309 | EXPORT_SYMBOL_GPL(read_unlock_usermodehelper); | ||
310 | |||
296 | /** | 311 | /** |
297 | * usermodehelper_disable - prevent new helpers from being started | 312 | * usermodehelper_disable - prevent new helpers from being started |
298 | */ | 313 | */ |
@@ -300,8 +315,10 @@ int usermodehelper_disable(void) | |||
300 | { | 315 | { |
301 | long retval; | 316 | long retval; |
302 | 317 | ||
318 | down_write(&umhelper_sem); | ||
303 | usermodehelper_disabled = 1; | 319 | usermodehelper_disabled = 1; |
304 | smp_mb(); | 320 | up_write(&umhelper_sem); |
321 | |||
305 | /* | 322 | /* |
306 | * From now on call_usermodehelper_exec() won't start any new | 323 | * From now on call_usermodehelper_exec() won't start any new |
307 | * helpers, so it is sufficient if running_helpers turns out to | 324 | * helpers, so it is sufficient if running_helpers turns out to |
@@ -314,7 +331,9 @@ int usermodehelper_disable(void) | |||
314 | if (retval) | 331 | if (retval) |
315 | return 0; | 332 | return 0; |
316 | 333 | ||
334 | down_write(&umhelper_sem); | ||
317 | usermodehelper_disabled = 0; | 335 | usermodehelper_disabled = 0; |
336 | up_write(&umhelper_sem); | ||
318 | return -EAGAIN; | 337 | return -EAGAIN; |
319 | } | 338 | } |
320 | 339 | ||
@@ -323,7 +342,9 @@ int usermodehelper_disable(void) | |||
323 | */ | 342 | */ |
324 | void usermodehelper_enable(void) | 343 | void usermodehelper_enable(void) |
325 | { | 344 | { |
345 | down_write(&umhelper_sem); | ||
326 | usermodehelper_disabled = 0; | 346 | usermodehelper_disabled = 0; |
347 | up_write(&umhelper_sem); | ||
327 | } | 348 | } |
328 | 349 | ||
329 | /** | 350 | /** |
diff --git a/kernel/kthread.c b/kernel/kthread.c index b6d216a92639..3d3de633702e 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c | |||
@@ -59,6 +59,31 @@ int kthread_should_stop(void) | |||
59 | EXPORT_SYMBOL(kthread_should_stop); | 59 | EXPORT_SYMBOL(kthread_should_stop); |
60 | 60 | ||
61 | /** | 61 | /** |
62 | * kthread_freezable_should_stop - should this freezable kthread return now? | ||
63 | * @was_frozen: optional out parameter, indicates whether %current was frozen | ||
64 | * | ||
65 | * kthread_should_stop() for freezable kthreads, which will enter | ||
66 | * refrigerator if necessary. This function is safe from kthread_stop() / | ||
67 | * freezer deadlock and freezable kthreads should use this function instead | ||
68 | * of calling try_to_freeze() directly. | ||
69 | */ | ||
70 | bool kthread_freezable_should_stop(bool *was_frozen) | ||
71 | { | ||
72 | bool frozen = false; | ||
73 | |||
74 | might_sleep(); | ||
75 | |||
76 | if (unlikely(freezing(current))) | ||
77 | frozen = __refrigerator(true); | ||
78 | |||
79 | if (was_frozen) | ||
80 | *was_frozen = frozen; | ||
81 | |||
82 | return kthread_should_stop(); | ||
83 | } | ||
84 | EXPORT_SYMBOL_GPL(kthread_freezable_should_stop); | ||
85 | |||
86 | /** | ||
62 | * kthread_data - return data value specified on kthread creation | 87 | * kthread_data - return data value specified on kthread creation |
63 | * @task: kthread task in question | 88 | * @task: kthread task in question |
64 | * | 89 | * |
@@ -257,7 +282,7 @@ int kthreadd(void *unused) | |||
257 | set_cpus_allowed_ptr(tsk, cpu_all_mask); | 282 | set_cpus_allowed_ptr(tsk, cpu_all_mask); |
258 | set_mems_allowed(node_states[N_HIGH_MEMORY]); | 283 | set_mems_allowed(node_states[N_HIGH_MEMORY]); |
259 | 284 | ||
260 | current->flags |= PF_NOFREEZE | PF_FREEZER_NOSIG; | 285 | current->flags |= PF_NOFREEZE; |
261 | 286 | ||
262 | for (;;) { | 287 | for (;;) { |
263 | set_current_state(TASK_INTERRUPTIBLE); | 288 | set_current_state(TASK_INTERRUPTIBLE); |
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index a6b0503574ee..6d6d28870335 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c | |||
@@ -43,8 +43,6 @@ int in_suspend __nosavedata; | |||
43 | enum { | 43 | enum { |
44 | HIBERNATION_INVALID, | 44 | HIBERNATION_INVALID, |
45 | HIBERNATION_PLATFORM, | 45 | HIBERNATION_PLATFORM, |
46 | HIBERNATION_TEST, | ||
47 | HIBERNATION_TESTPROC, | ||
48 | HIBERNATION_SHUTDOWN, | 46 | HIBERNATION_SHUTDOWN, |
49 | HIBERNATION_REBOOT, | 47 | HIBERNATION_REBOOT, |
50 | /* keep last */ | 48 | /* keep last */ |
@@ -55,7 +53,7 @@ enum { | |||
55 | 53 | ||
56 | static int hibernation_mode = HIBERNATION_SHUTDOWN; | 54 | static int hibernation_mode = HIBERNATION_SHUTDOWN; |
57 | 55 | ||
58 | static bool freezer_test_done; | 56 | bool freezer_test_done; |
59 | 57 | ||
60 | static const struct platform_hibernation_ops *hibernation_ops; | 58 | static const struct platform_hibernation_ops *hibernation_ops; |
61 | 59 | ||
@@ -71,14 +69,14 @@ void hibernation_set_ops(const struct platform_hibernation_ops *ops) | |||
71 | WARN_ON(1); | 69 | WARN_ON(1); |
72 | return; | 70 | return; |
73 | } | 71 | } |
74 | mutex_lock(&pm_mutex); | 72 | lock_system_sleep(); |
75 | hibernation_ops = ops; | 73 | hibernation_ops = ops; |
76 | if (ops) | 74 | if (ops) |
77 | hibernation_mode = HIBERNATION_PLATFORM; | 75 | hibernation_mode = HIBERNATION_PLATFORM; |
78 | else if (hibernation_mode == HIBERNATION_PLATFORM) | 76 | else if (hibernation_mode == HIBERNATION_PLATFORM) |
79 | hibernation_mode = HIBERNATION_SHUTDOWN; | 77 | hibernation_mode = HIBERNATION_SHUTDOWN; |
80 | 78 | ||
81 | mutex_unlock(&pm_mutex); | 79 | unlock_system_sleep(); |
82 | } | 80 | } |
83 | 81 | ||
84 | static bool entering_platform_hibernation; | 82 | static bool entering_platform_hibernation; |
@@ -96,15 +94,6 @@ static void hibernation_debug_sleep(void) | |||
96 | mdelay(5000); | 94 | mdelay(5000); |
97 | } | 95 | } |
98 | 96 | ||
99 | static int hibernation_testmode(int mode) | ||
100 | { | ||
101 | if (hibernation_mode == mode) { | ||
102 | hibernation_debug_sleep(); | ||
103 | return 1; | ||
104 | } | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int hibernation_test(int level) | 97 | static int hibernation_test(int level) |
109 | { | 98 | { |
110 | if (pm_test_level == level) { | 99 | if (pm_test_level == level) { |
@@ -114,7 +103,6 @@ static int hibernation_test(int level) | |||
114 | return 0; | 103 | return 0; |
115 | } | 104 | } |
116 | #else /* !CONFIG_PM_DEBUG */ | 105 | #else /* !CONFIG_PM_DEBUG */ |
117 | static int hibernation_testmode(int mode) { return 0; } | ||
118 | static int hibernation_test(int level) { return 0; } | 106 | static int hibernation_test(int level) { return 0; } |
119 | #endif /* !CONFIG_PM_DEBUG */ | 107 | #endif /* !CONFIG_PM_DEBUG */ |
120 | 108 | ||
@@ -278,8 +266,7 @@ static int create_image(int platform_mode) | |||
278 | goto Platform_finish; | 266 | goto Platform_finish; |
279 | 267 | ||
280 | error = disable_nonboot_cpus(); | 268 | error = disable_nonboot_cpus(); |
281 | if (error || hibernation_test(TEST_CPUS) | 269 | if (error || hibernation_test(TEST_CPUS)) |
282 | || hibernation_testmode(HIBERNATION_TEST)) | ||
283 | goto Enable_cpus; | 270 | goto Enable_cpus; |
284 | 271 | ||
285 | local_irq_disable(); | 272 | local_irq_disable(); |
@@ -333,7 +320,7 @@ static int create_image(int platform_mode) | |||
333 | */ | 320 | */ |
334 | int hibernation_snapshot(int platform_mode) | 321 | int hibernation_snapshot(int platform_mode) |
335 | { | 322 | { |
336 | pm_message_t msg = PMSG_RECOVER; | 323 | pm_message_t msg; |
337 | int error; | 324 | int error; |
338 | 325 | ||
339 | error = platform_begin(platform_mode); | 326 | error = platform_begin(platform_mode); |
@@ -349,8 +336,7 @@ int hibernation_snapshot(int platform_mode) | |||
349 | if (error) | 336 | if (error) |
350 | goto Cleanup; | 337 | goto Cleanup; |
351 | 338 | ||
352 | if (hibernation_test(TEST_FREEZER) || | 339 | if (hibernation_test(TEST_FREEZER)) { |
353 | hibernation_testmode(HIBERNATION_TESTPROC)) { | ||
354 | 340 | ||
355 | /* | 341 | /* |
356 | * Indicate to the caller that we are returning due to a | 342 | * Indicate to the caller that we are returning due to a |
@@ -362,26 +348,26 @@ int hibernation_snapshot(int platform_mode) | |||
362 | 348 | ||
363 | error = dpm_prepare(PMSG_FREEZE); | 349 | error = dpm_prepare(PMSG_FREEZE); |
364 | if (error) { | 350 | if (error) { |
365 | dpm_complete(msg); | 351 | dpm_complete(PMSG_RECOVER); |
366 | goto Cleanup; | 352 | goto Cleanup; |
367 | } | 353 | } |
368 | 354 | ||
369 | suspend_console(); | 355 | suspend_console(); |
370 | pm_restrict_gfp_mask(); | 356 | pm_restrict_gfp_mask(); |
357 | |||
371 | error = dpm_suspend(PMSG_FREEZE); | 358 | error = dpm_suspend(PMSG_FREEZE); |
372 | if (error) | ||
373 | goto Recover_platform; | ||
374 | 359 | ||
375 | if (hibernation_test(TEST_DEVICES)) | 360 | if (error || hibernation_test(TEST_DEVICES)) |
376 | goto Recover_platform; | 361 | platform_recover(platform_mode); |
362 | else | ||
363 | error = create_image(platform_mode); | ||
377 | 364 | ||
378 | error = create_image(platform_mode); | ||
379 | /* | 365 | /* |
380 | * Control returns here (1) after the image has been created or the | 366 | * In the case that we call create_image() above, the control |
367 | * returns here (1) after the image has been created or the | ||
381 | * image creation has failed and (2) after a successful restore. | 368 | * image creation has failed and (2) after a successful restore. |
382 | */ | 369 | */ |
383 | 370 | ||
384 | Resume_devices: | ||
385 | /* We may need to release the preallocated image pages here. */ | 371 | /* We may need to release the preallocated image pages here. */ |
386 | if (error || !in_suspend) | 372 | if (error || !in_suspend) |
387 | swsusp_free(); | 373 | swsusp_free(); |
@@ -399,10 +385,6 @@ int hibernation_snapshot(int platform_mode) | |||
399 | platform_end(platform_mode); | 385 | platform_end(platform_mode); |
400 | return error; | 386 | return error; |
401 | 387 | ||
402 | Recover_platform: | ||
403 | platform_recover(platform_mode); | ||
404 | goto Resume_devices; | ||
405 | |||
406 | Cleanup: | 388 | Cleanup: |
407 | swsusp_free(); | 389 | swsusp_free(); |
408 | goto Close; | 390 | goto Close; |
@@ -590,9 +572,6 @@ int hibernation_platform_enter(void) | |||
590 | static void power_down(void) | 572 | static void power_down(void) |
591 | { | 573 | { |
592 | switch (hibernation_mode) { | 574 | switch (hibernation_mode) { |
593 | case HIBERNATION_TEST: | ||
594 | case HIBERNATION_TESTPROC: | ||
595 | break; | ||
596 | case HIBERNATION_REBOOT: | 575 | case HIBERNATION_REBOOT: |
597 | kernel_restart(NULL); | 576 | kernel_restart(NULL); |
598 | break; | 577 | break; |
@@ -611,17 +590,6 @@ static void power_down(void) | |||
611 | while(1); | 590 | while(1); |
612 | } | 591 | } |
613 | 592 | ||
614 | static int prepare_processes(void) | ||
615 | { | ||
616 | int error = 0; | ||
617 | |||
618 | if (freeze_processes()) { | ||
619 | error = -EBUSY; | ||
620 | thaw_processes(); | ||
621 | } | ||
622 | return error; | ||
623 | } | ||
624 | |||
625 | /** | 593 | /** |
626 | * hibernate - Carry out system hibernation, including saving the image. | 594 | * hibernate - Carry out system hibernation, including saving the image. |
627 | */ | 595 | */ |
@@ -629,7 +597,7 @@ int hibernate(void) | |||
629 | { | 597 | { |
630 | int error; | 598 | int error; |
631 | 599 | ||
632 | mutex_lock(&pm_mutex); | 600 | lock_system_sleep(); |
633 | /* The snapshot device should not be opened while we're running */ | 601 | /* The snapshot device should not be opened while we're running */ |
634 | if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { | 602 | if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { |
635 | error = -EBUSY; | 603 | error = -EBUSY; |
@@ -654,7 +622,7 @@ int hibernate(void) | |||
654 | sys_sync(); | 622 | sys_sync(); |
655 | printk("done.\n"); | 623 | printk("done.\n"); |
656 | 624 | ||
657 | error = prepare_processes(); | 625 | error = freeze_processes(); |
658 | if (error) | 626 | if (error) |
659 | goto Finish; | 627 | goto Finish; |
660 | 628 | ||
@@ -697,7 +665,7 @@ int hibernate(void) | |||
697 | pm_restore_console(); | 665 | pm_restore_console(); |
698 | atomic_inc(&snapshot_device_available); | 666 | atomic_inc(&snapshot_device_available); |
699 | Unlock: | 667 | Unlock: |
700 | mutex_unlock(&pm_mutex); | 668 | unlock_system_sleep(); |
701 | return error; | 669 | return error; |
702 | } | 670 | } |
703 | 671 | ||
@@ -811,11 +779,13 @@ static int software_resume(void) | |||
811 | goto close_finish; | 779 | goto close_finish; |
812 | 780 | ||
813 | error = create_basic_memory_bitmaps(); | 781 | error = create_basic_memory_bitmaps(); |
814 | if (error) | 782 | if (error) { |
783 | usermodehelper_enable(); | ||
815 | goto close_finish; | 784 | goto close_finish; |
785 | } | ||
816 | 786 | ||
817 | pr_debug("PM: Preparing processes for restore.\n"); | 787 | pr_debug("PM: Preparing processes for restore.\n"); |
818 | error = prepare_processes(); | 788 | error = freeze_processes(); |
819 | if (error) { | 789 | if (error) { |
820 | swsusp_close(FMODE_READ); | 790 | swsusp_close(FMODE_READ); |
821 | goto Done; | 791 | goto Done; |
@@ -855,8 +825,6 @@ static const char * const hibernation_modes[] = { | |||
855 | [HIBERNATION_PLATFORM] = "platform", | 825 | [HIBERNATION_PLATFORM] = "platform", |
856 | [HIBERNATION_SHUTDOWN] = "shutdown", | 826 | [HIBERNATION_SHUTDOWN] = "shutdown", |
857 | [HIBERNATION_REBOOT] = "reboot", | 827 | [HIBERNATION_REBOOT] = "reboot", |
858 | [HIBERNATION_TEST] = "test", | ||
859 | [HIBERNATION_TESTPROC] = "testproc", | ||
860 | }; | 828 | }; |
861 | 829 | ||
862 | /* | 830 | /* |
@@ -865,17 +833,15 @@ static const char * const hibernation_modes[] = { | |||
865 | * Hibernation can be handled in several ways. There are a few different ways | 833 | * Hibernation can be handled in several ways. There are a few different ways |
866 | * to put the system into the sleep state: using the platform driver (e.g. ACPI | 834 | * to put the system into the sleep state: using the platform driver (e.g. ACPI |
867 | * or other hibernation_ops), powering it off or rebooting it (for testing | 835 | * or other hibernation_ops), powering it off or rebooting it (for testing |
868 | * mostly), or using one of the two available test modes. | 836 | * mostly). |
869 | * | 837 | * |
870 | * The sysfs file /sys/power/disk provides an interface for selecting the | 838 | * The sysfs file /sys/power/disk provides an interface for selecting the |
871 | * hibernation mode to use. Reading from this file causes the available modes | 839 | * hibernation mode to use. Reading from this file causes the available modes |
872 | * to be printed. There are 5 modes that can be supported: | 840 | * to be printed. There are 3 modes that can be supported: |
873 | * | 841 | * |
874 | * 'platform' | 842 | * 'platform' |
875 | * 'shutdown' | 843 | * 'shutdown' |
876 | * 'reboot' | 844 | * 'reboot' |
877 | * 'test' | ||
878 | * 'testproc' | ||
879 | * | 845 | * |
880 | * If a platform hibernation driver is in use, 'platform' will be supported | 846 | * If a platform hibernation driver is in use, 'platform' will be supported |
881 | * and will be used by default. Otherwise, 'shutdown' will be used by default. | 847 | * and will be used by default. Otherwise, 'shutdown' will be used by default. |
@@ -899,8 +865,6 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr, | |||
899 | switch (i) { | 865 | switch (i) { |
900 | case HIBERNATION_SHUTDOWN: | 866 | case HIBERNATION_SHUTDOWN: |
901 | case HIBERNATION_REBOOT: | 867 | case HIBERNATION_REBOOT: |
902 | case HIBERNATION_TEST: | ||
903 | case HIBERNATION_TESTPROC: | ||
904 | break; | 868 | break; |
905 | case HIBERNATION_PLATFORM: | 869 | case HIBERNATION_PLATFORM: |
906 | if (hibernation_ops) | 870 | if (hibernation_ops) |
@@ -929,7 +893,7 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
929 | p = memchr(buf, '\n', n); | 893 | p = memchr(buf, '\n', n); |
930 | len = p ? p - buf : n; | 894 | len = p ? p - buf : n; |
931 | 895 | ||
932 | mutex_lock(&pm_mutex); | 896 | lock_system_sleep(); |
933 | for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) { | 897 | for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) { |
934 | if (len == strlen(hibernation_modes[i]) | 898 | if (len == strlen(hibernation_modes[i]) |
935 | && !strncmp(buf, hibernation_modes[i], len)) { | 899 | && !strncmp(buf, hibernation_modes[i], len)) { |
@@ -941,8 +905,6 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
941 | switch (mode) { | 905 | switch (mode) { |
942 | case HIBERNATION_SHUTDOWN: | 906 | case HIBERNATION_SHUTDOWN: |
943 | case HIBERNATION_REBOOT: | 907 | case HIBERNATION_REBOOT: |
944 | case HIBERNATION_TEST: | ||
945 | case HIBERNATION_TESTPROC: | ||
946 | hibernation_mode = mode; | 908 | hibernation_mode = mode; |
947 | break; | 909 | break; |
948 | case HIBERNATION_PLATFORM: | 910 | case HIBERNATION_PLATFORM: |
@@ -957,7 +919,7 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
957 | if (!error) | 919 | if (!error) |
958 | pr_debug("PM: Hibernation mode set to '%s'\n", | 920 | pr_debug("PM: Hibernation mode set to '%s'\n", |
959 | hibernation_modes[mode]); | 921 | hibernation_modes[mode]); |
960 | mutex_unlock(&pm_mutex); | 922 | unlock_system_sleep(); |
961 | return error ? error : n; | 923 | return error ? error : n; |
962 | } | 924 | } |
963 | 925 | ||
@@ -984,9 +946,9 @@ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
984 | if (maj != MAJOR(res) || min != MINOR(res)) | 946 | if (maj != MAJOR(res) || min != MINOR(res)) |
985 | goto out; | 947 | goto out; |
986 | 948 | ||
987 | mutex_lock(&pm_mutex); | 949 | lock_system_sleep(); |
988 | swsusp_resume_device = res; | 950 | swsusp_resume_device = res; |
989 | mutex_unlock(&pm_mutex); | 951 | unlock_system_sleep(); |
990 | printk(KERN_INFO "PM: Starting manual resume from disk\n"); | 952 | printk(KERN_INFO "PM: Starting manual resume from disk\n"); |
991 | noresume = 0; | 953 | noresume = 0; |
992 | software_resume(); | 954 | software_resume(); |
diff --git a/kernel/power/main.c b/kernel/power/main.c index 36e0f0903c32..9824b41e5a18 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (c) 2003 Patrick Mochel | 4 | * Copyright (c) 2003 Patrick Mochel |
5 | * Copyright (c) 2003 Open Source Development Lab | 5 | * Copyright (c) 2003 Open Source Development Lab |
6 | * | 6 | * |
7 | * This file is released under the GPLv2 | 7 | * This file is released under the GPLv2 |
8 | * | 8 | * |
9 | */ | 9 | */ |
@@ -116,7 +116,7 @@ static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
116 | p = memchr(buf, '\n', n); | 116 | p = memchr(buf, '\n', n); |
117 | len = p ? p - buf : n; | 117 | len = p ? p - buf : n; |
118 | 118 | ||
119 | mutex_lock(&pm_mutex); | 119 | lock_system_sleep(); |
120 | 120 | ||
121 | level = TEST_FIRST; | 121 | level = TEST_FIRST; |
122 | for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++) | 122 | for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++) |
@@ -126,7 +126,7 @@ static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
126 | break; | 126 | break; |
127 | } | 127 | } |
128 | 128 | ||
129 | mutex_unlock(&pm_mutex); | 129 | unlock_system_sleep(); |
130 | 130 | ||
131 | return error ? error : n; | 131 | return error ? error : n; |
132 | } | 132 | } |
@@ -240,7 +240,7 @@ struct kobject *power_kobj; | |||
240 | * 'standby' (Power-On Suspend), 'mem' (Suspend-to-RAM), and | 240 | * 'standby' (Power-On Suspend), 'mem' (Suspend-to-RAM), and |
241 | * 'disk' (Suspend-to-Disk). | 241 | * 'disk' (Suspend-to-Disk). |
242 | * | 242 | * |
243 | * store() accepts one of those strings, translates it into the | 243 | * store() accepts one of those strings, translates it into the |
244 | * proper enumerated value, and initiates a suspend transition. | 244 | * proper enumerated value, and initiates a suspend transition. |
245 | */ | 245 | */ |
246 | static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, | 246 | static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, |
@@ -282,7 +282,7 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
282 | /* First, check if we are requested to hibernate */ | 282 | /* First, check if we are requested to hibernate */ |
283 | if (len == 4 && !strncmp(buf, "disk", len)) { | 283 | if (len == 4 && !strncmp(buf, "disk", len)) { |
284 | error = hibernate(); | 284 | error = hibernate(); |
285 | goto Exit; | 285 | goto Exit; |
286 | } | 286 | } |
287 | 287 | ||
288 | #ifdef CONFIG_SUSPEND | 288 | #ifdef CONFIG_SUSPEND |
diff --git a/kernel/power/power.h b/kernel/power/power.h index 23a2db1ec442..0c4defe6d3b8 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h | |||
@@ -50,6 +50,8 @@ static inline char *check_image_kernel(struct swsusp_info *info) | |||
50 | #define SPARE_PAGES ((1024 * 1024) >> PAGE_SHIFT) | 50 | #define SPARE_PAGES ((1024 * 1024) >> PAGE_SHIFT) |
51 | 51 | ||
52 | /* kernel/power/hibernate.c */ | 52 | /* kernel/power/hibernate.c */ |
53 | extern bool freezer_test_done; | ||
54 | |||
53 | extern int hibernation_snapshot(int platform_mode); | 55 | extern int hibernation_snapshot(int platform_mode); |
54 | extern int hibernation_restore(int platform_mode); | 56 | extern int hibernation_restore(int platform_mode); |
55 | extern int hibernation_platform_enter(void); | 57 | extern int hibernation_platform_enter(void); |
diff --git a/kernel/power/process.c b/kernel/power/process.c index addbbe5531bc..77274c9ba2f1 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c | |||
@@ -22,16 +22,7 @@ | |||
22 | */ | 22 | */ |
23 | #define TIMEOUT (20 * HZ) | 23 | #define TIMEOUT (20 * HZ) |
24 | 24 | ||
25 | static inline int freezable(struct task_struct * p) | 25 | static int try_to_freeze_tasks(bool user_only) |
26 | { | ||
27 | if ((p == current) || | ||
28 | (p->flags & PF_NOFREEZE) || | ||
29 | (p->exit_state != 0)) | ||
30 | return 0; | ||
31 | return 1; | ||
32 | } | ||
33 | |||
34 | static int try_to_freeze_tasks(bool sig_only) | ||
35 | { | 26 | { |
36 | struct task_struct *g, *p; | 27 | struct task_struct *g, *p; |
37 | unsigned long end_time; | 28 | unsigned long end_time; |
@@ -46,17 +37,14 @@ static int try_to_freeze_tasks(bool sig_only) | |||
46 | 37 | ||
47 | end_time = jiffies + TIMEOUT; | 38 | end_time = jiffies + TIMEOUT; |
48 | 39 | ||
49 | if (!sig_only) | 40 | if (!user_only) |
50 | freeze_workqueues_begin(); | 41 | freeze_workqueues_begin(); |
51 | 42 | ||
52 | while (true) { | 43 | while (true) { |
53 | todo = 0; | 44 | todo = 0; |
54 | read_lock(&tasklist_lock); | 45 | read_lock(&tasklist_lock); |
55 | do_each_thread(g, p) { | 46 | do_each_thread(g, p) { |
56 | if (frozen(p) || !freezable(p)) | 47 | if (p == current || !freeze_task(p)) |
57 | continue; | ||
58 | |||
59 | if (!freeze_task(p, sig_only)) | ||
60 | continue; | 48 | continue; |
61 | 49 | ||
62 | /* | 50 | /* |
@@ -77,7 +65,7 @@ static int try_to_freeze_tasks(bool sig_only) | |||
77 | } while_each_thread(g, p); | 65 | } while_each_thread(g, p); |
78 | read_unlock(&tasklist_lock); | 66 | read_unlock(&tasklist_lock); |
79 | 67 | ||
80 | if (!sig_only) { | 68 | if (!user_only) { |
81 | wq_busy = freeze_workqueues_busy(); | 69 | wq_busy = freeze_workqueues_busy(); |
82 | todo += wq_busy; | 70 | todo += wq_busy; |
83 | } | 71 | } |
@@ -103,11 +91,6 @@ static int try_to_freeze_tasks(bool sig_only) | |||
103 | elapsed_csecs = elapsed_csecs64; | 91 | elapsed_csecs = elapsed_csecs64; |
104 | 92 | ||
105 | if (todo) { | 93 | if (todo) { |
106 | /* This does not unfreeze processes that are already frozen | ||
107 | * (we have slightly ugly calling convention in that respect, | ||
108 | * and caller must call thaw_processes() if something fails), | ||
109 | * but it cleans up leftover PF_FREEZE requests. | ||
110 | */ | ||
111 | printk("\n"); | 94 | printk("\n"); |
112 | printk(KERN_ERR "Freezing of tasks %s after %d.%02d seconds " | 95 | printk(KERN_ERR "Freezing of tasks %s after %d.%02d seconds " |
113 | "(%d tasks refusing to freeze, wq_busy=%d):\n", | 96 | "(%d tasks refusing to freeze, wq_busy=%d):\n", |
@@ -115,15 +98,11 @@ static int try_to_freeze_tasks(bool sig_only) | |||
115 | elapsed_csecs / 100, elapsed_csecs % 100, | 98 | elapsed_csecs / 100, elapsed_csecs % 100, |
116 | todo - wq_busy, wq_busy); | 99 | todo - wq_busy, wq_busy); |
117 | 100 | ||
118 | thaw_workqueues(); | ||
119 | |||
120 | read_lock(&tasklist_lock); | 101 | read_lock(&tasklist_lock); |
121 | do_each_thread(g, p) { | 102 | do_each_thread(g, p) { |
122 | task_lock(p); | 103 | if (!wakeup && !freezer_should_skip(p) && |
123 | if (!wakeup && freezing(p) && !freezer_should_skip(p)) | 104 | p != current && freezing(p) && !frozen(p)) |
124 | sched_show_task(p); | 105 | sched_show_task(p); |
125 | cancel_freezing(p); | ||
126 | task_unlock(p); | ||
127 | } while_each_thread(g, p); | 106 | } while_each_thread(g, p); |
128 | read_unlock(&tasklist_lock); | 107 | read_unlock(&tasklist_lock); |
129 | } else { | 108 | } else { |
@@ -136,12 +115,18 @@ static int try_to_freeze_tasks(bool sig_only) | |||
136 | 115 | ||
137 | /** | 116 | /** |
138 | * freeze_processes - Signal user space processes to enter the refrigerator. | 117 | * freeze_processes - Signal user space processes to enter the refrigerator. |
118 | * | ||
119 | * On success, returns 0. On failure, -errno and system is fully thawed. | ||
139 | */ | 120 | */ |
140 | int freeze_processes(void) | 121 | int freeze_processes(void) |
141 | { | 122 | { |
142 | int error; | 123 | int error; |
143 | 124 | ||
125 | if (!pm_freezing) | ||
126 | atomic_inc(&system_freezing_cnt); | ||
127 | |||
144 | printk("Freezing user space processes ... "); | 128 | printk("Freezing user space processes ... "); |
129 | pm_freezing = true; | ||
145 | error = try_to_freeze_tasks(true); | 130 | error = try_to_freeze_tasks(true); |
146 | if (!error) { | 131 | if (!error) { |
147 | printk("done."); | 132 | printk("done."); |
@@ -150,17 +135,22 @@ int freeze_processes(void) | |||
150 | printk("\n"); | 135 | printk("\n"); |
151 | BUG_ON(in_atomic()); | 136 | BUG_ON(in_atomic()); |
152 | 137 | ||
138 | if (error) | ||
139 | thaw_processes(); | ||
153 | return error; | 140 | return error; |
154 | } | 141 | } |
155 | 142 | ||
156 | /** | 143 | /** |
157 | * freeze_kernel_threads - Make freezable kernel threads go to the refrigerator. | 144 | * freeze_kernel_threads - Make freezable kernel threads go to the refrigerator. |
145 | * | ||
146 | * On success, returns 0. On failure, -errno and system is fully thawed. | ||
158 | */ | 147 | */ |
159 | int freeze_kernel_threads(void) | 148 | int freeze_kernel_threads(void) |
160 | { | 149 | { |
161 | int error; | 150 | int error; |
162 | 151 | ||
163 | printk("Freezing remaining freezable tasks ... "); | 152 | printk("Freezing remaining freezable tasks ... "); |
153 | pm_nosig_freezing = true; | ||
164 | error = try_to_freeze_tasks(false); | 154 | error = try_to_freeze_tasks(false); |
165 | if (!error) | 155 | if (!error) |
166 | printk("done."); | 156 | printk("done."); |
@@ -168,37 +158,32 @@ int freeze_kernel_threads(void) | |||
168 | printk("\n"); | 158 | printk("\n"); |
169 | BUG_ON(in_atomic()); | 159 | BUG_ON(in_atomic()); |
170 | 160 | ||
161 | if (error) | ||
162 | thaw_processes(); | ||
171 | return error; | 163 | return error; |
172 | } | 164 | } |
173 | 165 | ||
174 | static void thaw_tasks(bool nosig_only) | 166 | void thaw_processes(void) |
175 | { | 167 | { |
176 | struct task_struct *g, *p; | 168 | struct task_struct *g, *p; |
177 | 169 | ||
178 | read_lock(&tasklist_lock); | 170 | if (pm_freezing) |
179 | do_each_thread(g, p) { | 171 | atomic_dec(&system_freezing_cnt); |
180 | if (!freezable(p)) | 172 | pm_freezing = false; |
181 | continue; | 173 | pm_nosig_freezing = false; |
182 | 174 | ||
183 | if (nosig_only && should_send_signal(p)) | 175 | oom_killer_enable(); |
184 | continue; | 176 | |
177 | printk("Restarting tasks ... "); | ||
185 | 178 | ||
186 | if (cgroup_freezing_or_frozen(p)) | 179 | thaw_workqueues(); |
187 | continue; | ||
188 | 180 | ||
189 | thaw_process(p); | 181 | read_lock(&tasklist_lock); |
182 | do_each_thread(g, p) { | ||
183 | __thaw_task(p); | ||
190 | } while_each_thread(g, p); | 184 | } while_each_thread(g, p); |
191 | read_unlock(&tasklist_lock); | 185 | read_unlock(&tasklist_lock); |
192 | } | ||
193 | 186 | ||
194 | void thaw_processes(void) | ||
195 | { | ||
196 | oom_killer_enable(); | ||
197 | |||
198 | printk("Restarting tasks ... "); | ||
199 | thaw_workqueues(); | ||
200 | thaw_tasks(true); | ||
201 | thaw_tasks(false); | ||
202 | schedule(); | 187 | schedule(); |
203 | printk("done.\n"); | 188 | printk("done.\n"); |
204 | } | 189 | } |
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 4953dc054c53..4fd51beed879 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c | |||
@@ -42,9 +42,9 @@ static const struct platform_suspend_ops *suspend_ops; | |||
42 | */ | 42 | */ |
43 | void suspend_set_ops(const struct platform_suspend_ops *ops) | 43 | void suspend_set_ops(const struct platform_suspend_ops *ops) |
44 | { | 44 | { |
45 | mutex_lock(&pm_mutex); | 45 | lock_system_sleep(); |
46 | suspend_ops = ops; | 46 | suspend_ops = ops; |
47 | mutex_unlock(&pm_mutex); | 47 | unlock_system_sleep(); |
48 | } | 48 | } |
49 | EXPORT_SYMBOL_GPL(suspend_set_ops); | 49 | EXPORT_SYMBOL_GPL(suspend_set_ops); |
50 | 50 | ||
@@ -106,13 +106,11 @@ static int suspend_prepare(void) | |||
106 | goto Finish; | 106 | goto Finish; |
107 | 107 | ||
108 | error = suspend_freeze_processes(); | 108 | error = suspend_freeze_processes(); |
109 | if (error) { | 109 | if (!error) |
110 | suspend_stats.failed_freeze++; | ||
111 | dpm_save_failed_step(SUSPEND_FREEZE); | ||
112 | } else | ||
113 | return 0; | 110 | return 0; |
114 | 111 | ||
115 | suspend_thaw_processes(); | 112 | suspend_stats.failed_freeze++; |
113 | dpm_save_failed_step(SUSPEND_FREEZE); | ||
116 | usermodehelper_enable(); | 114 | usermodehelper_enable(); |
117 | Finish: | 115 | Finish: |
118 | pm_notifier_call_chain(PM_POST_SUSPEND); | 116 | pm_notifier_call_chain(PM_POST_SUSPEND); |
diff --git a/kernel/power/user.c b/kernel/power/user.c index 6d8f535c2b88..6b1ab7a88522 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/swapops.h> | 21 | #include <linux/swapops.h> |
22 | #include <linux/pm.h> | 22 | #include <linux/pm.h> |
23 | #include <linux/fs.h> | 23 | #include <linux/fs.h> |
24 | #include <linux/compat.h> | ||
24 | #include <linux/console.h> | 25 | #include <linux/console.h> |
25 | #include <linux/cpu.h> | 26 | #include <linux/cpu.h> |
26 | #include <linux/freezer.h> | 27 | #include <linux/freezer.h> |
@@ -30,28 +31,6 @@ | |||
30 | 31 | ||
31 | #include "power.h" | 32 | #include "power.h" |
32 | 33 | ||
33 | /* | ||
34 | * NOTE: The SNAPSHOT_SET_SWAP_FILE and SNAPSHOT_PMOPS ioctls are obsolete and | ||
35 | * will be removed in the future. They are only preserved here for | ||
36 | * compatibility with existing userland utilities. | ||
37 | */ | ||
38 | #define SNAPSHOT_SET_SWAP_FILE _IOW(SNAPSHOT_IOC_MAGIC, 10, unsigned int) | ||
39 | #define SNAPSHOT_PMOPS _IOW(SNAPSHOT_IOC_MAGIC, 12, unsigned int) | ||
40 | |||
41 | #define PMOPS_PREPARE 1 | ||
42 | #define PMOPS_ENTER 2 | ||
43 | #define PMOPS_FINISH 3 | ||
44 | |||
45 | /* | ||
46 | * NOTE: The following ioctl definitions are wrong and have been replaced with | ||
47 | * correct ones. They are only preserved here for compatibility with existing | ||
48 | * userland utilities and will be removed in the future. | ||
49 | */ | ||
50 | #define SNAPSHOT_ATOMIC_SNAPSHOT _IOW(SNAPSHOT_IOC_MAGIC, 3, void *) | ||
51 | #define SNAPSHOT_SET_IMAGE_SIZE _IOW(SNAPSHOT_IOC_MAGIC, 6, unsigned long) | ||
52 | #define SNAPSHOT_AVAIL_SWAP _IOR(SNAPSHOT_IOC_MAGIC, 7, void *) | ||
53 | #define SNAPSHOT_GET_SWAP_PAGE _IOR(SNAPSHOT_IOC_MAGIC, 8, void *) | ||
54 | |||
55 | 34 | ||
56 | #define SNAPSHOT_MINOR 231 | 35 | #define SNAPSHOT_MINOR 231 |
57 | 36 | ||
@@ -71,7 +50,7 @@ static int snapshot_open(struct inode *inode, struct file *filp) | |||
71 | struct snapshot_data *data; | 50 | struct snapshot_data *data; |
72 | int error; | 51 | int error; |
73 | 52 | ||
74 | mutex_lock(&pm_mutex); | 53 | lock_system_sleep(); |
75 | 54 | ||
76 | if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { | 55 | if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { |
77 | error = -EBUSY; | 56 | error = -EBUSY; |
@@ -123,7 +102,7 @@ static int snapshot_open(struct inode *inode, struct file *filp) | |||
123 | data->platform_support = 0; | 102 | data->platform_support = 0; |
124 | 103 | ||
125 | Unlock: | 104 | Unlock: |
126 | mutex_unlock(&pm_mutex); | 105 | unlock_system_sleep(); |
127 | 106 | ||
128 | return error; | 107 | return error; |
129 | } | 108 | } |
@@ -132,7 +111,7 @@ static int snapshot_release(struct inode *inode, struct file *filp) | |||
132 | { | 111 | { |
133 | struct snapshot_data *data; | 112 | struct snapshot_data *data; |
134 | 113 | ||
135 | mutex_lock(&pm_mutex); | 114 | lock_system_sleep(); |
136 | 115 | ||
137 | swsusp_free(); | 116 | swsusp_free(); |
138 | free_basic_memory_bitmaps(); | 117 | free_basic_memory_bitmaps(); |
@@ -146,7 +125,7 @@ static int snapshot_release(struct inode *inode, struct file *filp) | |||
146 | PM_POST_HIBERNATION : PM_POST_RESTORE); | 125 | PM_POST_HIBERNATION : PM_POST_RESTORE); |
147 | atomic_inc(&snapshot_device_available); | 126 | atomic_inc(&snapshot_device_available); |
148 | 127 | ||
149 | mutex_unlock(&pm_mutex); | 128 | unlock_system_sleep(); |
150 | 129 | ||
151 | return 0; | 130 | return 0; |
152 | } | 131 | } |
@@ -158,7 +137,7 @@ static ssize_t snapshot_read(struct file *filp, char __user *buf, | |||
158 | ssize_t res; | 137 | ssize_t res; |
159 | loff_t pg_offp = *offp & ~PAGE_MASK; | 138 | loff_t pg_offp = *offp & ~PAGE_MASK; |
160 | 139 | ||
161 | mutex_lock(&pm_mutex); | 140 | lock_system_sleep(); |
162 | 141 | ||
163 | data = filp->private_data; | 142 | data = filp->private_data; |
164 | if (!data->ready) { | 143 | if (!data->ready) { |
@@ -179,7 +158,7 @@ static ssize_t snapshot_read(struct file *filp, char __user *buf, | |||
179 | *offp += res; | 158 | *offp += res; |
180 | 159 | ||
181 | Unlock: | 160 | Unlock: |
182 | mutex_unlock(&pm_mutex); | 161 | unlock_system_sleep(); |
183 | 162 | ||
184 | return res; | 163 | return res; |
185 | } | 164 | } |
@@ -191,7 +170,7 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf, | |||
191 | ssize_t res; | 170 | ssize_t res; |
192 | loff_t pg_offp = *offp & ~PAGE_MASK; | 171 | loff_t pg_offp = *offp & ~PAGE_MASK; |
193 | 172 | ||
194 | mutex_lock(&pm_mutex); | 173 | lock_system_sleep(); |
195 | 174 | ||
196 | data = filp->private_data; | 175 | data = filp->private_data; |
197 | 176 | ||
@@ -208,20 +187,11 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf, | |||
208 | if (res > 0) | 187 | if (res > 0) |
209 | *offp += res; | 188 | *offp += res; |
210 | unlock: | 189 | unlock: |
211 | mutex_unlock(&pm_mutex); | 190 | unlock_system_sleep(); |
212 | 191 | ||
213 | return res; | 192 | return res; |
214 | } | 193 | } |
215 | 194 | ||
216 | static void snapshot_deprecated_ioctl(unsigned int cmd) | ||
217 | { | ||
218 | if (printk_ratelimit()) | ||
219 | printk(KERN_NOTICE "%pf: ioctl '%.8x' is deprecated and will " | ||
220 | "be removed soon, update your suspend-to-disk " | ||
221 | "utilities\n", | ||
222 | __builtin_return_address(0), cmd); | ||
223 | } | ||
224 | |||
225 | static long snapshot_ioctl(struct file *filp, unsigned int cmd, | 195 | static long snapshot_ioctl(struct file *filp, unsigned int cmd, |
226 | unsigned long arg) | 196 | unsigned long arg) |
227 | { | 197 | { |
@@ -257,11 +227,9 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
257 | break; | 227 | break; |
258 | 228 | ||
259 | error = freeze_processes(); | 229 | error = freeze_processes(); |
260 | if (error) { | 230 | if (error) |
261 | thaw_processes(); | ||
262 | usermodehelper_enable(); | 231 | usermodehelper_enable(); |
263 | } | 232 | else |
264 | if (!error) | ||
265 | data->frozen = 1; | 233 | data->frozen = 1; |
266 | break; | 234 | break; |
267 | 235 | ||
@@ -274,8 +242,6 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
274 | data->frozen = 0; | 242 | data->frozen = 0; |
275 | break; | 243 | break; |
276 | 244 | ||
277 | case SNAPSHOT_ATOMIC_SNAPSHOT: | ||
278 | snapshot_deprecated_ioctl(cmd); | ||
279 | case SNAPSHOT_CREATE_IMAGE: | 245 | case SNAPSHOT_CREATE_IMAGE: |
280 | if (data->mode != O_RDONLY || !data->frozen || data->ready) { | 246 | if (data->mode != O_RDONLY || !data->frozen || data->ready) { |
281 | error = -EPERM; | 247 | error = -EPERM; |
@@ -283,10 +249,15 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
283 | } | 249 | } |
284 | pm_restore_gfp_mask(); | 250 | pm_restore_gfp_mask(); |
285 | error = hibernation_snapshot(data->platform_support); | 251 | error = hibernation_snapshot(data->platform_support); |
286 | if (!error) | 252 | if (!error) { |
287 | error = put_user(in_suspend, (int __user *)arg); | 253 | error = put_user(in_suspend, (int __user *)arg); |
288 | if (!error) | 254 | if (!error && !freezer_test_done) |
289 | data->ready = 1; | 255 | data->ready = 1; |
256 | if (freezer_test_done) { | ||
257 | freezer_test_done = false; | ||
258 | thaw_processes(); | ||
259 | } | ||
260 | } | ||
290 | break; | 261 | break; |
291 | 262 | ||
292 | case SNAPSHOT_ATOMIC_RESTORE: | 263 | case SNAPSHOT_ATOMIC_RESTORE: |
@@ -305,8 +276,6 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
305 | data->ready = 0; | 276 | data->ready = 0; |
306 | break; | 277 | break; |
307 | 278 | ||
308 | case SNAPSHOT_SET_IMAGE_SIZE: | ||
309 | snapshot_deprecated_ioctl(cmd); | ||
310 | case SNAPSHOT_PREF_IMAGE_SIZE: | 279 | case SNAPSHOT_PREF_IMAGE_SIZE: |
311 | image_size = arg; | 280 | image_size = arg; |
312 | break; | 281 | break; |
@@ -321,16 +290,12 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
321 | error = put_user(size, (loff_t __user *)arg); | 290 | error = put_user(size, (loff_t __user *)arg); |
322 | break; | 291 | break; |
323 | 292 | ||
324 | case SNAPSHOT_AVAIL_SWAP: | ||
325 | snapshot_deprecated_ioctl(cmd); | ||
326 | case SNAPSHOT_AVAIL_SWAP_SIZE: | 293 | case SNAPSHOT_AVAIL_SWAP_SIZE: |
327 | size = count_swap_pages(data->swap, 1); | 294 | size = count_swap_pages(data->swap, 1); |
328 | size <<= PAGE_SHIFT; | 295 | size <<= PAGE_SHIFT; |
329 | error = put_user(size, (loff_t __user *)arg); | 296 | error = put_user(size, (loff_t __user *)arg); |
330 | break; | 297 | break; |
331 | 298 | ||
332 | case SNAPSHOT_GET_SWAP_PAGE: | ||
333 | snapshot_deprecated_ioctl(cmd); | ||
334 | case SNAPSHOT_ALLOC_SWAP_PAGE: | 299 | case SNAPSHOT_ALLOC_SWAP_PAGE: |
335 | if (data->swap < 0 || data->swap >= MAX_SWAPFILES) { | 300 | if (data->swap < 0 || data->swap >= MAX_SWAPFILES) { |
336 | error = -ENODEV; | 301 | error = -ENODEV; |
@@ -353,27 +318,6 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
353 | free_all_swap_pages(data->swap); | 318 | free_all_swap_pages(data->swap); |
354 | break; | 319 | break; |
355 | 320 | ||
356 | case SNAPSHOT_SET_SWAP_FILE: /* This ioctl is deprecated */ | ||
357 | snapshot_deprecated_ioctl(cmd); | ||
358 | if (!swsusp_swap_in_use()) { | ||
359 | /* | ||
360 | * User space encodes device types as two-byte values, | ||
361 | * so we need to recode them | ||
362 | */ | ||
363 | if (old_decode_dev(arg)) { | ||
364 | data->swap = swap_type_of(old_decode_dev(arg), | ||
365 | 0, NULL); | ||
366 | if (data->swap < 0) | ||
367 | error = -ENODEV; | ||
368 | } else { | ||
369 | data->swap = -1; | ||
370 | error = -EINVAL; | ||
371 | } | ||
372 | } else { | ||
373 | error = -EPERM; | ||
374 | } | ||
375 | break; | ||
376 | |||
377 | case SNAPSHOT_S2RAM: | 321 | case SNAPSHOT_S2RAM: |
378 | if (!data->frozen) { | 322 | if (!data->frozen) { |
379 | error = -EPERM; | 323 | error = -EPERM; |
@@ -396,33 +340,6 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
396 | error = hibernation_platform_enter(); | 340 | error = hibernation_platform_enter(); |
397 | break; | 341 | break; |
398 | 342 | ||
399 | case SNAPSHOT_PMOPS: /* This ioctl is deprecated */ | ||
400 | snapshot_deprecated_ioctl(cmd); | ||
401 | error = -EINVAL; | ||
402 | |||
403 | switch (arg) { | ||
404 | |||
405 | case PMOPS_PREPARE: | ||
406 | data->platform_support = 1; | ||
407 | error = 0; | ||
408 | break; | ||
409 | |||
410 | case PMOPS_ENTER: | ||
411 | if (data->platform_support) | ||
412 | error = hibernation_platform_enter(); | ||
413 | break; | ||
414 | |||
415 | case PMOPS_FINISH: | ||
416 | if (data->platform_support) | ||
417 | error = 0; | ||
418 | break; | ||
419 | |||
420 | default: | ||
421 | printk(KERN_ERR "SNAPSHOT_PMOPS: invalid argument %ld\n", arg); | ||
422 | |||
423 | } | ||
424 | break; | ||
425 | |||
426 | case SNAPSHOT_SET_SWAP_AREA: | 343 | case SNAPSHOT_SET_SWAP_AREA: |
427 | if (swsusp_swap_in_use()) { | 344 | if (swsusp_swap_in_use()) { |
428 | error = -EPERM; | 345 | error = -EPERM; |
@@ -464,6 +381,66 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
464 | return error; | 381 | return error; |
465 | } | 382 | } |
466 | 383 | ||
384 | #ifdef CONFIG_COMPAT | ||
385 | |||
386 | struct compat_resume_swap_area { | ||
387 | compat_loff_t offset; | ||
388 | u32 dev; | ||
389 | } __packed; | ||
390 | |||
391 | static long | ||
392 | snapshot_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
393 | { | ||
394 | BUILD_BUG_ON(sizeof(loff_t) != sizeof(compat_loff_t)); | ||
395 | |||
396 | switch (cmd) { | ||
397 | case SNAPSHOT_GET_IMAGE_SIZE: | ||
398 | case SNAPSHOT_AVAIL_SWAP_SIZE: | ||
399 | case SNAPSHOT_ALLOC_SWAP_PAGE: { | ||
400 | compat_loff_t __user *uoffset = compat_ptr(arg); | ||
401 | loff_t offset; | ||
402 | mm_segment_t old_fs; | ||
403 | int err; | ||
404 | |||
405 | old_fs = get_fs(); | ||
406 | set_fs(KERNEL_DS); | ||
407 | err = snapshot_ioctl(file, cmd, (unsigned long) &offset); | ||
408 | set_fs(old_fs); | ||
409 | if (!err && put_user(offset, uoffset)) | ||
410 | err = -EFAULT; | ||
411 | return err; | ||
412 | } | ||
413 | |||
414 | case SNAPSHOT_CREATE_IMAGE: | ||
415 | return snapshot_ioctl(file, cmd, | ||
416 | (unsigned long) compat_ptr(arg)); | ||
417 | |||
418 | case SNAPSHOT_SET_SWAP_AREA: { | ||
419 | struct compat_resume_swap_area __user *u_swap_area = | ||
420 | compat_ptr(arg); | ||
421 | struct resume_swap_area swap_area; | ||
422 | mm_segment_t old_fs; | ||
423 | int err; | ||
424 | |||
425 | err = get_user(swap_area.offset, &u_swap_area->offset); | ||
426 | err |= get_user(swap_area.dev, &u_swap_area->dev); | ||
427 | if (err) | ||
428 | return -EFAULT; | ||
429 | old_fs = get_fs(); | ||
430 | set_fs(KERNEL_DS); | ||
431 | err = snapshot_ioctl(file, SNAPSHOT_SET_SWAP_AREA, | ||
432 | (unsigned long) &swap_area); | ||
433 | set_fs(old_fs); | ||
434 | return err; | ||
435 | } | ||
436 | |||
437 | default: | ||
438 | return snapshot_ioctl(file, cmd, arg); | ||
439 | } | ||
440 | } | ||
441 | |||
442 | #endif /* CONFIG_COMPAT */ | ||
443 | |||
467 | static const struct file_operations snapshot_fops = { | 444 | static const struct file_operations snapshot_fops = { |
468 | .open = snapshot_open, | 445 | .open = snapshot_open, |
469 | .release = snapshot_release, | 446 | .release = snapshot_release, |
@@ -471,6 +448,9 @@ static const struct file_operations snapshot_fops = { | |||
471 | .write = snapshot_write, | 448 | .write = snapshot_write, |
472 | .llseek = no_llseek, | 449 | .llseek = no_llseek, |
473 | .unlocked_ioctl = snapshot_ioctl, | 450 | .unlocked_ioctl = snapshot_ioctl, |
451 | #ifdef CONFIG_COMPAT | ||
452 | .compat_ioctl = snapshot_compat_ioctl, | ||
453 | #endif | ||
474 | }; | 454 | }; |
475 | 455 | ||
476 | static struct miscdevice snapshot_device = { | 456 | static struct miscdevice snapshot_device = { |