1 /* 2 * cgroup_freezer.c - control group freezer subsystem 3 * 4 * Copyright IBM Corporation, 2007 5 * 6 * Author : Cedric Le Goater <clg@fr.ibm.com> 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of version 2.1 of the GNU Lesser General Public License 10 * as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it would be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 */ 16 17 #include <linux/export.h> 18 #include <linux/slab.h> 19 #include <linux/cgroup.h> 20 #include <linux/fs.h> 21 #include <linux/uaccess.h> 22 #include <linux/freezer.h> 23 #include <linux/seq_file.h> 24 25 /* 26 * A cgroup is freezing if any FREEZING flags are set. FREEZING_SELF is 27 * set if "FROZEN" is written to freezer.state cgroupfs file, and cleared 28 * for "THAWED". FREEZING_PARENT is set if the parent freezer is FREEZING 29 * for whatever reason. IOW, a cgroup has FREEZING_PARENT set if one of 30 * its ancestors has FREEZING_SELF set. 31 */ 32 enum freezer_state_flags { 33 CGROUP_FREEZER_ONLINE = (1 << 0), /* freezer is fully online */ 34 CGROUP_FREEZING_SELF = (1 << 1), /* this freezer is freezing */ 35 CGROUP_FREEZING_PARENT = (1 << 2), /* the parent freezer is freezing */ 36 CGROUP_FROZEN = (1 << 3), /* this and its descendants frozen */ 37 38 /* mask for all FREEZING flags */ 39 CGROUP_FREEZING = CGROUP_FREEZING_SELF | CGROUP_FREEZING_PARENT, 40 }; 41 42 struct freezer { 43 struct cgroup_subsys_state css; 44 unsigned int state; 45 spinlock_t lock; 46 }; 47 48 static inline struct freezer *cgroup_freezer(struct cgroup *cgroup) 49 { 50 return container_of(cgroup_subsys_state(cgroup, freezer_subsys_id), 51 struct freezer, css); 52 } 53 54 static inline struct freezer *task_freezer(struct task_struct *task) 55 { 56 return container_of(task_subsys_state(task, freezer_subsys_id), 57 struct freezer, css); 58 } 59 60 static struct freezer *parent_freezer(struct freezer *freezer) 61 { 62 struct cgroup *pcg = freezer->css.cgroup->parent; 63 64 if (pcg) 65 return cgroup_freezer(pcg); 66 return NULL; 67 } 68 69 bool cgroup_freezing(struct task_struct *task) 70 { 71 bool ret; 72 73 rcu_read_lock(); 74 ret = task_freezer(task)->state & CGROUP_FREEZING; 75 rcu_read_unlock(); 76 77 return ret; 78 } 79 80 /* 81 * cgroups_write_string() limits the size of freezer state strings to 82 * CGROUP_LOCAL_BUFFER_SIZE 83 */ 84 static const char *freezer_state_strs(unsigned int state) 85 { 86 if (state & CGROUP_FROZEN) 87 return "FROZEN"; 88 if (state & CGROUP_FREEZING) 89 return "FREEZING"; 90 return "THAWED"; 91 }; 92 93 struct cgroup_subsys freezer_subsys; 94 95 static struct cgroup_subsys_state *freezer_css_alloc(struct cgroup *cgroup) 96 { 97 struct freezer *freezer; 98 99 freezer = kzalloc(sizeof(struct freezer), GFP_KERNEL); 100 if (!freezer) 101 return ERR_PTR(-ENOMEM); 102 103 spin_lock_init(&freezer->lock); 104 return &freezer->css; 105 } 106 107 /** 108 * freezer_css_online - commit creation of a freezer cgroup 109 * @cgroup: cgroup being created 110 * 111 * We're committing to creation of @cgroup. Mark it online and inherit 112 * parent's freezing state while holding both parent's and our 113 * freezer->lock. 114 */ 115 static int freezer_css_online(struct cgroup *cgroup) 116 { 117 struct freezer *freezer = cgroup_freezer(cgroup); 118 struct freezer *parent = parent_freezer(freezer); 119 120 /* 121 * The following double locking and freezing state inheritance 122 * guarantee that @cgroup can never escape ancestors' freezing 123 * states. See cgroup_for_each_descendant_pre() for details. 124 */ 125 if (parent) 126 spin_lock_irq(&parent->lock); 127 spin_lock_nested(&freezer->lock, SINGLE_DEPTH_NESTING); 128 129 freezer->state |= CGROUP_FREEZER_ONLINE; 130 131 if (parent && (parent->state & CGROUP_FREEZING)) { 132 freezer->state |= CGROUP_FREEZING_PARENT | CGROUP_FROZEN; 133 atomic_inc(&system_freezing_cnt); 134 } 135 136 spin_unlock(&freezer->lock); 137 if (parent) 138 spin_unlock_irq(&parent->lock); 139 140 return 0; 141 } 142 143 /** 144 * freezer_css_offline - initiate destruction of @cgroup 145 * @cgroup: cgroup being destroyed 146 * 147 * @cgroup is going away. Mark it dead and decrement system_freezing_count 148 * if it was holding one. 149 */ 150 static void freezer_css_offline(struct cgroup *cgroup) 151 { 152 struct freezer *freezer = cgroup_freezer(cgroup); 153 154 spin_lock_irq(&freezer->lock); 155 156 if (freezer->state & CGROUP_FREEZING) 157 atomic_dec(&system_freezing_cnt); 158 159 freezer->state = 0; 160 161 spin_unlock_irq(&freezer->lock); 162 } 163 164 static void freezer_css_free(struct cgroup *cgroup) 165 { 166 kfree(cgroup_freezer(cgroup)); 167 } 168 169 /* 170 * Tasks can be migrated into a different freezer anytime regardless of its 171 * current state. freezer_attach() is responsible for making new tasks 172 * conform to the current state. 173 * 174 * Freezer state changes and task migration are synchronized via 175 * @freezer->lock. freezer_attach() makes the new tasks conform to the 176 * current state and all following state changes can see the new tasks. 177 */ 178 static void freezer_attach(struct cgroup *new_cgrp, struct cgroup_taskset *tset) 179 { 180 struct freezer *freezer = cgroup_freezer(new_cgrp); 181 struct task_struct *task; 182 bool clear_frozen = false; 183 184 spin_lock_irq(&freezer->lock); 185 186 /* 187 * Make the new tasks conform to the current state of @new_cgrp. 188 * For simplicity, when migrating any task to a FROZEN cgroup, we 189 * revert it to FREEZING and let update_if_frozen() determine the 190 * correct state later. 191 * 192 * Tasks in @tset are on @new_cgrp but may not conform to its 193 * current state before executing the following - !frozen tasks may 194 * be visible in a FROZEN cgroup and frozen tasks in a THAWED one. 195 */ 196 cgroup_taskset_for_each(task, new_cgrp, tset) { 197 if (!(freezer->state & CGROUP_FREEZING)) { 198 __thaw_task(task); 199 } else { 200 freeze_task(task); 201 freezer->state &= ~CGROUP_FROZEN; 202 clear_frozen = true; 203 } 204 } 205 206 spin_unlock_irq(&freezer->lock); 207 208 /* 209 * Propagate FROZEN clearing upwards. We may race with 210 * update_if_frozen(), but as long as both work bottom-up, either 211 * update_if_frozen() sees child's FROZEN cleared or we clear the 212 * parent's FROZEN later. No parent w/ !FROZEN children can be 213 * left FROZEN. 214 */ 215 while (clear_frozen && (freezer = parent_freezer(freezer))) { 216 spin_lock_irq(&freezer->lock); 217 freezer->state &= ~CGROUP_FROZEN; 218 clear_frozen = freezer->state & CGROUP_FREEZING; 219 spin_unlock_irq(&freezer->lock); 220 } 221 } 222 223 static void freezer_fork(struct task_struct *task) 224 { 225 struct freezer *freezer; 226 227 rcu_read_lock(); 228 freezer = task_freezer(task); 229 230 /* 231 * The root cgroup is non-freezable, so we can skip the 232 * following check. 233 */ 234 if (!freezer->css.cgroup->parent) 235 goto out; 236 237 spin_lock_irq(&freezer->lock); 238 if (freezer->state & CGROUP_FREEZING) 239 freeze_task(task); 240 spin_unlock_irq(&freezer->lock); 241 out: 242 rcu_read_unlock(); 243 } 244 245 /** 246 * update_if_frozen - update whether a cgroup finished freezing 247 * @cgroup: cgroup of interest 248 * 249 * Once FREEZING is initiated, transition to FROZEN is lazily updated by 250 * calling this function. If the current state is FREEZING but not FROZEN, 251 * this function checks whether all tasks of this cgroup and the descendant 252 * cgroups finished freezing and, if so, sets FROZEN. 253 * 254 * The caller is responsible for grabbing RCU read lock and calling 255 * update_if_frozen() on all descendants prior to invoking this function. 256 * 257 * Task states and freezer state might disagree while tasks are being 258 * migrated into or out of @cgroup, so we can't verify task states against 259 * @freezer state here. See freezer_attach() for details. 260 */ 261 static void update_if_frozen(struct cgroup *cgroup) 262 { 263 struct freezer *freezer = cgroup_freezer(cgroup); 264 struct cgroup *pos; 265 struct cgroup_iter it; 266 struct task_struct *task; 267 268 WARN_ON_ONCE(!rcu_read_lock_held()); 269 270 spin_lock_irq(&freezer->lock); 271 272 if (!(freezer->state & CGROUP_FREEZING) || 273 (freezer->state & CGROUP_FROZEN)) 274 goto out_unlock; 275 276 /* are all (live) children frozen? */ 277 cgroup_for_each_child(pos, cgroup) { 278 struct freezer *child = cgroup_freezer(pos); 279 280 if ((child->state & CGROUP_FREEZER_ONLINE) && 281 !(child->state & CGROUP_FROZEN)) 282 goto out_unlock; 283 } 284 285 /* are all tasks frozen? */ 286 cgroup_iter_start(cgroup, &it); 287 288 while ((task = cgroup_iter_next(cgroup, &it))) { 289 if (freezing(task)) { 290 /* 291 * freezer_should_skip() indicates that the task 292 * should be skipped when determining freezing 293 * completion. Consider it frozen in addition to 294 * the usual frozen condition. 295 */ 296 if (!frozen(task) && !freezer_should_skip(task)) 297 goto out_iter_end; 298 } 299 } 300 301 freezer->state |= CGROUP_FROZEN; 302 out_iter_end: 303 cgroup_iter_end(cgroup, &it); 304 out_unlock: 305 spin_unlock_irq(&freezer->lock); 306 } 307 308 static int freezer_read(struct cgroup *cgroup, struct cftype *cft, 309 struct seq_file *m) 310 { 311 struct cgroup *pos; 312 313 rcu_read_lock(); 314 315 /* update states bottom-up */ 316 cgroup_for_each_descendant_post(pos, cgroup) 317 update_if_frozen(pos); 318 update_if_frozen(cgroup); 319 320 rcu_read_unlock(); 321 322 seq_puts(m, freezer_state_strs(cgroup_freezer(cgroup)->state)); 323 seq_putc(m, '\n'); 324 return 0; 325 } 326 327 static void freeze_cgroup(struct freezer *freezer) 328 { 329 struct cgroup *cgroup = freezer->css.cgroup; 330 struct cgroup_iter it; 331 struct task_struct *task; 332 333 cgroup_iter_start(cgroup, &it); 334 while ((task = cgroup_iter_next(cgroup, &it))) 335 freeze_task(task); 336 cgroup_iter_end(cgroup, &it); 337 } 338 339 static void unfreeze_cgroup(struct freezer *freezer) 340 { 341 struct cgroup *cgroup = freezer->css.cgroup; 342 struct cgroup_iter it; 343 struct task_struct *task; 344 345 cgroup_iter_start(cgroup, &it); 346 while ((task = cgroup_iter_next(cgroup, &it))) 347 __thaw_task(task); 348 cgroup_iter_end(cgroup, &it); 349 } 350 351 /** 352 * freezer_apply_state - apply state change to a single cgroup_freezer 353 * @freezer: freezer to apply state change to 354 * @freeze: whether to freeze or unfreeze 355 * @state: CGROUP_FREEZING_* flag to set or clear 356 * 357 * Set or clear @state on @cgroup according to @freeze, and perform 358 * freezing or thawing as necessary. 359 */ 360 static void freezer_apply_state(struct freezer *freezer, bool freeze, 361 unsigned int state) 362 { 363 /* also synchronizes against task migration, see freezer_attach() */ 364 lockdep_assert_held(&freezer->lock); 365 366 if (!(freezer->state & CGROUP_FREEZER_ONLINE)) 367 return; 368 369 if (freeze) { 370 if (!(freezer->state & CGROUP_FREEZING)) 371 atomic_inc(&system_freezing_cnt); 372 freezer->state |= state; 373 freeze_cgroup(freezer); 374 } else { 375 bool was_freezing = freezer->state & CGROUP_FREEZING; 376 377 freezer->state &= ~state; 378 379 if (!(freezer->state & CGROUP_FREEZING)) { 380 if (was_freezing) 381 atomic_dec(&system_freezing_cnt); 382 freezer->state &= ~CGROUP_FROZEN; 383 unfreeze_cgroup(freezer); 384 } 385 } 386 } 387 388 /** 389 * freezer_change_state - change the freezing state of a cgroup_freezer 390 * @freezer: freezer of interest 391 * @freeze: whether to freeze or thaw 392 * 393 * Freeze or thaw @freezer according to @freeze. The operations are 394 * recursive - all descendants of @freezer will be affected. 395 */ 396 static void freezer_change_state(struct freezer *freezer, bool freeze) 397 { 398 struct cgroup *pos; 399 400 /* update @freezer */ 401 spin_lock_irq(&freezer->lock); 402 freezer_apply_state(freezer, freeze, CGROUP_FREEZING_SELF); 403 spin_unlock_irq(&freezer->lock); 404 405 /* 406 * Update all its descendants in pre-order traversal. Each 407 * descendant will try to inherit its parent's FREEZING state as 408 * CGROUP_FREEZING_PARENT. 409 */ 410 rcu_read_lock(); 411 cgroup_for_each_descendant_pre(pos, freezer->css.cgroup) { 412 struct freezer *pos_f = cgroup_freezer(pos); 413 struct freezer *parent = parent_freezer(pos_f); 414 415 /* 416 * Our update to @parent->state is already visible which is 417 * all we need. No need to lock @parent. For more info on 418 * synchronization, see freezer_post_create(). 419 */ 420 spin_lock_irq(&pos_f->lock); 421 freezer_apply_state(pos_f, parent->state & CGROUP_FREEZING, 422 CGROUP_FREEZING_PARENT); 423 spin_unlock_irq(&pos_f->lock); 424 } 425 rcu_read_unlock(); 426 } 427 428 static int freezer_write(struct cgroup *cgroup, struct cftype *cft, 429 const char *buffer) 430 { 431 bool freeze; 432 433 if (strcmp(buffer, freezer_state_strs(0)) == 0) 434 freeze = false; 435 else if (strcmp(buffer, freezer_state_strs(CGROUP_FROZEN)) == 0) 436 freeze = true; 437 else 438 return -EINVAL; 439 440 freezer_change_state(cgroup_freezer(cgroup), freeze); 441 return 0; 442 } 443 444 static u64 freezer_self_freezing_read(struct cgroup *cgroup, struct cftype *cft) 445 { 446 struct freezer *freezer = cgroup_freezer(cgroup); 447 448 return (bool)(freezer->state & CGROUP_FREEZING_SELF); 449 } 450 451 static u64 freezer_parent_freezing_read(struct cgroup *cgroup, struct cftype *cft) 452 { 453 struct freezer *freezer = cgroup_freezer(cgroup); 454 455 return (bool)(freezer->state & CGROUP_FREEZING_PARENT); 456 } 457 458 static struct cftype files[] = { 459 { 460 .name = "state", 461 .flags = CFTYPE_NOT_ON_ROOT, 462 .read_seq_string = freezer_read, 463 .write_string = freezer_write, 464 }, 465 { 466 .name = "self_freezing", 467 .flags = CFTYPE_NOT_ON_ROOT, 468 .read_u64 = freezer_self_freezing_read, 469 }, 470 { 471 .name = "parent_freezing", 472 .flags = CFTYPE_NOT_ON_ROOT, 473 .read_u64 = freezer_parent_freezing_read, 474 }, 475 { } /* terminate */ 476 }; 477 478 struct cgroup_subsys freezer_subsys = { 479 .name = "freezer", 480 .css_alloc = freezer_css_alloc, 481 .css_online = freezer_css_online, 482 .css_offline = freezer_css_offline, 483 .css_free = freezer_css_free, 484 .subsys_id = freezer_subsys_id, 485 .attach = freezer_attach, 486 .fork = freezer_fork, 487 .base_cftypes = files, 488 }; 489
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.