aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cgroup_freezer.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/cgroup_freezer.c')
-rw-r--r--kernel/cgroup_freezer.c70
1 files changed, 35 insertions, 35 deletions
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c
index e95056954498..fb249e2bcada 100644
--- a/kernel/cgroup_freezer.c
+++ b/kernel/cgroup_freezer.c
@@ -162,9 +162,13 @@ static int freezer_can_attach(struct cgroup_subsys *ss,
162 struct task_struct *task) 162 struct task_struct *task)
163{ 163{
164 struct freezer *freezer; 164 struct freezer *freezer;
165 int retval;
166 165
167 /* Anything frozen can't move or be moved to/from */ 166 /*
167 * Anything frozen can't move or be moved to/from.
168 *
169 * Since orig_freezer->state == FROZEN means that @task has been
170 * frozen, so it's sufficient to check the latter condition.
171 */
168 172
169 if (is_task_frozen_enough(task)) 173 if (is_task_frozen_enough(task))
170 return -EBUSY; 174 return -EBUSY;
@@ -173,25 +177,31 @@ static int freezer_can_attach(struct cgroup_subsys *ss,
173 if (freezer->state == CGROUP_FROZEN) 177 if (freezer->state == CGROUP_FROZEN)
174 return -EBUSY; 178 return -EBUSY;
175 179
176 retval = 0; 180 return 0;
177 task_lock(task);
178 freezer = task_freezer(task);
179 if (freezer->state == CGROUP_FROZEN)
180 retval = -EBUSY;
181 task_unlock(task);
182 return retval;
183} 181}
184 182
185static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) 183static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task)
186{ 184{
187 struct freezer *freezer; 185 struct freezer *freezer;
188 186
189 task_lock(task); 187 /*
188 * No lock is needed, since the task isn't on tasklist yet,
189 * so it can't be moved to another cgroup, which means the
190 * freezer won't be removed and will be valid during this
191 * function call.
192 */
190 freezer = task_freezer(task); 193 freezer = task_freezer(task);
191 task_unlock(task);
192 194
193 BUG_ON(freezer->state == CGROUP_FROZEN); 195 /*
196 * The root cgroup is non-freezable, so we can skip the
197 * following check.
198 */
199 if (!freezer->css.cgroup->parent)
200 return;
201
194 spin_lock_irq(&freezer->lock); 202 spin_lock_irq(&freezer->lock);
203 BUG_ON(freezer->state == CGROUP_FROZEN);
204
195 /* Locking avoids race with FREEZING -> THAWED transitions. */ 205 /* Locking avoids race with FREEZING -> THAWED transitions. */
196 if (freezer->state == CGROUP_FREEZING) 206 if (freezer->state == CGROUP_FREEZING)
197 freeze_task(task, true); 207 freeze_task(task, true);
@@ -276,25 +286,18 @@ static int try_to_freeze_cgroup(struct cgroup *cgroup, struct freezer *freezer)
276 return num_cant_freeze_now ? -EBUSY : 0; 286 return num_cant_freeze_now ? -EBUSY : 0;
277} 287}
278 288
279static int unfreeze_cgroup(struct cgroup *cgroup, struct freezer *freezer) 289static void unfreeze_cgroup(struct cgroup *cgroup, struct freezer *freezer)
280{ 290{
281 struct cgroup_iter it; 291 struct cgroup_iter it;
282 struct task_struct *task; 292 struct task_struct *task;
283 293
284 cgroup_iter_start(cgroup, &it); 294 cgroup_iter_start(cgroup, &it);
285 while ((task = cgroup_iter_next(cgroup, &it))) { 295 while ((task = cgroup_iter_next(cgroup, &it))) {
286 int do_wake; 296 thaw_process(task);
287
288 task_lock(task);
289 do_wake = __thaw_process(task);
290 task_unlock(task);
291 if (do_wake)
292 wake_up_process(task);
293 } 297 }
294 cgroup_iter_end(cgroup, &it); 298 cgroup_iter_end(cgroup, &it);
295 freezer->state = CGROUP_THAWED;
296 299
297 return 0; 300 freezer->state = CGROUP_THAWED;
298} 301}
299 302
300static int freezer_change_state(struct cgroup *cgroup, 303static int freezer_change_state(struct cgroup *cgroup,
@@ -304,27 +307,22 @@ static int freezer_change_state(struct cgroup *cgroup,
304 int retval = 0; 307 int retval = 0;
305 308
306 freezer = cgroup_freezer(cgroup); 309 freezer = cgroup_freezer(cgroup);
310
307 spin_lock_irq(&freezer->lock); 311 spin_lock_irq(&freezer->lock);
312
308 update_freezer_state(cgroup, freezer); 313 update_freezer_state(cgroup, freezer);
309 if (goal_state == freezer->state) 314 if (goal_state == freezer->state)
310 goto out; 315 goto out;
311 switch (freezer->state) { 316
317 switch (goal_state) {
312 case CGROUP_THAWED: 318 case CGROUP_THAWED:
313 retval = try_to_freeze_cgroup(cgroup, freezer); 319 unfreeze_cgroup(cgroup, freezer);
314 break; 320 break;
315 case CGROUP_FREEZING:
316 if (goal_state == CGROUP_FROZEN) {
317 /* Userspace is retrying after
318 * "/bin/echo FROZEN > freezer.state" returned -EBUSY */
319 retval = try_to_freeze_cgroup(cgroup, freezer);
320 break;
321 }
322 /* state == FREEZING and goal_state == THAWED, so unfreeze */
323 case CGROUP_FROZEN: 321 case CGROUP_FROZEN:
324 retval = unfreeze_cgroup(cgroup, freezer); 322 retval = try_to_freeze_cgroup(cgroup, freezer);
325 break; 323 break;
326 default: 324 default:
327 break; 325 BUG();
328 } 326 }
329out: 327out:
330 spin_unlock_irq(&freezer->lock); 328 spin_unlock_irq(&freezer->lock);
@@ -344,7 +342,7 @@ static int freezer_write(struct cgroup *cgroup,
344 else if (strcmp(buffer, freezer_state_strs[CGROUP_FROZEN]) == 0) 342 else if (strcmp(buffer, freezer_state_strs[CGROUP_FROZEN]) == 0)
345 goal_state = CGROUP_FROZEN; 343 goal_state = CGROUP_FROZEN;
346 else 344 else
347 return -EIO; 345 return -EINVAL;
348 346
349 if (!cgroup_lock_live_group(cgroup)) 347 if (!cgroup_lock_live_group(cgroup))
350 return -ENODEV; 348 return -ENODEV;
@@ -363,6 +361,8 @@ static struct cftype files[] = {
363 361
364static int freezer_populate(struct cgroup_subsys *ss, struct cgroup *cgroup) 362static int freezer_populate(struct cgroup_subsys *ss, struct cgroup *cgroup)
365{ 363{
364 if (!cgroup->parent)
365 return 0;
366 return cgroup_add_files(cgroup, ss, files, ARRAY_SIZE(files)); 366 return cgroup_add_files(cgroup, ss, files, ARRAY_SIZE(files));
367} 367}
368 368