diff options
-rw-r--r-- | include/linux/freezer.h | 10 | ||||
-rw-r--r-- | kernel/power/process.c | 12 |
2 files changed, 21 insertions, 1 deletions
diff --git a/include/linux/freezer.h b/include/linux/freezer.h index 5e75e26d478..db5423eae24 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h @@ -37,14 +37,24 @@ static inline void do_not_freeze(struct task_struct *p) /* * Wake up a frozen process + * + * task_lock() is taken to prevent the race with refrigerator() which may + * occur if the freezing of tasks fails. Namely, without the lock, if the + * freezing of tasks failed, thaw_tasks() might have run before a task in + * refrigerator() could call frozen_process(), in which case the task would be + * frozen and no one would thaw it. */ static inline int thaw_process(struct task_struct *p) { + task_lock(p); if (frozen(p)) { p->flags &= ~PF_FROZEN; + task_unlock(p); wake_up_process(p); return 1; } + clear_tsk_thread_flag(p, TIF_FREEZE); + task_unlock(p); return 0; } diff --git a/kernel/power/process.c b/kernel/power/process.c index 08841938738..02e490e311e 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -37,10 +37,18 @@ void refrigerator(void) /* Hmm, should we be allowed to suspend when there are realtime processes around? */ long save; + + task_lock(current); + if (freezing(current)) { + frozen_process(current); + task_unlock(current); + } else { + task_unlock(current); + return; + } save = current->state; pr_debug("%s entered refrigerator\n", current->comm); - frozen_process(current); spin_lock_irq(¤t->sighand->siglock); recalc_sigpending(); /* We sent fake signal, clean it up */ spin_unlock_irq(¤t->sighand->siglock); @@ -152,10 +160,12 @@ static unsigned int try_to_freeze_tasks(int freeze_user_space) if (is_user_space(p) == !freeze_user_space) continue; + task_lock(p); if (freezeable(p) && !frozen(p)) printk(KERN_ERR " %s\n", p->comm); cancel_freezing(p); + task_unlock(p); } while_each_thread(g, p); read_unlock(&tasklist_lock); } |