diff options
Diffstat (limited to 'kernel/power/process.c')
| -rw-r--r-- | kernel/power/process.c | 97 |
1 files changed, 42 insertions, 55 deletions
diff --git a/kernel/power/process.c b/kernel/power/process.c index f1d0b345c9ba..5fb87652f214 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c | |||
| @@ -19,9 +19,6 @@ | |||
| 19 | */ | 19 | */ |
| 20 | #define TIMEOUT (20 * HZ) | 20 | #define TIMEOUT (20 * HZ) |
| 21 | 21 | ||
| 22 | #define FREEZER_KERNEL_THREADS 0 | ||
| 23 | #define FREEZER_USER_SPACE 1 | ||
| 24 | |||
| 25 | static inline int freezeable(struct task_struct * p) | 22 | static inline int freezeable(struct task_struct * p) |
| 26 | { | 23 | { |
| 27 | if ((p == current) || | 24 | if ((p == current) || |
| @@ -84,63 +81,53 @@ static void fake_signal_wake_up(struct task_struct *p) | |||
| 84 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | 81 | spin_unlock_irqrestore(&p->sighand->siglock, flags); |
| 85 | } | 82 | } |
| 86 | 83 | ||
| 87 | static int has_mm(struct task_struct *p) | 84 | static inline bool should_send_signal(struct task_struct *p) |
| 88 | { | 85 | { |
| 89 | return (p->mm && !(p->flags & PF_BORROWED_MM)); | 86 | return !(p->flags & PF_FREEZER_NOSIG); |
| 90 | } | 87 | } |
| 91 | 88 | ||
| 92 | /** | 89 | /** |
| 93 | * freeze_task - send a freeze request to given task | 90 | * freeze_task - send a freeze request to given task |
| 94 | * @p: task to send the request to | 91 | * @p: task to send the request to |
| 95 | * @with_mm_only: if set, the request will only be sent if the task has its | 92 | * @sig_only: if set, the request will only be sent if the task has the |
| 96 | * own mm | 93 | * PF_FREEZER_NOSIG flag unset |
| 97 | * Return value: 0, if @with_mm_only is set and the task has no mm of its | 94 | * Return value: 'false', if @sig_only is set and the task has |
| 98 | * own or the task is frozen, 1, otherwise | 95 | * PF_FREEZER_NOSIG set or the task is frozen, 'true', otherwise |
| 99 | * | 96 | * |
| 100 | * The freeze request is sent by seting the tasks's TIF_FREEZE flag and | 97 | * The freeze request is sent by setting the tasks's TIF_FREEZE flag and |
| 101 | * either sending a fake signal to it or waking it up, depending on whether | 98 | * either sending a fake signal to it or waking it up, depending on whether |
| 102 | * or not it has its own mm (ie. it is a user land task). If @with_mm_only | 99 | * or not it has PF_FREEZER_NOSIG set. If @sig_only is set and the task |
| 103 | * is set and the task has no mm of its own (ie. it is a kernel thread), | 100 | * has PF_FREEZER_NOSIG set (ie. it is a typical kernel thread), its |
| 104 | * its TIF_FREEZE flag should not be set. | 101 | * TIF_FREEZE flag will not be set. |
| 105 | * | ||
| 106 | * The task_lock() is necessary to prevent races with exit_mm() or | ||
| 107 | * use_mm()/unuse_mm() from occuring. | ||
| 108 | */ | 102 | */ |
| 109 | static int freeze_task(struct task_struct *p, int with_mm_only) | 103 | static bool freeze_task(struct task_struct *p, bool sig_only) |
| 110 | { | 104 | { |
| 111 | int ret = 1; | 105 | /* |
| 106 | * We first check if the task is freezing and next if it has already | ||
| 107 | * been frozen to avoid the race with frozen_process() which first marks | ||
| 108 | * the task as frozen and next clears its TIF_FREEZE. | ||
| 109 | */ | ||
| 110 | if (!freezing(p)) { | ||
| 111 | rmb(); | ||
| 112 | if (frozen(p)) | ||
| 113 | return false; | ||
| 112 | 114 | ||
| 113 | task_lock(p); | 115 | if (!sig_only || should_send_signal(p)) |
| 114 | if (freezing(p)) { | 116 | set_freeze_flag(p); |
| 115 | if (has_mm(p)) { | 117 | else |
| 116 | if (!signal_pending(p)) | 118 | return false; |
| 117 | fake_signal_wake_up(p); | 119 | } |
| 118 | } else { | 120 | |
| 119 | if (with_mm_only) | 121 | if (should_send_signal(p)) { |
| 120 | ret = 0; | 122 | if (!signal_pending(p)) |
| 121 | else | 123 | fake_signal_wake_up(p); |
| 122 | wake_up_state(p, TASK_INTERRUPTIBLE); | 124 | } else if (sig_only) { |
| 123 | } | 125 | return false; |
| 124 | } else { | 126 | } else { |
| 125 | rmb(); | 127 | wake_up_state(p, TASK_INTERRUPTIBLE); |
| 126 | if (frozen(p)) { | ||
| 127 | ret = 0; | ||
| 128 | } else { | ||
| 129 | if (has_mm(p)) { | ||
| 130 | set_freeze_flag(p); | ||
| 131 | fake_signal_wake_up(p); | ||
| 132 | } else { | ||
| 133 | if (with_mm_only) { | ||
| 134 | ret = 0; | ||
| 135 | } else { | ||
| 136 | set_freeze_flag(p); | ||
| 137 | wake_up_state(p, TASK_INTERRUPTIBLE); | ||
| 138 | } | ||
| 139 | } | ||
| 140 | } | ||
| 141 | } | 128 | } |
| 142 | task_unlock(p); | 129 | |
| 143 | return ret; | 130 | return true; |
| 144 | } | 131 | } |
| 145 | 132 | ||
| 146 | static void cancel_freezing(struct task_struct *p) | 133 | static void cancel_freezing(struct task_struct *p) |
| @@ -156,7 +143,7 @@ static void cancel_freezing(struct task_struct *p) | |||
| 156 | } | 143 | } |
| 157 | } | 144 | } |
| 158 | 145 | ||
| 159 | static int try_to_freeze_tasks(int freeze_user_space) | 146 | static int try_to_freeze_tasks(bool sig_only) |
| 160 | { | 147 | { |
| 161 | struct task_struct *g, *p; | 148 | struct task_struct *g, *p; |
| 162 | unsigned long end_time; | 149 | unsigned long end_time; |
| @@ -175,7 +162,7 @@ static int try_to_freeze_tasks(int freeze_user_space) | |||
| 175 | if (frozen(p) || !freezeable(p)) | 162 | if (frozen(p) || !freezeable(p)) |
| 176 | continue; | 163 | continue; |
| 177 | 164 | ||
| 178 | if (!freeze_task(p, freeze_user_space)) | 165 | if (!freeze_task(p, sig_only)) |
| 179 | continue; | 166 | continue; |
| 180 | 167 | ||
| 181 | /* | 168 | /* |
| @@ -235,13 +222,13 @@ int freeze_processes(void) | |||
| 235 | int error; | 222 | int error; |
| 236 | 223 | ||
| 237 | printk("Freezing user space processes ... "); | 224 | printk("Freezing user space processes ... "); |
| 238 | error = try_to_freeze_tasks(FREEZER_USER_SPACE); | 225 | error = try_to_freeze_tasks(true); |
| 239 | if (error) | 226 | if (error) |
| 240 | goto Exit; | 227 | goto Exit; |
| 241 | printk("done.\n"); | 228 | printk("done.\n"); |
| 242 | 229 | ||
| 243 | printk("Freezing remaining freezable tasks ... "); | 230 | printk("Freezing remaining freezable tasks ... "); |
| 244 | error = try_to_freeze_tasks(FREEZER_KERNEL_THREADS); | 231 | error = try_to_freeze_tasks(false); |
| 245 | if (error) | 232 | if (error) |
| 246 | goto Exit; | 233 | goto Exit; |
| 247 | printk("done."); | 234 | printk("done."); |
| @@ -251,7 +238,7 @@ int freeze_processes(void) | |||
| 251 | return error; | 238 | return error; |
| 252 | } | 239 | } |
| 253 | 240 | ||
| 254 | static void thaw_tasks(int thaw_user_space) | 241 | static void thaw_tasks(bool nosig_only) |
| 255 | { | 242 | { |
| 256 | struct task_struct *g, *p; | 243 | struct task_struct *g, *p; |
| 257 | 244 | ||
| @@ -260,7 +247,7 @@ static void thaw_tasks(int thaw_user_space) | |||
| 260 | if (!freezeable(p)) | 247 | if (!freezeable(p)) |
| 261 | continue; | 248 | continue; |
| 262 | 249 | ||
| 263 | if (!p->mm == thaw_user_space) | 250 | if (nosig_only && should_send_signal(p)) |
| 264 | continue; | 251 | continue; |
| 265 | 252 | ||
| 266 | thaw_process(p); | 253 | thaw_process(p); |
| @@ -271,8 +258,8 @@ static void thaw_tasks(int thaw_user_space) | |||
| 271 | void thaw_processes(void) | 258 | void thaw_processes(void) |
| 272 | { | 259 | { |
| 273 | printk("Restarting tasks ... "); | 260 | printk("Restarting tasks ... "); |
| 274 | thaw_tasks(FREEZER_KERNEL_THREADS); | 261 | thaw_tasks(true); |
| 275 | thaw_tasks(FREEZER_USER_SPACE); | 262 | thaw_tasks(false); |
| 276 | schedule(); | 263 | schedule(); |
| 277 | printk("done.\n"); | 264 | printk("done.\n"); |
| 278 | } | 265 | } |
