diff options
Diffstat (limited to 'kernel/power/process.c')
-rw-r--r-- | kernel/power/process.c | 130 |
1 files changed, 86 insertions, 44 deletions
diff --git a/kernel/power/process.c b/kernel/power/process.c index 72e72d2c61e6..99eeb119b06d 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c | |||
@@ -13,12 +13,15 @@ | |||
13 | #include <linux/suspend.h> | 13 | #include <linux/suspend.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/syscalls.h> | 15 | #include <linux/syscalls.h> |
16 | #include <linux/freezer.h> | ||
16 | 17 | ||
17 | /* | 18 | /* |
18 | * Timeout for stopping processes | 19 | * Timeout for stopping processes |
19 | */ | 20 | */ |
20 | #define TIMEOUT (20 * HZ) | 21 | #define TIMEOUT (20 * HZ) |
21 | 22 | ||
23 | #define FREEZER_KERNEL_THREADS 0 | ||
24 | #define FREEZER_USER_SPACE 1 | ||
22 | 25 | ||
23 | static inline int freezeable(struct task_struct * p) | 26 | static inline int freezeable(struct task_struct * p) |
24 | { | 27 | { |
@@ -39,7 +42,6 @@ void refrigerator(void) | |||
39 | long save; | 42 | long save; |
40 | save = current->state; | 43 | save = current->state; |
41 | pr_debug("%s entered refrigerator\n", current->comm); | 44 | pr_debug("%s entered refrigerator\n", current->comm); |
42 | printk("="); | ||
43 | 45 | ||
44 | frozen_process(current); | 46 | frozen_process(current); |
45 | spin_lock_irq(¤t->sighand->siglock); | 47 | spin_lock_irq(¤t->sighand->siglock); |
@@ -79,96 +81,136 @@ static void cancel_freezing(struct task_struct *p) | |||
79 | } | 81 | } |
80 | } | 82 | } |
81 | 83 | ||
82 | /* 0 = success, else # of processes that we failed to stop */ | 84 | static inline int is_user_space(struct task_struct *p) |
83 | int freeze_processes(void) | 85 | { |
86 | return p->mm && !(p->flags & PF_BORROWED_MM); | ||
87 | } | ||
88 | |||
89 | static unsigned int try_to_freeze_tasks(int freeze_user_space) | ||
84 | { | 90 | { |
85 | int todo, nr_user, user_frozen; | ||
86 | unsigned long start_time; | ||
87 | struct task_struct *g, *p; | 91 | struct task_struct *g, *p; |
92 | unsigned long end_time; | ||
93 | unsigned int todo; | ||
88 | 94 | ||
89 | printk( "Stopping tasks: " ); | 95 | end_time = jiffies + TIMEOUT; |
90 | start_time = jiffies; | ||
91 | user_frozen = 0; | ||
92 | do { | 96 | do { |
93 | nr_user = todo = 0; | 97 | todo = 0; |
94 | read_lock(&tasklist_lock); | 98 | read_lock(&tasklist_lock); |
95 | do_each_thread(g, p) { | 99 | do_each_thread(g, p) { |
96 | if (!freezeable(p)) | 100 | if (!freezeable(p)) |
97 | continue; | 101 | continue; |
102 | |||
98 | if (frozen(p)) | 103 | if (frozen(p)) |
99 | continue; | 104 | continue; |
100 | if (p->state == TASK_TRACED && frozen(p->parent)) { | 105 | |
106 | if (p->state == TASK_TRACED && | ||
107 | (frozen(p->parent) || | ||
108 | p->parent->state == TASK_STOPPED)) { | ||
101 | cancel_freezing(p); | 109 | cancel_freezing(p); |
102 | continue; | 110 | continue; |
103 | } | 111 | } |
104 | if (p->mm && !(p->flags & PF_BORROWED_MM)) { | 112 | if (is_user_space(p)) { |
105 | /* The task is a user-space one. | 113 | if (!freeze_user_space) |
106 | * Freeze it unless there's a vfork completion | 114 | continue; |
107 | * pending | 115 | |
116 | /* Freeze the task unless there is a vfork | ||
117 | * completion pending | ||
108 | */ | 118 | */ |
109 | if (!p->vfork_done) | 119 | if (!p->vfork_done) |
110 | freeze_process(p); | 120 | freeze_process(p); |
111 | nr_user++; | ||
112 | } else { | 121 | } else { |
113 | /* Freeze only if the user space is frozen */ | 122 | if (freeze_user_space) |
114 | if (user_frozen) | 123 | continue; |
115 | freeze_process(p); | 124 | |
116 | todo++; | 125 | freeze_process(p); |
117 | } | 126 | } |
127 | todo++; | ||
118 | } while_each_thread(g, p); | 128 | } while_each_thread(g, p); |
119 | read_unlock(&tasklist_lock); | 129 | read_unlock(&tasklist_lock); |
120 | todo += nr_user; | ||
121 | if (!user_frozen && !nr_user) { | ||
122 | sys_sync(); | ||
123 | start_time = jiffies; | ||
124 | } | ||
125 | user_frozen = !nr_user; | ||
126 | yield(); /* Yield is okay here */ | 130 | yield(); /* Yield is okay here */ |
127 | if (todo && time_after(jiffies, start_time + TIMEOUT)) | 131 | if (todo && time_after(jiffies, end_time)) |
128 | break; | 132 | break; |
129 | } while(todo); | 133 | } while (todo); |
130 | 134 | ||
131 | /* This does not unfreeze processes that are already frozen | ||
132 | * (we have slightly ugly calling convention in that respect, | ||
133 | * and caller must call thaw_processes() if something fails), | ||
134 | * but it cleans up leftover PF_FREEZE requests. | ||
135 | */ | ||
136 | if (todo) { | 135 | if (todo) { |
137 | printk( "\n" ); | 136 | /* This does not unfreeze processes that are already frozen |
138 | printk(KERN_ERR " stopping tasks timed out " | 137 | * (we have slightly ugly calling convention in that respect, |
139 | "after %d seconds (%d tasks remaining):\n", | 138 | * and caller must call thaw_processes() if something fails), |
140 | TIMEOUT / HZ, todo); | 139 | * but it cleans up leftover PF_FREEZE requests. |
140 | */ | ||
141 | printk("\n"); | ||
142 | printk(KERN_ERR "Stopping %s timed out after %d seconds " | ||
143 | "(%d tasks refusing to freeze):\n", | ||
144 | freeze_user_space ? "user space processes" : | ||
145 | "kernel threads", | ||
146 | TIMEOUT / HZ, todo); | ||
141 | read_lock(&tasklist_lock); | 147 | read_lock(&tasklist_lock); |
142 | do_each_thread(g, p) { | 148 | do_each_thread(g, p) { |
149 | if (is_user_space(p) == !freeze_user_space) | ||
150 | continue; | ||
151 | |||
143 | if (freezeable(p) && !frozen(p)) | 152 | if (freezeable(p) && !frozen(p)) |
144 | printk(KERN_ERR " %s\n", p->comm); | 153 | printk(KERN_ERR " %s\n", p->comm); |
154 | |||
145 | cancel_freezing(p); | 155 | cancel_freezing(p); |
146 | } while_each_thread(g, p); | 156 | } while_each_thread(g, p); |
147 | read_unlock(&tasklist_lock); | 157 | read_unlock(&tasklist_lock); |
148 | return todo; | ||
149 | } | 158 | } |
150 | 159 | ||
151 | printk( "|\n" ); | 160 | return todo; |
161 | } | ||
162 | |||
163 | /** | ||
164 | * freeze_processes - tell processes to enter the refrigerator | ||
165 | * | ||
166 | * Returns 0 on success, or the number of processes that didn't freeze, | ||
167 | * although they were told to. | ||
168 | */ | ||
169 | int freeze_processes(void) | ||
170 | { | ||
171 | unsigned int nr_unfrozen; | ||
172 | |||
173 | printk("Stopping tasks ... "); | ||
174 | nr_unfrozen = try_to_freeze_tasks(FREEZER_USER_SPACE); | ||
175 | if (nr_unfrozen) | ||
176 | return nr_unfrozen; | ||
177 | |||
178 | sys_sync(); | ||
179 | nr_unfrozen = try_to_freeze_tasks(FREEZER_KERNEL_THREADS); | ||
180 | if (nr_unfrozen) | ||
181 | return nr_unfrozen; | ||
182 | |||
183 | printk("done.\n"); | ||
152 | BUG_ON(in_atomic()); | 184 | BUG_ON(in_atomic()); |
153 | return 0; | 185 | return 0; |
154 | } | 186 | } |
155 | 187 | ||
156 | void thaw_processes(void) | 188 | static void thaw_tasks(int thaw_user_space) |
157 | { | 189 | { |
158 | struct task_struct *g, *p; | 190 | struct task_struct *g, *p; |
159 | 191 | ||
160 | printk( "Restarting tasks..." ); | ||
161 | read_lock(&tasklist_lock); | 192 | read_lock(&tasklist_lock); |
162 | do_each_thread(g, p) { | 193 | do_each_thread(g, p) { |
163 | if (!freezeable(p)) | 194 | if (!freezeable(p)) |
164 | continue; | 195 | continue; |
196 | |||
197 | if (is_user_space(p) == !thaw_user_space) | ||
198 | continue; | ||
199 | |||
165 | if (!thaw_process(p)) | 200 | if (!thaw_process(p)) |
166 | printk(KERN_INFO " Strange, %s not stopped\n", p->comm ); | 201 | printk(KERN_WARNING " Strange, %s not stopped\n", |
202 | p->comm ); | ||
167 | } while_each_thread(g, p); | 203 | } while_each_thread(g, p); |
168 | |||
169 | read_unlock(&tasklist_lock); | 204 | read_unlock(&tasklist_lock); |
205 | } | ||
206 | |||
207 | void thaw_processes(void) | ||
208 | { | ||
209 | printk("Restarting tasks ... "); | ||
210 | thaw_tasks(FREEZER_KERNEL_THREADS); | ||
211 | thaw_tasks(FREEZER_USER_SPACE); | ||
170 | schedule(); | 212 | schedule(); |
171 | printk( " done\n" ); | 213 | printk("done.\n"); |
172 | } | 214 | } |
173 | 215 | ||
174 | EXPORT_SYMBOL(refrigerator); | 216 | EXPORT_SYMBOL(refrigerator); |