linux/kernel/cgroup_freezer.c
<<
>>
Prefs
   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
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.