diff options
Diffstat (limited to 'kernel/power/process.c')
-rw-r--r-- | kernel/power/process.c | 84 |
1 files changed, 54 insertions, 30 deletions
diff --git a/kernel/power/process.c b/kernel/power/process.c index fd0ebb942f50..99eeb119b06d 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c | |||
@@ -86,24 +86,23 @@ static inline int is_user_space(struct task_struct *p) | |||
86 | return p->mm && !(p->flags & PF_BORROWED_MM); | 86 | return p->mm && !(p->flags & PF_BORROWED_MM); |
87 | } | 87 | } |
88 | 88 | ||
89 | /* 0 = success, else # of processes that we failed to stop */ | 89 | static unsigned int try_to_freeze_tasks(int freeze_user_space) |
90 | int freeze_processes(void) | ||
91 | { | 90 | { |
92 | int todo, nr_user, user_frozen; | ||
93 | unsigned long start_time; | ||
94 | struct task_struct *g, *p; | 91 | struct task_struct *g, *p; |
92 | unsigned long end_time; | ||
93 | unsigned int todo; | ||
95 | 94 | ||
96 | printk("Stopping tasks... "); | 95 | end_time = jiffies + TIMEOUT; |
97 | start_time = jiffies; | ||
98 | user_frozen = 0; | ||
99 | do { | 96 | do { |
100 | nr_user = todo = 0; | 97 | todo = 0; |
101 | read_lock(&tasklist_lock); | 98 | read_lock(&tasklist_lock); |
102 | do_each_thread(g, p) { | 99 | do_each_thread(g, p) { |
103 | if (!freezeable(p)) | 100 | if (!freezeable(p)) |
104 | continue; | 101 | continue; |
102 | |||
105 | if (frozen(p)) | 103 | if (frozen(p)) |
106 | continue; | 104 | continue; |
105 | |||
107 | if (p->state == TASK_TRACED && | 106 | if (p->state == TASK_TRACED && |
108 | (frozen(p->parent) || | 107 | (frozen(p->parent) || |
109 | p->parent->state == TASK_STOPPED)) { | 108 | p->parent->state == TASK_STOPPED)) { |
@@ -111,51 +110,76 @@ int freeze_processes(void) | |||
111 | continue; | 110 | continue; |
112 | } | 111 | } |
113 | if (is_user_space(p)) { | 112 | if (is_user_space(p)) { |
113 | if (!freeze_user_space) | ||
114 | continue; | ||
115 | |||
114 | /* Freeze the task unless there is a vfork | 116 | /* Freeze the task unless there is a vfork |
115 | * completion pending | 117 | * completion pending |
116 | */ | 118 | */ |
117 | if (!p->vfork_done) | 119 | if (!p->vfork_done) |
118 | freeze_process(p); | 120 | freeze_process(p); |
119 | nr_user++; | ||
120 | } else { | 121 | } else { |
121 | /* Freeze only if the user space is frozen */ | 122 | if (freeze_user_space) |
122 | if (user_frozen) | 123 | continue; |
123 | freeze_process(p); | 124 | |
124 | todo++; | 125 | freeze_process(p); |
125 | } | 126 | } |
127 | todo++; | ||
126 | } while_each_thread(g, p); | 128 | } while_each_thread(g, p); |
127 | read_unlock(&tasklist_lock); | 129 | read_unlock(&tasklist_lock); |
128 | todo += nr_user; | ||
129 | if (!user_frozen && !nr_user) { | ||
130 | sys_sync(); | ||
131 | start_time = jiffies; | ||
132 | } | ||
133 | user_frozen = !nr_user; | ||
134 | yield(); /* Yield is okay here */ | 130 | yield(); /* Yield is okay here */ |
135 | if (todo && time_after(jiffies, start_time + TIMEOUT)) | 131 | if (todo && time_after(jiffies, end_time)) |
136 | break; | 132 | break; |
137 | } while(todo); | 133 | } while (todo); |
138 | 134 | ||
139 | /* This does not unfreeze processes that are already frozen | ||
140 | * (we have slightly ugly calling convention in that respect, | ||
141 | * and caller must call thaw_processes() if something fails), | ||
142 | * but it cleans up leftover PF_FREEZE requests. | ||
143 | */ | ||
144 | if (todo) { | 135 | if (todo) { |
136 | /* This does not unfreeze processes that are already frozen | ||
137 | * (we have slightly ugly calling convention in that respect, | ||
138 | * and caller must call thaw_processes() if something fails), | ||
139 | * but it cleans up leftover PF_FREEZE requests. | ||
140 | */ | ||
145 | printk("\n"); | 141 | printk("\n"); |
146 | printk(KERN_ERR "Stopping tasks timed out " | 142 | printk(KERN_ERR "Stopping %s timed out after %d seconds " |
147 | "after %d seconds (%d tasks remaining):\n", | 143 | "(%d tasks refusing to freeze):\n", |
148 | TIMEOUT / HZ, todo); | 144 | freeze_user_space ? "user space processes" : |
145 | "kernel threads", | ||
146 | TIMEOUT / HZ, todo); | ||
149 | read_lock(&tasklist_lock); | 147 | read_lock(&tasklist_lock); |
150 | do_each_thread(g, p) { | 148 | do_each_thread(g, p) { |
149 | if (is_user_space(p) == !freeze_user_space) | ||
150 | continue; | ||
151 | |||
151 | if (freezeable(p) && !frozen(p)) | 152 | if (freezeable(p) && !frozen(p)) |
152 | printk(KERN_ERR " %s\n", p->comm); | 153 | printk(KERN_ERR " %s\n", p->comm); |
154 | |||
153 | cancel_freezing(p); | 155 | cancel_freezing(p); |
154 | } while_each_thread(g, p); | 156 | } while_each_thread(g, p); |
155 | read_unlock(&tasklist_lock); | 157 | read_unlock(&tasklist_lock); |
156 | return todo; | ||
157 | } | 158 | } |
158 | 159 | ||
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 | |||
159 | printk("done.\n"); | 183 | printk("done.\n"); |
160 | BUG_ON(in_atomic()); | 184 | BUG_ON(in_atomic()); |
161 | return 0; | 185 | return 0; |