aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2011-11-21 15:32:24 -0500
committerTejun Heo <tj@kernel.org>2011-11-21 15:32:24 -0500
commit03afed8bc296fa70186ba832c1126228bb992465 (patch)
tree96d0a6a9bffdcfc678d31f21caa88e43693bde94
parent376fede80e74d98b49d1ba9ac18f23c9fd026ddd (diff)
freezer: clean up freeze_processes() failure path
freeze_processes() failure path is rather messy. Freezing is canceled for workqueues and tasks which aren't frozen yet but frozen tasks are left alone and should be thawed by the caller and of course some callers (xen and kexec) didn't do it. This patch updates __thaw_task() to handle cancelation correctly and makes freeze_processes() and freeze_kernel_threads() call thaw_processes() on failure instead so that the system is fully thawed on failure. Unnecessary [suspend_]thaw_processes() calls are removed from kernel/power/hibernate.c, suspend.c and user.c. While at it, restructure error checking if clause in suspend_prepare() to be less weird. -v2: Srivatsa spotted missing removal of suspend_thaw_processes() in suspend_prepare() and error in commit message. Updated. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
-rw-r--r--include/linux/freezer.h1
-rw-r--r--kernel/freezer.c25
-rw-r--r--kernel/power/hibernate.c15
-rw-r--r--kernel/power/process.c16
-rw-r--r--kernel/power/suspend.c8
-rw-r--r--kernel/power/user.c4
6 files changed, 23 insertions, 46 deletions
diff --git a/include/linux/freezer.h b/include/linux/freezer.h
index ba4f512d2938..93f411a52872 100644
--- a/include/linux/freezer.h
+++ b/include/linux/freezer.h
@@ -61,7 +61,6 @@ static inline bool try_to_freeze(void)
61} 61}
62 62
63extern bool freeze_task(struct task_struct *p, bool sig_only); 63extern bool freeze_task(struct task_struct *p, bool sig_only);
64extern void cancel_freezing(struct task_struct *p);
65 64
66#ifdef CONFIG_CGROUP_FREEZER 65#ifdef CONFIG_CGROUP_FREEZER
67extern int cgroup_freezing_or_frozen(struct task_struct *task); 66extern int cgroup_freezing_or_frozen(struct task_struct *task);
diff --git a/kernel/freezer.c b/kernel/freezer.c
index b8b562124ba9..11e32d419dec 100644
--- a/kernel/freezer.c
+++ b/kernel/freezer.c
@@ -129,21 +129,6 @@ out_unlock:
129 return ret; 129 return ret;
130} 130}
131 131
132void cancel_freezing(struct task_struct *p)
133{
134 unsigned long flags;
135
136 spin_lock_irqsave(&freezer_lock, flags);
137 if (freezing(p)) {
138 pr_debug(" clean up: %s\n", p->comm);
139 clear_freeze_flag(p);
140 spin_lock(&p->sighand->siglock);
141 recalc_sigpending_and_wake(p);
142 spin_unlock(&p->sighand->siglock);
143 }
144 spin_unlock_irqrestore(&freezer_lock, flags);
145}
146
147void __thaw_task(struct task_struct *p) 132void __thaw_task(struct task_struct *p)
148{ 133{
149 unsigned long flags; 134 unsigned long flags;
@@ -153,10 +138,18 @@ void __thaw_task(struct task_struct *p)
153 * be visible to @p as waking up implies wmb. Waking up inside 138 * be visible to @p as waking up implies wmb. Waking up inside
154 * freezer_lock also prevents wakeups from leaking outside 139 * freezer_lock also prevents wakeups from leaking outside
155 * refrigerator. 140 * refrigerator.
141 *
142 * If !FROZEN, @p hasn't reached refrigerator, recalc sigpending to
143 * avoid leaving dangling TIF_SIGPENDING behind.
156 */ 144 */
157 spin_lock_irqsave(&freezer_lock, flags); 145 spin_lock_irqsave(&freezer_lock, flags);
158 clear_freeze_flag(p); 146 clear_freeze_flag(p);
159 if (frozen(p)) 147 if (frozen(p)) {
160 wake_up_process(p); 148 wake_up_process(p);
149 } else {
150 spin_lock(&p->sighand->siglock);
151 recalc_sigpending_and_wake(p);
152 spin_unlock(&p->sighand->siglock);
153 }
161 spin_unlock_irqrestore(&freezer_lock, flags); 154 spin_unlock_irqrestore(&freezer_lock, flags);
162} 155}
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 196c01268ebd..ba2319ffc860 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -607,17 +607,6 @@ static void power_down(void)
607 while(1); 607 while(1);
608} 608}
609 609
610static int prepare_processes(void)
611{
612 int error = 0;
613
614 if (freeze_processes()) {
615 error = -EBUSY;
616 thaw_processes();
617 }
618 return error;
619}
620
621/** 610/**
622 * hibernate - Carry out system hibernation, including saving the image. 611 * hibernate - Carry out system hibernation, including saving the image.
623 */ 612 */
@@ -650,7 +639,7 @@ int hibernate(void)
650 sys_sync(); 639 sys_sync();
651 printk("done.\n"); 640 printk("done.\n");
652 641
653 error = prepare_processes(); 642 error = freeze_processes();
654 if (error) 643 if (error)
655 goto Finish; 644 goto Finish;
656 645
@@ -811,7 +800,7 @@ static int software_resume(void)
811 goto close_finish; 800 goto close_finish;
812 801
813 pr_debug("PM: Preparing processes for restore.\n"); 802 pr_debug("PM: Preparing processes for restore.\n");
814 error = prepare_processes(); 803 error = freeze_processes();
815 if (error) { 804 if (error) {
816 swsusp_close(FMODE_READ); 805 swsusp_close(FMODE_READ);
817 goto Done; 806 goto Done;
diff --git a/kernel/power/process.c b/kernel/power/process.c
index e59676f5811d..ce643838a00c 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -91,11 +91,6 @@ static int try_to_freeze_tasks(bool sig_only)
91 elapsed_csecs = elapsed_csecs64; 91 elapsed_csecs = elapsed_csecs64;
92 92
93 if (todo) { 93 if (todo) {
94 /* This does not unfreeze processes that are already frozen
95 * (we have slightly ugly calling convention in that respect,
96 * and caller must call thaw_processes() if something fails),
97 * but it cleans up leftover PF_FREEZE requests.
98 */
99 printk("\n"); 94 printk("\n");
100 printk(KERN_ERR "Freezing of tasks %s after %d.%02d seconds " 95 printk(KERN_ERR "Freezing of tasks %s after %d.%02d seconds "
101 "(%d tasks refusing to freeze, wq_busy=%d):\n", 96 "(%d tasks refusing to freeze, wq_busy=%d):\n",
@@ -103,14 +98,11 @@ static int try_to_freeze_tasks(bool sig_only)
103 elapsed_csecs / 100, elapsed_csecs % 100, 98 elapsed_csecs / 100, elapsed_csecs % 100,
104 todo - wq_busy, wq_busy); 99 todo - wq_busy, wq_busy);
105 100
106 thaw_workqueues();
107
108 read_lock(&tasklist_lock); 101 read_lock(&tasklist_lock);
109 do_each_thread(g, p) { 102 do_each_thread(g, p) {
110 if (!wakeup && !freezer_should_skip(p) && 103 if (!wakeup && !freezer_should_skip(p) &&
111 freezing(p) && !frozen(p)) 104 freezing(p) && !frozen(p))
112 sched_show_task(p); 105 sched_show_task(p);
113 cancel_freezing(p);
114 } while_each_thread(g, p); 106 } while_each_thread(g, p);
115 read_unlock(&tasklist_lock); 107 read_unlock(&tasklist_lock);
116 } else { 108 } else {
@@ -123,6 +115,8 @@ static int try_to_freeze_tasks(bool sig_only)
123 115
124/** 116/**
125 * 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.
126 */ 120 */
127int freeze_processes(void) 121int freeze_processes(void)
128{ 122{
@@ -137,11 +131,15 @@ int freeze_processes(void)
137 printk("\n"); 131 printk("\n");
138 BUG_ON(in_atomic()); 132 BUG_ON(in_atomic());
139 133
134 if (error)
135 thaw_processes();
140 return error; 136 return error;
141} 137}
142 138
143/** 139/**
144 * freeze_kernel_threads - Make freezable kernel threads go to the refrigerator. 140 * freeze_kernel_threads - Make freezable kernel threads go to the refrigerator.
141 *
142 * On success, returns 0. On failure, -errno and system is fully thawed.
145 */ 143 */
146int freeze_kernel_threads(void) 144int freeze_kernel_threads(void)
147{ 145{
@@ -155,6 +153,8 @@ int freeze_kernel_threads(void)
155 printk("\n"); 153 printk("\n");
156 BUG_ON(in_atomic()); 154 BUG_ON(in_atomic());
157 155
156 if (error)
157 thaw_processes();
158 return error; 158 return error;
159} 159}
160 160
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 4953dc054c53..d336b27d1104 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -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..7cc3f5bc5c24 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -257,10 +257,8 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
257 break; 257 break;
258 258
259 error = freeze_processes(); 259 error = freeze_processes();
260 if (error) { 260 if (error)
261 thaw_processes();
262 usermodehelper_enable(); 261 usermodehelper_enable();
263 }
264 if (!error) 262 if (!error)
265 data->frozen = 1; 263 data->frozen = 1;
266 break; 264 break;