diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/exit.c | 3 | ||||
-rw-r--r-- | kernel/power/process.c | 64 |
2 files changed, 36 insertions, 31 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index e8af8d0c2483..464c2b172f07 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <linux/resource.h> | 45 | #include <linux/resource.h> |
46 | #include <linux/blkdev.h> | 46 | #include <linux/blkdev.h> |
47 | #include <linux/task_io_accounting_ops.h> | 47 | #include <linux/task_io_accounting_ops.h> |
48 | #include <linux/freezer.h> | ||
48 | 49 | ||
49 | #include <asm/uaccess.h> | 50 | #include <asm/uaccess.h> |
50 | #include <asm/unistd.h> | 51 | #include <asm/unistd.h> |
@@ -594,6 +595,8 @@ static void exit_mm(struct task_struct * tsk) | |||
594 | tsk->mm = NULL; | 595 | tsk->mm = NULL; |
595 | up_read(&mm->mmap_sem); | 596 | up_read(&mm->mmap_sem); |
596 | enter_lazy_tlb(mm, current); | 597 | enter_lazy_tlb(mm, current); |
598 | /* We don't want this task to be frozen prematurely */ | ||
599 | clear_freeze_flag(tsk); | ||
597 | task_unlock(tsk); | 600 | task_unlock(tsk); |
598 | mmput(mm); | 601 | mmput(mm); |
599 | } | 602 | } |
diff --git a/kernel/power/process.c b/kernel/power/process.c index b850173e7561..e1bcdedd1464 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c | |||
@@ -40,7 +40,7 @@ static inline void frozen_process(void) | |||
40 | current->flags |= PF_FROZEN; | 40 | current->flags |= PF_FROZEN; |
41 | wmb(); | 41 | wmb(); |
42 | } | 42 | } |
43 | clear_tsk_thread_flag(current, TIF_FREEZE); | 43 | clear_freeze_flag(current); |
44 | } | 44 | } |
45 | 45 | ||
46 | /* Refrigerator is place where frozen processes are stored :-). */ | 46 | /* Refrigerator is place where frozen processes are stored :-). */ |
@@ -75,17 +75,16 @@ void refrigerator(void) | |||
75 | current->state = save; | 75 | current->state = save; |
76 | } | 76 | } |
77 | 77 | ||
78 | static inline void freeze_process(struct task_struct *p) | 78 | static void freeze_task(struct task_struct *p) |
79 | { | 79 | { |
80 | unsigned long flags; | 80 | unsigned long flags; |
81 | 81 | ||
82 | if (!freezing(p)) { | 82 | if (!freezing(p)) { |
83 | rmb(); | 83 | rmb(); |
84 | if (!frozen(p)) { | 84 | if (!frozen(p)) { |
85 | set_freeze_flag(p); | ||
85 | if (p->state == TASK_STOPPED) | 86 | if (p->state == TASK_STOPPED) |
86 | force_sig_specific(SIGSTOP, p); | 87 | force_sig_specific(SIGSTOP, p); |
87 | |||
88 | freeze(p); | ||
89 | spin_lock_irqsave(&p->sighand->siglock, flags); | 88 | spin_lock_irqsave(&p->sighand->siglock, flags); |
90 | signal_wake_up(p, p->state == TASK_STOPPED); | 89 | signal_wake_up(p, p->state == TASK_STOPPED); |
91 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | 90 | spin_unlock_irqrestore(&p->sighand->siglock, flags); |
@@ -99,18 +98,13 @@ static void cancel_freezing(struct task_struct *p) | |||
99 | 98 | ||
100 | if (freezing(p)) { | 99 | if (freezing(p)) { |
101 | pr_debug(" clean up: %s\n", p->comm); | 100 | pr_debug(" clean up: %s\n", p->comm); |
102 | do_not_freeze(p); | 101 | clear_freeze_flag(p); |
103 | spin_lock_irqsave(&p->sighand->siglock, flags); | 102 | spin_lock_irqsave(&p->sighand->siglock, flags); |
104 | recalc_sigpending_and_wake(p); | 103 | recalc_sigpending_and_wake(p); |
105 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | 104 | spin_unlock_irqrestore(&p->sighand->siglock, flags); |
106 | } | 105 | } |
107 | } | 106 | } |
108 | 107 | ||
109 | static inline int is_user_space(struct task_struct *p) | ||
110 | { | ||
111 | return p->mm && !(p->flags & PF_BORROWED_MM); | ||
112 | } | ||
113 | |||
114 | static unsigned int try_to_freeze_tasks(int freeze_user_space) | 108 | static unsigned int try_to_freeze_tasks(int freeze_user_space) |
115 | { | 109 | { |
116 | struct task_struct *g, *p; | 110 | struct task_struct *g, *p; |
@@ -122,20 +116,34 @@ static unsigned int try_to_freeze_tasks(int freeze_user_space) | |||
122 | todo = 0; | 116 | todo = 0; |
123 | read_lock(&tasklist_lock); | 117 | read_lock(&tasklist_lock); |
124 | do_each_thread(g, p) { | 118 | do_each_thread(g, p) { |
125 | if (!freezeable(p)) | 119 | if (frozen(p) || !freezeable(p)) |
126 | continue; | ||
127 | |||
128 | if (frozen(p)) | ||
129 | continue; | 120 | continue; |
130 | 121 | ||
131 | if (p->state == TASK_TRACED && frozen(p->parent)) { | 122 | if (freeze_user_space) { |
132 | cancel_freezing(p); | 123 | if (p->state == TASK_TRACED && |
133 | continue; | 124 | frozen(p->parent)) { |
125 | cancel_freezing(p); | ||
126 | continue; | ||
127 | } | ||
128 | /* | ||
129 | * Kernel threads should not have TIF_FREEZE set | ||
130 | * at this point, so we must ensure that either | ||
131 | * p->mm is not NULL *and* PF_BORROWED_MM is | ||
132 | * unset, or TIF_FRREZE is left unset. | ||
133 | * The task_lock() is necessary to prevent races | ||
134 | * with exit_mm() or use_mm()/unuse_mm() from | ||
135 | * occuring. | ||
136 | */ | ||
137 | task_lock(p); | ||
138 | if (!p->mm || (p->flags & PF_BORROWED_MM)) { | ||
139 | task_unlock(p); | ||
140 | continue; | ||
141 | } | ||
142 | freeze_task(p); | ||
143 | task_unlock(p); | ||
144 | } else { | ||
145 | freeze_task(p); | ||
134 | } | 146 | } |
135 | if (freeze_user_space && !is_user_space(p)) | ||
136 | continue; | ||
137 | |||
138 | freeze_process(p); | ||
139 | if (!freezer_should_skip(p)) | 147 | if (!freezer_should_skip(p)) |
140 | todo++; | 148 | todo++; |
141 | } while_each_thread(g, p); | 149 | } while_each_thread(g, p); |
@@ -152,22 +160,16 @@ static unsigned int try_to_freeze_tasks(int freeze_user_space) | |||
152 | * but it cleans up leftover PF_FREEZE requests. | 160 | * but it cleans up leftover PF_FREEZE requests. |
153 | */ | 161 | */ |
154 | printk("\n"); | 162 | printk("\n"); |
155 | printk(KERN_ERR "Stopping %s timed out after %d seconds " | 163 | printk(KERN_ERR "Freezing of %s timed out after %d seconds " |
156 | "(%d tasks refusing to freeze):\n", | 164 | "(%d tasks refusing to freeze):\n", |
157 | freeze_user_space ? "user space processes" : | 165 | freeze_user_space ? "user space " : "tasks ", |
158 | "kernel threads", | ||
159 | TIMEOUT / HZ, todo); | 166 | TIMEOUT / HZ, todo); |
160 | show_state(); | 167 | show_state(); |
161 | read_lock(&tasklist_lock); | 168 | read_lock(&tasklist_lock); |
162 | do_each_thread(g, p) { | 169 | do_each_thread(g, p) { |
163 | if (freeze_user_space && !is_user_space(p)) | ||
164 | continue; | ||
165 | |||
166 | task_lock(p); | 170 | task_lock(p); |
167 | if (freezeable(p) && !frozen(p) && | 171 | if (freezing(p) && !freezer_should_skip(p)) |
168 | !freezer_should_skip(p)) | ||
169 | printk(KERN_ERR " %s\n", p->comm); | 172 | printk(KERN_ERR " %s\n", p->comm); |
170 | |||
171 | cancel_freezing(p); | 173 | cancel_freezing(p); |
172 | task_unlock(p); | 174 | task_unlock(p); |
173 | } while_each_thread(g, p); | 175 | } while_each_thread(g, p); |
@@ -211,7 +213,7 @@ static void thaw_tasks(int thaw_user_space) | |||
211 | if (!freezeable(p)) | 213 | if (!freezeable(p)) |
212 | continue; | 214 | continue; |
213 | 215 | ||
214 | if (is_user_space(p) == !thaw_user_space) | 216 | if (!p->mm == thaw_user_space) |
215 | continue; | 217 | continue; |
216 | 218 | ||
217 | thaw_process(p); | 219 | thaw_process(p); |