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/module.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 25enum freezer_state { 26 CGROUP_THAWED = 0, 27 CGROUP_FREEZING, 28 CGROUP_FROZEN, 29}; 30 31struct freezer { 32 struct cgroup_subsys_state css; 33 enum freezer_state state; 34 spinlock_t lock; /* protects _writes_ to state */ 35}; 36 37static inline struct freezer *cgroup_freezer( 38 struct cgroup *cgroup) 39{ 40 return container_of( 41 cgroup_subsys_state(cgroup, freezer_subsys_id), 42 struct freezer, css); 43} 44 45static inline struct freezer *task_freezer(struct task_struct *task) 46{ 47 return container_of(task_subsys_state(task, freezer_subsys_id), 48 struct freezer, css); 49} 50 51int cgroup_freezing_or_frozen(struct task_struct *task) 52{ 53 struct freezer *freezer; 54 enum freezer_state state; 55 56 task_lock(task); 57 freezer = task_freezer(task); 58 if (!freezer->css.cgroup->parent) 59 state = CGROUP_THAWED; /* root cgroup can't be frozen */ 60 else 61 state = freezer->state; 62 task_unlock(task); 63 64 return (state == CGROUP_FREEZING) || (state == CGROUP_FROZEN); 65} 66 67/* 68 * cgroups_write_string() limits the size of freezer state strings to 69 * CGROUP_LOCAL_BUFFER_SIZE 70 */ 71static const char *freezer_state_strs[] = { 72 "THAWED", 73 "FREEZING", 74 "FROZEN", 75}; 76 77/* 78 * State diagram 79 * Transitions are caused by userspace writes to the freezer.state file. 80 * The values in parenthesis are state labels. The rest are edge labels. 81 * 82 * (THAWED) --FROZEN--> (FREEZING) --FROZEN--> (FROZEN) 83 * ^ ^ | | 84 * | \_______THAWED_______/ | 85 * \__________________________THAWED____________/ 86 */ 87 88struct cgroup_subsys freezer_subsys; 89 90/* Locks taken and their ordering 91 * ------------------------------ 92 * cgroup_mutex (AKA cgroup_lock) 93 * freezer->lock 94 * css_set_lock 95 * task->alloc_lock (AKA task_lock) 96 * task->sighand->siglock 97 * 98 * cgroup code forces css_set_lock to be taken before task->alloc_lock 99 * 100 * freezer_create(), freezer_destroy(): 101 * cgroup_mutex [ by cgroup core ] 102 * 103 * freezer_can_attach(): 104 * cgroup_mutex (held by caller of can_attach) 105 * 106 * cgroup_freezing_or_frozen(): 107 * task->alloc_lock (to get task's cgroup) 108 * 109 * freezer_fork() (preserving fork() performance means can't take cgroup_mutex): 110 * freezer->lock 111 * sighand->siglock (if the cgroup is freezing) 112 * 113 * freezer_read(): 114 * cgroup_mutex 115 * freezer->lock 116 * write_lock css_set_lock (cgroup iterator start) 117 * task->alloc_lock 118 * read_lock css_set_lock (cgroup iterator start) 119 * 120 * freezer_write() (freeze): 121 * cgroup_mutex 122 * freezer->lock 123 * write_lock css_set_lock (cgroup iterator start) 124 * task->alloc_lock 125 * read_lock css_set_lock (cgroup iterator start) 126 * sighand->siglock (fake signal delivery inside freeze_task()) 127 * 128 * freezer_write() (unfreeze): 129 * cgroup_mutex 130 * freezer->lock 131 * write_lock css_set_lock (cgroup iterator start) 132 * task->alloc_lock 133 * read_lock css_set_lock (cgroup iterator start) 134 * task->alloc_lock (inside thaw_process(), prevents race with refrigerator()) 135 * sighand->siglock 136 */ 137static struct cgroup_subsys_state *freezer_create(struct cgroup_subsys *ss, 138 struct cgroup *cgroup) 139{ 140 struct freezer *freezer; 141 142 freezer = kzalloc(sizeof(struct freezer), GFP_KERNEL); 143 if (!freezer) 144 return ERR_PTR(-ENOMEM); 145 146 spin_lock_init(&freezer->lock); 147 freezer->state = CGROUP_THAWED; 148 return &freezer->css; 149} 150 151static void freezer_destroy(struct cgroup_subsys *ss, 152 struct cgroup *cgroup) 153{ 154 kfree(cgroup_freezer(cgroup)); 155} 156 157/* Task is frozen or will freeze immediately when next it gets woken */ 158static bool is_task_frozen_enough(struct task_struct *task) 159{ 160 return frozen(task) || 161 (task_is_stopped_or_traced(task) && freezing(task)); 162} 163 164/* 165 * The call to cgroup_lock() in the freezer.state write method prevents 166 * a write to that file racing against an attach, and hence the 167 * can_attach() result will remain valid until the attach completes. 168 */ 169static int freezer_can_attach(struct cgroup_subsys *ss, 170 struct cgroup *new_cgroup, 171 struct task_struct *task, bool threadgroup) 172{ 173 struct freezer *freezer; 174 175 /* 176 * Anything frozen can't move or be moved to/from. 177 * 178 * Since orig_freezer->state == FROZEN means that @task has been 179 * frozen, so it's sufficient to check the latter condition. 180 */ 181 182 if (is_task_frozen_enough(task)) 183 return -EBUSY; 184 185 freezer = cgroup_freezer(new_cgroup); 186 if (freezer->state == CGROUP_FROZEN) 187 return -EBUSY; 188 189 if (threadgroup) { 190 struct task_struct *c; 191 192 rcu_read_lock(); 193 list_for_each_entry_rcu(c, &task->thread_group, thread_group) { 194 if (is_task_frozen_enough(c)) { 195 rcu_read_unlock(); 196 return -EBUSY; 197 } 198 } 199 rcu_read_unlock(); 200 } 201 202 return 0; 203} 204 205static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) 206{ 207 struct freezer *freezer; 208 209 /* 210 * No lock is needed, since the task isn't on tasklist yet, 211 * so it can't be moved to another cgroup, which means the 212 * freezer won't be removed and will be valid during this 213 * function call. Nevertheless, apply RCU read-side critical 214 * section to suppress RCU lockdep false positives. 215 */ 216 rcu_read_lock(); 217 freezer = task_freezer(task); 218 rcu_read_unlock(); 219 220 /* 221 * The root cgroup is non-freezable, so we can skip the 222 * following check. 223 */ 224 if (!freezer->css.cgroup->parent) 225 return; 226 227 spin_lock_irq(&freezer->lock); 228 BUG_ON(freezer->state == CGROUP_FROZEN); 229 230 /* Locking avoids race with FREEZING -> THAWED transitions. */ 231 if (freezer->state == CGROUP_FREEZING) 232 freeze_task(task, true); 233 spin_unlock_irq(&freezer->lock); 234} 235 236/* 237 * caller must hold freezer->lock 238 */ 239static void update_freezer_state(struct cgroup *cgroup, 240 struct freezer *freezer) 241{ 242 struct cgroup_iter it; 243 struct task_struct *task; 244 unsigned int nfrozen = 0, ntotal = 0; 245 246 cgroup_iter_start(cgroup, &it); 247 while ((task = cgroup_iter_next(cgroup, &it))) { 248 ntotal++; 249 if (is_task_frozen_enough(task)) 250 nfrozen++; 251 } 252 253 /* 254 * Transition to FROZEN when no new tasks can be added ensures 255 * that we never exist in the FROZEN state while there are unfrozen 256 * tasks. 257 */ 258 if (nfrozen == ntotal) 259 freezer->state = CGROUP_FROZEN; 260 else if (nfrozen > 0) 261 freezer->state = CGROUP_FREEZING; 262 else 263 freezer->state = CGROUP_THAWED; 264 cgroup_iter_end(cgroup, &it); 265} 266 267static int freezer_read(struct cgroup *cgroup, struct cftype *cft, 268 struct seq_file *m) 269{ 270 struct freezer *freezer; 271 enum freezer_state state; 272 273 if (!cgroup_lock_live_group(cgroup)) 274 return -ENODEV; 275 276 freezer = cgroup_freezer(cgroup); 277 spin_lock_irq(&freezer->lock); 278 state = freezer->state; 279 if (state == CGROUP_FREEZING) { 280 /* We change from FREEZING to FROZEN lazily if the cgroup was 281 * only partially frozen when we exitted write. */ 282 update_freezer_state(cgroup, freezer); 283 state = freezer->state; 284 } 285 spin_unlock_irq(&freezer->lock); 286 cgroup_unlock(); 287 288 seq_puts(m, freezer_state_strs[state]); 289 seq_putc(m, '\n'); 290 return 0; 291} 292 293static int try_to_freeze_cgroup(struct cgroup *cgroup, struct freezer *freezer) 294{ 295 struct cgroup_iter it; 296 struct task_struct *task; 297 unsigned int num_cant_freeze_now = 0; 298 299 freezer->state = CGROUP_FREEZING; 300 cgroup_iter_start(cgroup, &it); 301 while ((task = cgroup_iter_next(cgroup, &it))) { 302 if (!freeze_task(task, true)) 303 continue; 304 if (is_task_frozen_enough(task)) 305 continue; 306 if (!freezing(task) && !freezer_should_skip(task)) 307 num_cant_freeze_now++; 308 } 309 cgroup_iter_end(cgroup, &it); 310 311 return num_cant_freeze_now ? -EBUSY : 0; 312} 313 314static void unfreeze_cgroup(struct cgroup *cgroup, struct freezer *freezer) 315{ 316 struct cgroup_iter it; 317 struct task_struct *task; 318 319 cgroup_iter_start(cgroup, &it); 320 while ((task = cgroup_iter_next(cgroup, &it))) { 321 thaw_process(task); 322 } 323 cgroup_iter_end(cgroup, &it); 324 325 freezer->state = CGROUP_THAWED; 326} 327 328static int freezer_change_state(struct cgroup *cgroup, 329 enum freezer_state goal_state) 330{ 331 struct freezer *freezer; 332 int retval = 0; 333 334 freezer = cgroup_freezer(cgroup); 335 336 spin_lock_irq(&freezer->lock); 337 338 update_freezer_state(cgroup, freezer); 339 if (goal_state == freezer->state) 340 goto out; 341 342 switch (goal_state) { 343 case CGROUP_THAWED: 344 unfreeze_cgroup(cgroup, freezer); 345 break; 346 case CGROUP_FROZEN: 347 retval = try_to_freeze_cgroup(cgroup, freezer); 348 break; 349 default: 350 BUG(); 351 } 352out: 353 spin_unlock_irq(&freezer->lock); 354 355 return retval; 356} 357 358static int freezer_write(struct cgroup *cgroup, 359 struct cftype *cft, 360 const char *buffer) 361{ 362 int retval; 363 enum freezer_state goal_state; 364 365 if (strcmp(buffer, freezer_state_strs[CGROUP_THAWED]) == 0) 366 goal_state = CGROUP_THAWED; 367 else if (strcmp(buffer, freezer_state_strs[CGROUP_FROZEN]) == 0) 368 goal_state = CGROUP_FROZEN; 369 else 370 return -EINVAL; 371 372 if (!cgroup_lock_live_group(cgroup)) 373 return -ENODEV; 374 retval = freezer_change_state(cgroup, goal_state); 375 cgroup_unlock(); 376 return retval; 377} 378 379static struct cftype files[] = { 380 { 381 .name = "state", 382 .read_seq_string = freezer_read, 383 .write_string = freezer_write, 384 }, 385}; 386 387static int freezer_populate(struct cgroup_subsys *ss, struct cgroup *cgroup) 388{ 389 if (!cgroup->parent) 390 return 0; 391 return cgroup_add_files(cgroup, ss, files, ARRAY_SIZE(files)); 392} 393 394struct cgroup_subsys freezer_subsys = { 395 .name = "freezer", 396 .create = freezer_create, 397 .destroy = freezer_destroy, 398 .populate = freezer_populate, 399 .subsys_id = freezer_subsys_id, 400 .can_attach = freezer_can_attach, 401 .attach = NULL, 402 .fork = freezer_fork, 403 .exit = NULL, 404}; 405