[PATCH 0/4] Container Freezer: Reuse Suspend Freezer - Kernel

This is a discussion on [PATCH 0/4] Container Freezer: Reuse Suspend Freezer - Kernel ; This patchset reuses the container infrastructure and the swsusp freezer to freeze a group of tasks. The freezer subsystem in the container filesystem defines a file named freezer.state. Writing "FROZEN" to the state file will freeze all tasks in the ...

+ Reply to Thread
Results 1 to 16 of 16

Thread: [PATCH 0/4] Container Freezer: Reuse Suspend Freezer

  1. [PATCH 0/4] Container Freezer: Reuse Suspend Freezer


    This patchset reuses the container infrastructure and the swsusp freezer to
    freeze a group of tasks.

    The freezer subsystem in the container filesystem defines a file named
    freezer.state. Writing "FROZEN" to the state file will freeze all tasks in the
    cgroup. Subsequently writing "RUNNING" will unfreeze the tasks in the cgroup.
    Reading will return the current state.

    * Examples of usage :

    # mkdir /containers/freezer
    # mount -t cgroup -ofreezer,signal freezer /containers
    # mkdir /containers/0
    # echo $some_pid > /containers/0/tasks

    to get status of the freezer subsystem :

    # cat /containers/0/freezer.state
    RUNNING

    to freeze all tasks in the container :

    # echo FROZEN > /containers/0/freezer.state
    # cat /containers/0/freezer.state
    FREEZING
    # cat /containers/0/freezer.state
    FROZEN

    to unfreeze all tasks in the container :

    # echo RUNNING > /containers/0/freezer.state
    # cat /containers/0/freezer.state
    RUNNING

    to kill all tasks in the container :

    # echo 9 > /containers/0/signal.kill

    I've reworked Cedric's patches to use task_lock() to protect access to the
    task's cgroup.

    Paul, Pavel asked me to send these to Rafael next. They are patches to make
    the freezer useful for checkpoint/restart using cgroups so it would be nice
    to get an explicit [N]Ack from you first.

    Rafael, if Paul agrees, please consider applying these patches.

    Changes since v3:
    v4 (Almost all of these changes are confined to patch 3):
    Reworked the series to use task_lock() instead of RCU.
    Reworked the series to use write_string() and read_seq_string()
    cgroup methods.
    Fixed the race Paul Menage identified.
    Fixed up check_if_frozen() to do more than just test the FROZEN
    flag. In some cases tasks could be stopped (T) and marked
    FREEZING. When that happens we can safely assume that it
    will be frozen immediately upon waking up in the kernel.
    Waiting for it to get marked with PF_FROZEN in order to
    transition to the FROZEN state would block unnecessarily.
    Removed freezer_ prefix from static functions in cgroup_freezer.c.
    Simplified STATE_ switch.
    Updated the locking comments.
    v3:
    Ported to 2.6.26-rc5-mm2 with Rafael's freezer patches
    Tested on 24 combinations of 3 architectures (x86, x86_64, ppc64)
    with 8 different kernel configs varying power management
    and cgroup config variables. Each patch builds and boots
    in these 24 combinations.
    Passes functional testing.
    v2 (roughly patches 3 and 5):
    Moved the "kill" file into a separate cgroup subsystem (signal) and
    it's own patch.
    Changed the name of the file from freezer.freeze to freezer.state.
    Switched from taking 1 and 0 as input to the strings "FROZEN" and
    "RUNNING", respectively. This helps keep the interface
    human-usable if/when we need to more states.
    Checked that stopped or interrupted is "frozen enough"
    Since try_to_freeze() is called upon wakeup of these tasks
    this should be fine. This idea comes from recent changes to
    the freezer.
    Checked that if (task == current) whilst freezing cgroup we're ok
    Fixed bug where -EBUSY would always be returned when freezing
    Added code to handle userspace retries for any remaining -EBUSY

    Cheers,
    -Matt Helsley

    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  2. [PATCH 4/4] Container Freezer: Skip frozen cgroups during power management resume

    From: Cedric Le Goater
    Subject: [PATCH 4/4] Container Freezer: Skip frozen cgroups during power management resume

    When a system is resumed after a suspend, it will also unfreeze
    frozen cgroups.

    This patchs modifies the resume sequence to skip the tasks which
    are part of a frozen control group.

    Signed-off-by: Cedric Le Goater
    Signed-off-by: Matt Helsley
    Tested-by: Matt Helsley
    ---
    kernel/power/process.c | 4 ++++
    1 file changed, 4 insertions(+)

    Index: linux-2.6.26-rc5-mm2/kernel/power/process.c
    ================================================== =================
    --- linux-2.6.26-rc5-mm2.orig/kernel/power/process.c
    +++ linux-2.6.26-rc5-mm2/kernel/power/process.c
    @@ -11,10 +11,11 @@
    #include
    #include
    #include
    #include
    #include
    +#include

    /*
    * Timeout for stopping processes
    */
    #define TIMEOUT (20 * HZ)
    @@ -133,10 +134,13 @@ static void thaw_tasks(bool nosig_only)
    continue;

    if (nosig_only && should_send_signal(p))
    continue;

    + if (cgroup_frozen(p))
    + continue;
    +
    thaw_process(p);
    } while_each_thread(g, p);
    read_unlock(&tasklist_lock);
    }


    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  3. [PATCH 3/4] Container Freezer: Implement freezer cgroup subsystem

    From: Cedric Le Goater
    Subject: [PATCH 3/4] Container Freezer: Implement freezer cgroup subsystem

    This patch implements a new freezer subsystem in the control groups framework.
    It provides a way to stop and resume execution of all tasks in a cgroup by
    writing in the cgroup filesystem.

    This is the basic mechanism which should do the right thing for user space task
    in a simple scenario.

    It's important to note that freezing can be incomplete. In that case we return
    EBUSY. This means that some tasks in the cgroup are busy doing something that
    prevents us from completely freezing the cgroup at this time. After EBUSY,
    the cgroup will remain partially frozen -- reflected by freezer.state reporting
    "FREEZING" when read. The state will remain "FREEZING" until one of these
    things happens:

    1) Userspace cancels the freezing operation by writing "RUNNING" to
    the freezer.state file
    2) Userspace retries the freezing operation by writing "FROZEN" to
    the freezer.state file (writing "FREEZING" is not legal
    and returns EIO)
    3) The tasks that blocked the cgroup from entering the "FROZEN"
    state disappear from the cgroup's set of tasks.

    Signed-off-by: Cedric Le Goater
    Signed-off-by: Matt Helsley
    Tested-by: Matt Helsley
    ---
    Changelog:
    v2:
    Moved the "kill" file into a separate cgroup subsystem (signal) and
    it's own patch.
    Changed the name of the file from freezer.freeze to freezer.state.
    Switched from taking 1 and 0 as input to the strings "FROZEN" and
    "RUNNING", respectively. This helps keep the interface
    human-usable if/when we need to more states.
    Checked that stopped or interrupted is "frozen enough"
    Since try_to_freeze() is called upon wakeup of these tasks
    this should be fine. This idea comes from recent changes to
    the freezer.
    Checked that if (task == current) whilst freezing cgroup we're ok
    Fixed bug where -EBUSY would always be returned when freezing
    Added code to handle userspace retries for any remaining -EBUSY

    include/linux/cgroup_freezer.h | 71 +++++++++
    include/linux/cgroup_subsys.h | 6
    include/linux/freezer.h | 16 +-
    init/Kconfig | 7
    kernel/Makefile | 1
    kernel/cgroup_freezer.c | 317 +++++++++++++++++++++++++++++++++++++++++
    6 files changed, 414 insertions(+), 4 deletions(-)

    Index: linux-2.6.26-rc5-mm2/include/linux/cgroup_freezer.h
    ================================================== =================
    --- /dev/null
    +++ linux-2.6.26-rc5-mm2/include/linux/cgroup_freezer.h
    @@ -0,0 +1,71 @@
    +#ifndef _LINUX_CGROUP_FREEZER_H
    +#define _LINUX_CGROUP_FREEZER_H
    +/*
    + * cgroup_freezer.h - control group freezer subsystem interface
    + *
    + * Copyright IBM Corporation, 2007
    + *
    + * Author : Cedric Le Goater
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of version 2.1 of the GNU Lesser General Public License
    + * as published by the Free Software Foundation.
    + *
    + * This program is distributed in the hope that it would be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    + */
    +
    +#include
    +
    +#ifdef CONFIG_CGROUP_FREEZER
    +
    +enum freezer_state {
    + STATE_RUNNING = 0,
    + STATE_FREEZING,
    + STATE_FROZEN,
    +};
    +
    +struct freezer {
    + struct cgroup_subsys_state css;
    + enum freezer_state state;
    + spinlock_t lock; /* protects _writes_ to state */
    +};
    +
    +static inline struct freezer *cgroup_freezer(
    + struct cgroup *cgroup)
    +{
    + return container_of(
    + cgroup_subsys_state(cgroup, freezer_subsys_id),
    + struct freezer, css);
    +}
    +
    +static inline struct freezer *task_freezer(struct task_struct *task)
    +{
    + return container_of(task_subsys_state(task, freezer_subsys_id),
    + struct freezer, css);
    +}
    +
    +static inline int cgroup_frozen(struct task_struct *task)
    +{
    + struct freezer *freezer;
    + enum freezer_state state;
    +
    + task_lock(task);
    + freezer = task_freezer(task);
    + state = freezer->state;
    + task_unlock(task);
    +
    + return state == STATE_FROZEN;
    +}
    +
    +#else /* !CONFIG_CGROUP_FREEZER */
    +
    +static inline int cgroup_frozen(struct task_struct *task)
    +{
    + return 0;
    +}
    +
    +#endif /* !CONFIG_CGROUP_FREEZER */
    +
    +#endif /* _LINUX_CGROUP_FREEZER_H */
    Index: linux-2.6.26-rc5-mm2/include/linux/cgroup_subsys.h
    ================================================== =================
    --- linux-2.6.26-rc5-mm2.orig/include/linux/cgroup_subsys.h
    +++ linux-2.6.26-rc5-mm2/include/linux/cgroup_subsys.h
    @@ -50,5 +50,11 @@ SUBSYS(devices)
    #ifdef CONFIG_CGROUP_MEMRLIMIT_CTLR
    SUBSYS(memrlimit_cgroup)
    #endif

    /* */
    +
    +#ifdef CONFIG_CGROUP_FREEZER
    +SUBSYS(freezer)
    +#endif
    +
    +/* */
    Index: linux-2.6.26-rc5-mm2/init/Kconfig
    ================================================== =================
    --- linux-2.6.26-rc5-mm2.orig/init/Kconfig
    +++ linux-2.6.26-rc5-mm2/init/Kconfig
    @@ -329,10 +329,17 @@ config GROUP_SCHED
    default n
    help
    This feature lets CPU scheduler recognize task groups and control CPU
    bandwidth allocation to such task groups.

    +config CGROUP_FREEZER
    + bool "control group freezer subsystem"
    + depends on CGROUPS
    + help
    + Provides a way to freeze and unfreeze all tasks in a
    + cgroup
    +
    config FAIR_GROUP_SCHED
    bool "Group scheduling for SCHED_OTHER"
    depends on GROUP_SCHED
    default GROUP_SCHED

    Index: linux-2.6.26-rc5-mm2/kernel/Makefile
    ================================================== =================
    --- linux-2.6.26-rc5-mm2.orig/kernel/Makefile
    +++ linux-2.6.26-rc5-mm2/kernel/Makefile
    @@ -49,10 +49,11 @@ obj-$(CONFIG_PM) += power/
    obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
    obj-$(CONFIG_KEXEC) += kexec.o
    obj-$(CONFIG_COMPAT) += compat.o
    obj-$(CONFIG_CGROUPS) += cgroup.o
    obj-$(CONFIG_CGROUP_DEBUG) += cgroup_debug.o
    +obj-$(CONFIG_CGROUP_FREEZER) += cgroup_freezer.o
    obj-$(CONFIG_CPUSETS) += cpuset.o
    obj-$(CONFIG_CGROUP_NS) += ns_cgroup.o
    obj-$(CONFIG_UTS_NS) += utsname.o
    obj-$(CONFIG_USER_NS) += user_namespace.o
    obj-$(CONFIG_PID_NS) += pid_namespace.o
    Index: linux-2.6.26-rc5-mm2/kernel/cgroup_freezer.c
    ================================================== =================
    --- /dev/null
    +++ linux-2.6.26-rc5-mm2/kernel/cgroup_freezer.c
    @@ -0,0 +1,317 @@
    +/*
    + * cgroup_freezer.c - control group freezer subsystem
    + *
    + * Copyright IBM Corporation, 2007
    + *
    + * Author : Cedric Le Goater
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms of version 2.1 of the GNU Lesser General Public License
    + * as published by the Free Software Foundation.
    + *
    + * This program is distributed in the hope that it would be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    + */
    +
    +#include
    +#include
    +#include
    +#include
    +#include
    +#include
    +#include
    +
    +/*
    + * Buffer size for freezer state is limited by cgroups write_string()
    + * interface. See cgroups code for the current size.
    + */
    +static const char *freezer_state_strs[] = {
    + "RUNNING",
    + "FREEZING",
    + "FROZEN",
    +};
    +
    +/*
    + * State diagram (transition labels in parenthesis):
    + *
    + * RUNNING -(FROZEN)-> FREEZING -(FROZEN)-> FROZEN
    + * ^ ^ | |
    + * | |____(RUNNING)_____| |
    + * |___________________________(RUNNING)____|
    + */
    +
    +struct cgroup_subsys freezer_subsys;
    +
    +/* Locks taken and their ordering:
    + *
    + * freezer_create(), freezer_destroy():
    + * cgroup_lock [ by cgroup core ]
    + *
    + * can_attach():
    + * cgroup_lock
    + *
    + * cgroup_frozen():
    + * task_lock
    + *
    + * freezer_fork():
    + * task_lock
    + * freezer->lock
    + * sighand->siglock
    + *
    + * freezer_read():
    + * cgroup_lock
    + * freezer->lock
    + * read_lock css_set_lock
    + *
    + * freezer_write():
    + * cgroup_lock
    + * freezer->lock
    + * read_lock css_set_lock
    + * [unfreeze: task_lock (reaquire freezer->lock)]
    + * sighand->siglock
    + */
    +static struct cgroup_subsys_state *freezer_create(struct cgroup_subsys *ss,
    + struct cgroup *cgroup)
    +{
    + struct freezer *freezer;
    +
    + freezer = kzalloc(sizeof(struct freezer), GFP_KERNEL);
    + if (!freezer)
    + return ERR_PTR(-ENOMEM);
    +
    + spin_lock_init(&freezer->lock);
    + freezer->state = STATE_RUNNING;
    + return &freezer->css;
    +}
    +
    +static void freezer_destroy(struct cgroup_subsys *ss,
    + struct cgroup *cgroup)
    +{
    + kfree(cgroup_freezer(cgroup));
    +}
    +
    +
    +static int freezer_can_attach(struct cgroup_subsys *ss,
    + struct cgroup *new_cgroup,
    + struct task_struct *task)
    +{
    + struct freezer *freezer;
    + int retval = 0;
    +
    + /*
    + * The call to cgroup_lock() in the freezer.state write method prevents
    + * a write to that file racing against an attach, and hence the
    + * can_attach() result will remain valid until the attach completes.
    + */
    + freezer = cgroup_freezer(new_cgroup);
    + if (freezer->state == STATE_FROZEN)
    + retval = -EBUSY;
    + return retval;
    +}
    +
    +static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task)
    +{
    + struct freezer *freezer;
    +
    + task_lock(task);
    + freezer = task_freezer(task);
    +
    + BUG_ON(freezer->state == STATE_FROZEN);
    +
    + /* Locking avoids race with FREEZING -> RUNNING transitions. */
    + spin_lock_irq(&freezer->lock);
    + if (freezer->state == STATE_FREEZING)
    + freeze_task(task, true);
    + spin_unlock_irq(&freezer->lock);
    +
    + task_unlock(task);
    +}
    +
    +/*
    + * caller must hold freezer->lock
    + */
    +static void check_if_frozen(struct cgroup *cgroup,
    + struct freezer *freezer)
    +{
    + struct cgroup_iter it;
    + struct task_struct *task;
    + unsigned int nfrozen = 0, ntotal = 0;
    +
    + cgroup_iter_start(cgroup, &it);
    + while ((task = cgroup_iter_next(cgroup, &it))) {
    + ntotal++;
    + /*
    + * Task is frozen or will freeze immediately when next it gets
    + * woken
    + */
    + if (frozen(task) ||
    + (task_is_stopped_or_traced(task) && freezing(task)))
    + nfrozen++;
    + }
    +
    + /*
    + * Transition to FROZEN when no new tasks can be added ensures
    + * that we never exist in the FROZEN state while there are unfrozen
    + * tasks.
    + */
    + if (nfrozen == ntotal)
    + freezer->state = STATE_FROZEN;
    + cgroup_iter_end(cgroup, &it);
    +}
    +
    +static ssize_t freezer_read(struct cgroup *cgroup, struct cftype *cft,
    + struct seq_file *m)
    +{
    + struct freezer *freezer;
    + enum freezer_state state;
    +
    + if (!cgroup_lock_live_group(cgroup))
    + return -ENODEV;
    +
    + freezer = cgroup_freezer(cgroup);
    + spin_lock_irq(&freezer->lock);
    + state = freezer->state;
    + if (state == STATE_FREEZING) {
    + /* We change from FREEZING to FROZEN lazily if the cgroup was
    + * only partially frozen when we exitted write. */
    + check_if_frozen(cgroup, freezer);
    + state = freezer->state;
    + }
    + spin_unlock_irq(&freezer->lock);
    + cgroup_unlock();
    +
    + seq_puts(m, freezer_state_strs[state]);
    + seq_putc(m, '\n');
    + return 0;
    +}
    +
    +static int try_to_freeze_cgroup(struct cgroup *cgroup, struct freezer *freezer)
    +{
    + struct cgroup_iter it;
    + struct task_struct *task;
    + unsigned int num_cant_freeze_now = 0;
    +
    + freezer->state = STATE_FREEZING;
    + cgroup_iter_start(cgroup, &it);
    + while ((task = cgroup_iter_next(cgroup, &it))) {
    + if (!freeze_task(task, true))
    + continue;
    + if (task_is_stopped_or_traced(task) && freezing(task))
    + /*
    + * The freeze flag is set so these tasks will
    + * immediately go into the fridge upon waking.
    + */
    + continue;
    + if (!freezing(task) && !freezer_should_skip(task))
    + num_cant_freeze_now++;
    + }
    + cgroup_iter_end(cgroup, &it);
    +
    + return num_cant_freeze_now ? -EBUSY : 0;
    +}
    +
    +static int unfreeze_cgroup(struct cgroup *cgroup, struct freezer *freezer)
    +{
    + struct cgroup_iter it;
    + struct task_struct *task;
    +
    + cgroup_iter_start(cgroup, &it);
    + while ((task = cgroup_iter_next(cgroup, &it))) {
    + int do_wake;
    +
    + /* Drop freezer->lock to fix lock ordering (see freezer_fork) */
    + spin_unlock_irq(&freezer->lock);
    + task_lock(task);
    + spin_lock_irq(&freezer->lock);
    + do_wake = __thaw_process(task);
    + task_unlock(task);
    + if (do_wake)
    + wake_up_process(task);
    + }
    + cgroup_iter_end(cgroup, &it);
    + freezer->state = STATE_RUNNING;
    +
    + return 0;
    +}
    +
    +static int freezer_change_state(struct cgroup *cgroup,
    + enum freezer_state goal_state)
    +{
    + struct freezer *freezer;
    + int retval = 0;
    +
    + freezer = cgroup_freezer(cgroup);
    + spin_lock_irq(&freezer->lock);
    + check_if_frozen(cgroup, freezer); /* may update freezer->state */
    + if (goal_state == freezer->state)
    + goto out;
    + switch (freezer->state) {
    + case STATE_RUNNING:
    + retval = try_to_freeze_cgroup(cgroup, freezer);
    + break;
    + case STATE_FREEZING:
    + if (goal_state == STATE_FROZEN) {
    + /* Userspace is retrying after
    + * "/bin/echo FROZEN > freezer.state" returned -EBUSY */
    + retval = try_to_freeze_cgroup(cgroup, freezer);
    + break;
    + }
    + /* state == FREEZING and goal_state == RUNNING, so unfreeze */
    + case STATE_FROZEN:
    + retval = unfreeze_cgroup(cgroup, freezer);
    + break;
    + default:
    + break;
    + }
    +out:
    + spin_unlock_irq(&freezer->lock);
    +
    + return retval;
    +}
    +
    +static int freezer_write(struct cgroup *cgroup,
    + struct cftype *cft,
    + const char *buffer)
    +{
    + int retval;
    + enum freezer_state goal_state;
    +
    + if (strcmp(buffer, freezer_state_strs[STATE_RUNNING]) == 0)
    + goal_state = STATE_RUNNING;
    + else if (strcmp(buffer, freezer_state_strs[STATE_FROZEN]) == 0)
    + goal_state = STATE_FROZEN;
    + else
    + return -EIO;
    +
    + if (!cgroup_lock_live_group(cgroup))
    + return -ENODEV;
    + retval = freezer_change_state(cgroup, goal_state);
    + cgroup_unlock();
    + return retval;
    +}
    +
    +static struct cftype files[] = {
    + {
    + .name = "state",
    + .read_seq_string = freezer_read,
    + .write_string = freezer_write,
    + },
    +};
    +
    +static int freezer_populate(struct cgroup_subsys *ss, struct cgroup *cgroup)
    +{
    + return cgroup_add_files(cgroup, ss, files, ARRAY_SIZE(files));
    +}
    +
    +struct cgroup_subsys freezer_subsys = {
    + .name = "freezer",
    + .create = freezer_create,
    + .destroy = freezer_destroy,
    + .populate = freezer_populate,
    + .subsys_id = freezer_subsys_id,
    + .can_attach = freezer_can_attach,
    + .attach = NULL,
    + .fork = freezer_fork,
    + .exit = NULL,
    +};
    Index: linux-2.6.26-rc5-mm2/include/linux/freezer.h
    ================================================== =================
    --- linux-2.6.26-rc5-mm2.orig/include/linux/freezer.h
    +++ linux-2.6.26-rc5-mm2/include/linux/freezer.h
    @@ -44,26 +44,34 @@ static inline bool should_send_signal(st
    }

    /*
    * Wake up a frozen process
    *
    - * task_lock() is taken to prevent the race with refrigerator() which may
    + * task_lock() is needed to prevent the race with refrigerator() which may
    * occur if the freezing of tasks fails. Namely, without the lock, if the
    * freezing of tasks failed, thaw_tasks() might have run before a task in
    * refrigerator() could call frozen_process(), in which case the task would be
    * frozen and no one would thaw it.
    */
    -static inline int thaw_process(struct task_struct *p)
    +static inline int __thaw_process(struct task_struct *p)
    {
    - task_lock(p);
    if (frozen(p)) {
    p->flags &= ~PF_FROZEN;
    + return 1;
    + }
    + clear_freeze_flag(p);
    + return 0;
    +}
    +
    +static inline int thaw_process(struct task_struct *p)
    +{
    + task_lock(p);
    + if (__thaw_process(p) == 1) {
    task_unlock(p);
    wake_up_process(p);
    return 1;
    }
    - clear_freeze_flag(p);
    task_unlock(p);
    return 0;
    }

    extern void refrigerator(void);

    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  4. [PATCH 2/4] Container Freezer: Make refrigerator always available

    From: Cedric Le Goater
    Subject: [PATCH 2/4] Container Freezer: Make refrigerator always available

    Now that the TIF_FREEZE flag is available in all architectures,
    extract the refrigerator() and freeze_task() from kernel/power/process.c
    and make it available to all.

    The refrigerator() can now be used in a control group subsystem
    implementing a control group freezer.

    Signed-off-by: Cedric Le Goater
    Signed-off-by: Matt Helsley
    Tested-by: Matt Helsley
    ---
    include/linux/freezer.h | 24 +++++----
    kernel/Makefile | 2
    kernel/freezer.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++
    kernel/power/process.c | 116 ---------------------------------------------
    4 files changed, 136 insertions(+), 128 deletions(-)

    Index: linux-2.6.26-rc5-mm2/include/linux/freezer.h
    ================================================== =================
    --- linux-2.6.26-rc5-mm2.orig/include/linux/freezer.h
    +++ linux-2.6.26-rc5-mm2/include/linux/freezer.h
    @@ -4,11 +4,10 @@
    #define FREEZER_H_INCLUDED

    #include
    #include

    -#ifdef CONFIG_PM_SLEEP
    /*
    * Check if a process has been frozen
    */
    static inline int frozen(struct task_struct *p)
    {
    @@ -37,10 +36,15 @@ static inline void set_freeze_flag(struc
    static inline void clear_freeze_flag(struct task_struct *p)
    {
    clear_tsk_thread_flag(p, TIF_FREEZE);
    }

    +static inline bool should_send_signal(struct task_struct *p)
    +{
    + return !(p->flags & PF_FREEZER_NOSIG);
    +}
    +
    /*
    * Wake up a frozen process
    *
    * task_lock() is taken to prevent the race with refrigerator() which may
    * occur if the freezing of tasks fails. Namely, without the lock, if the
    @@ -61,22 +65,28 @@ static inline int thaw_process(struct ta
    task_unlock(p);
    return 0;
    }

    extern void refrigerator(void);
    -extern int freeze_processes(void);
    -extern void thaw_processes(void);

    static inline int try_to_freeze(void)
    {
    if (freezing(current)) {
    refrigerator();
    return 1;
    } else
    return 0;
    }

    +extern bool freeze_task(struct task_struct *p, bool sig_only);
    +extern void cancel_freezing(struct task_struct *p);
    +
    +#ifdef CONFIG_PM_SLEEP
    +
    +extern int freeze_processes(void);
    +extern void thaw_processes(void);
    +
    /*
    * The PF_FREEZER_SKIP flag should be set by a vfork parent right before it
    * calls wait_for_completion(&vfork) and reset right after it returns from this
    * function. Next, the parent should call try_to_freeze() to freeze itself
    * appropriately in case the child has exited before the freezing of tasks is
    @@ -165,22 +175,14 @@ static inline void set_freezable_with_si
    __retval); \
    } while (try_to_freeze()); \
    __retval; \
    })
    #else /* !CONFIG_PM_SLEEP */
    -static inline int frozen(struct task_struct *p) { return 0; }
    -static inline int freezing(struct task_struct *p) { return 0; }
    -static inline void set_freeze_flag(struct task_struct *p) {}
    -static inline void clear_freeze_flag(struct task_struct *p) {}
    -static inline int thaw_process(struct task_struct *p) { return 1; }

    -static inline void refrigerator(void) {}
    static inline int freeze_processes(void) { BUG(); return 0; }
    static inline void thaw_processes(void) {}

    -static inline int try_to_freeze(void) { return 0; }
    -
    static inline void freezer_do_not_count(void) {}
    static inline void freezer_count(void) {}
    static inline int freezer_should_skip(struct task_struct *p) { return 0; }
    static inline void set_freezable(void) {}
    static inline void set_freezable_with_signal(void) {}
    Index: linux-2.6.26-rc5-mm2/kernel/Makefile
    ================================================== =================
    --- linux-2.6.26-rc5-mm2.orig/kernel/Makefile
    +++ linux-2.6.26-rc5-mm2/kernel/Makefile
    @@ -3,11 +3,11 @@
    #

    obj-y = sched.o fork.o exec_domain.o panic.o printk.o \
    exit.o itimer.o time.o softirq.o resource.o \
    sysctl.o capability.o ptrace.o timer.o user.o \
    - signal.o sys.o kmod.o workqueue.o pid.o \
    + signal.o sys.o kmod.o workqueue.o pid.o freezer.o \
    rcupdate.o extable.o params.o posix-timers.o \
    kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
    hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
    notifier.o ksysfs.o pm_qos_params.o sched_clock.o

    Index: linux-2.6.26-rc5-mm2/kernel/freezer.c
    ================================================== =================
    --- /dev/null
    +++ linux-2.6.26-rc5-mm2/kernel/freezer.c
    @@ -0,0 +1,122 @@
    +/*
    + * kernel/freezer.c - Function to freeze a process
    + *
    + * Originally from kernel/power/process.c
    + */
    +
    +#include
    +#include
    +#include
    +#include
    +#include
    +
    +/*
    + * freezing is complete, mark current process as frozen
    + */
    +static inline void frozen_process(void)
    +{
    + if (!unlikely(current->flags & PF_NOFREEZE)) {
    + current->flags |= PF_FROZEN;
    + wmb();
    + }
    + clear_freeze_flag(current);
    +}
    +
    +/* Refrigerator is place where frozen processes are stored :-). */
    +void refrigerator(void)
    +{
    + /* Hmm, should we be allowed to suspend when there are realtime
    + processes around? */
    + long save;
    +
    + task_lock(current);
    + if (freezing(current)) {
    + frozen_process();
    + task_unlock(current);
    + } else {
    + task_unlock(current);
    + return;
    + }
    + save = current->state;
    + pr_debug("%s entered refrigerator\n", current->comm);
    +
    + spin_lock_irq(&current->sighand->siglock);
    + recalc_sigpending(); /* We sent fake signal, clean it up */
    + spin_unlock_irq(&current->sighand->siglock);
    +
    + for (; {
    + set_current_state(TASK_UNINTERRUPTIBLE);
    + if (!frozen(current))
    + break;
    + schedule();
    + }
    + pr_debug("%s left refrigerator\n", current->comm);
    + __set_current_state(save);
    +}
    +EXPORT_SYMBOL(refrigerator);
    +
    +static void fake_signal_wake_up(struct task_struct *p)
    +{
    + unsigned long flags;
    +
    + spin_lock_irqsave(&p->sighand->siglock, flags);
    + signal_wake_up(p, 0);
    + spin_unlock_irqrestore(&p->sighand->siglock, flags);
    +}
    +
    +/**
    + * freeze_task - send a freeze request to given task
    + * @p: task to send the request to
    + * @sig_only: if set, the request will only be sent if the task has the
    + * PF_FREEZER_NOSIG flag unset
    + * Return value: 'false', if @sig_only is set and the task has
    + * PF_FREEZER_NOSIG set or the task is frozen, 'true', otherwise
    + *
    + * The freeze request is sent by setting the tasks's TIF_FREEZE flag and
    + * either sending a fake signal to it or waking it up, depending on whether
    + * or not it has PF_FREEZER_NOSIG set. If @sig_only is set and the task
    + * has PF_FREEZER_NOSIG set (ie. it is a typical kernel thread), its
    + * TIF_FREEZE flag will not be set.
    + */
    +bool freeze_task(struct task_struct *p, bool sig_only)
    +{
    + /*
    + * We first check if the task is freezing and next if it has already
    + * been frozen to avoid the race with frozen_process() which first marks
    + * the task as frozen and next clears its TIF_FREEZE.
    + */
    + if (!freezing(p)) {
    + rmb();
    + if (frozen(p))
    + return false;
    +
    + if (!sig_only || should_send_signal(p))
    + set_freeze_flag(p);
    + else
    + return false;
    + }
    +
    + if (should_send_signal(p)) {
    + if (!signal_pending(p))
    + fake_signal_wake_up(p);
    + } else if (sig_only) {
    + return false;
    + } else {
    + wake_up_state(p, TASK_INTERRUPTIBLE);
    + }
    +
    + return true;
    +}
    +
    +void cancel_freezing(struct task_struct *p)
    +{
    + unsigned long flags;
    +
    + if (freezing(p)) {
    + pr_debug(" clean up: %s\n", p->comm);
    + clear_freeze_flag(p);
    + spin_lock_irqsave(&p->sighand->siglock, flags);
    + recalc_sigpending_and_wake(p);
    + spin_unlock_irqrestore(&p->sighand->siglock, flags);
    + }
    +}
    Index: linux-2.6.26-rc5-mm2/kernel/power/process.c
    ================================================== =================
    --- linux-2.6.26-rc5-mm2.orig/kernel/power/process.c
    +++ linux-2.6.26-rc5-mm2/kernel/power/process.c
    @@ -26,125 +26,10 @@ static inline int freezeable(struct task
    (p->exit_state != 0))
    return 0;
    return 1;
    }

    -/*
    - * freezing is complete, mark current process as frozen
    - */
    -static inline void frozen_process(void)
    -{
    - if (!unlikely(current->flags & PF_NOFREEZE)) {
    - current->flags |= PF_FROZEN;
    - wmb();
    - }
    - clear_freeze_flag(current);
    -}
    -
    -/* Refrigerator is place where frozen processes are stored :-). */
    -void refrigerator(void)
    -{
    - /* Hmm, should we be allowed to suspend when there are realtime
    - processes around? */
    - long save;
    -
    - task_lock(current);
    - if (freezing(current)) {
    - frozen_process();
    - task_unlock(current);
    - } else {
    - task_unlock(current);
    - return;
    - }
    - save = current->state;
    - pr_debug("%s entered refrigerator\n", current->comm);
    -
    - spin_lock_irq(&current->sighand->siglock);
    - recalc_sigpending(); /* We sent fake signal, clean it up */
    - spin_unlock_irq(&current->sighand->siglock);
    -
    - for (; {
    - set_current_state(TASK_UNINTERRUPTIBLE);
    - if (!frozen(current))
    - break;
    - schedule();
    - }
    - pr_debug("%s left refrigerator\n", current->comm);
    - __set_current_state(save);
    -}
    -
    -static void fake_signal_wake_up(struct task_struct *p)
    -{
    - unsigned long flags;
    -
    - spin_lock_irqsave(&p->sighand->siglock, flags);
    - signal_wake_up(p, 0);
    - spin_unlock_irqrestore(&p->sighand->siglock, flags);
    -}
    -
    -static inline bool should_send_signal(struct task_struct *p)
    -{
    - return !(p->flags & PF_FREEZER_NOSIG);
    -}
    -
    -/**
    - * freeze_task - send a freeze request to given task
    - * @p: task to send the request to
    - * @sig_only: if set, the request will only be sent if the task has the
    - * PF_FREEZER_NOSIG flag unset
    - * Return value: 'false', if @sig_only is set and the task has
    - * PF_FREEZER_NOSIG set or the task is frozen, 'true', otherwise
    - *
    - * The freeze request is sent by setting the tasks's TIF_FREEZE flag and
    - * either sending a fake signal to it or waking it up, depending on whether
    - * or not it has PF_FREEZER_NOSIG set. If @sig_only is set and the task
    - * has PF_FREEZER_NOSIG set (ie. it is a typical kernel thread), its
    - * TIF_FREEZE flag will not be set.
    - */
    -static bool freeze_task(struct task_struct *p, bool sig_only)
    -{
    - /*
    - * We first check if the task is freezing and next if it has already
    - * been frozen to avoid the race with frozen_process() which first marks
    - * the task as frozen and next clears its TIF_FREEZE.
    - */
    - if (!freezing(p)) {
    - rmb();
    - if (frozen(p))
    - return false;
    -
    - if (!sig_only || should_send_signal(p))
    - set_freeze_flag(p);
    - else
    - return false;
    - }
    -
    - if (should_send_signal(p)) {
    - if (!signal_pending(p))
    - fake_signal_wake_up(p);
    - } else if (sig_only) {
    - return false;
    - } else {
    - wake_up_state(p, TASK_INTERRUPTIBLE);
    - }
    -
    - return true;
    -}
    -
    -static void cancel_freezing(struct task_struct *p)
    -{
    - unsigned long flags;
    -
    - if (freezing(p)) {
    - pr_debug(" clean up: %s\n", p->comm);
    - clear_freeze_flag(p);
    - spin_lock_irqsave(&p->sighand->siglock, flags);
    - recalc_sigpending_and_wake(p);
    - spin_unlock_irqrestore(&p->sighand->siglock, flags);
    - }
    -}
    -
    static int try_to_freeze_tasks(bool sig_only)
    {
    struct task_struct *g, *p;
    unsigned long end_time;
    unsigned int todo;
    @@ -262,6 +147,5 @@ void thaw_processes(void)
    thaw_tasks(false);
    schedule();
    printk("done.\n");
    }

    -EXPORT_SYMBOL(refrigerator);

    --
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  5. Re: [PATCH 0/4] Container Freezer: Reuse Suspend Freezer


    On Mon, 2008-07-07 at 15:58 -0700, Matt Helsley wrote:
    > This patchset reuses the container infrastructure and the swsusp freezer to
    > freeze a group of tasks.
    >
    > The freezer subsystem in the container filesystem defines a file named
    > freezer.state. Writing "FROZEN" to the state file will freeze all tasks in the
    > cgroup. Subsequently writing "RUNNING" will unfreeze the tasks in the cgroup.
    > Reading will return the current state.
    >
    > * Examples of usage :
    >
    > # mkdir /containers/freezer
    > # mount -t cgroup -ofreezer,signal freezer /containers
    > # mkdir /containers/0
    > # echo $some_pid > /containers/0/tasks
    >
    > to get status of the freezer subsystem :
    >
    > # cat /containers/0/freezer.state
    > RUNNING
    >
    > to freeze all tasks in the container :
    >
    > # echo FROZEN > /containers/0/freezer.state
    > # cat /containers/0/freezer.state
    > FREEZING
    > # cat /containers/0/freezer.state
    > FROZEN
    >
    > to unfreeze all tasks in the container :
    >
    > # echo RUNNING > /containers/0/freezer.state
    > # cat /containers/0/freezer.state
    > RUNNING
    >
    > to kill all tasks in the container :
    >
    > # echo 9 > /containers/0/signal.kill
    >
    > I've reworked Cedric's patches to use task_lock() to protect access to the
    > task's cgroup.
    >
    > Paul, Pavel asked me to send these to Rafael next. They are patches to make
    > the freezer useful for checkpoint/restart using cgroups so it would be nice
    > to get an explicit [N]Ack from you first.
    >
    > Rafael, if Paul agrees, please consider applying these patches.
    >
    > Changes since v3:
    > v4 (Almost all of these changes are confined to patch 3):
    > Reworked the series to use task_lock() instead of RCU.
    > Reworked the series to use write_string() and read_seq_string()
    > cgroup methods.


    FYI - This means these patches need Paul's patches introducing
    write_string(). I can certainly restore the old code for .read
    and .write, but I was anticipating write_string() making it into various
    trees first. If that's not necessarily the case please let me know.

    Cheers,
    -Matt

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  6. Re: [PATCH 0/4] Container Freezer: Reuse Suspend Freezer

    Hi, could I make brief questions ?

    On Mon, 07 Jul 2008 15:58:23 -0700
    Matt Helsley wrote:
    > to get status of the freezer subsystem :
    >
    > # cat /containers/0/freezer.state
    > RUNNING
    >
    > to freeze all tasks in the container :
    >
    > # echo FROZEN > /containers/0/freezer.state
    > # cat /containers/0/freezer.state
    > FREEZING
    > # cat /containers/0/freezer.state
    > FROZEN
    >

    I'm just curious.

    1. When we see FREEZING and have to retry ?
    While there are some threads which wait for some event ?

    2. What happens when FROZEN threads are moved to other group ?
    Can we move them ?
    Can we wake them up (if it can be moved) ?
    What operations are allowed to frozen threads ?

    Thanks,
    -Kame

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  7. Re: [PATCH 0/4] Container Freezer: Reuse Suspend Freezer


    Cedric was accidentally not Cc'd on the introduction (PATCH 0). Adding
    him.

    On Tue, 2008-07-08 at 12:31 +0900, KAMEZAWA Hiroyuki wrote:
    > Hi, could I make brief questions ?
    >
    > On Mon, 07 Jul 2008 15:58:23 -0700
    > Matt Helsley wrote:
    > > to get status of the freezer subsystem :
    > >
    > > # cat /containers/0/freezer.state
    > > RUNNING
    > >
    > > to freeze all tasks in the container :
    > >
    > > # echo FROZEN > /containers/0/freezer.state
    > > # cat /containers/0/freezer.state
    > > FREEZING
    > > # cat /containers/0/freezer.state
    > > FROZEN
    > >

    > I'm just curious.
    >
    > 1. When we see FREEZING and have to retry ?


    One example is when some processes are in the a specific portion of
    vfork() you might see FREEZING and have to retry.

    > While there are some threads which wait for some event ?


    Depending on which kind of "wait" they are performing, yes. If it's
    uninterruptible sleep and the PF_FROZEN flag is not set then you might
    see FREEZING.

    > 2. What happens when FROZEN threads are moved to other group ?
    > Can we move them ?


    If the destination cgroup is not FROZEN, yes.

    If the destination cgroup is FREEZING this works as expected.

    If the destination cgroup is RUNNING you'd have a problem unfreezing the
    task. This happends because the cgroup has a state inconsistent with the
    task's state. To unfreeze the task you'd have to try to freeze and then
    unfreeze the destination cgroup.

    There are several ways I could change this.

    One is to try and disallow users from moving frozen tasks. That doesn't
    seem like a good approach since it would require a new cgroups interface
    "can_detach()".

    However we can prevent attach so I could add checks that look at the
    attaching tasks's state and refuse the attach when the task's state
    (unfrozen, frozen) is inconsistent with the cgroup state (RUNNING,
    FREEZING, FROZEN). I'll send a fifth patch on top of this series showing
    this idea.

    Rather than refuse to allow attach we could change the destination
    cgroup's state during attach so that the two states are consistent.
    However, this introduces more ugly cases for userspace to be aware of.

    > Can we wake them up (if it can be moved) ?


    You can't wake them until you've unfrozen them.

    > What operations are allowed to frozen threads ?


    Any operation that doesn't require the threads to run.

    Cheers,
    -Matt Helsley

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  8. Re: [PATCH 0/4] Container Freezer: Reuse Suspend Freezer

    On Tue, Jul 8, 2008 at 12:39 PM, Matt Helsley wrote:
    >
    > One is to try and disallow users from moving frozen tasks. That doesn't
    > seem like a good approach since it would require a new cgroups interface
    > "can_detach()".


    Detaching from the old cgroup happens at the same time as attaching to
    the new cgroup, so can_attach() would work here.

    Paul
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  9. Re: [PATCH 0/4] Container Freezer: Reuse Suspend Freezer

    On Tue, Jul 8, 2008 at 1:06 PM, Paul Menage wrote:
    > On Tue, Jul 8, 2008 at 12:39 PM, Matt Helsley wrote:
    >>
    >> One is to try and disallow users from moving frozen tasks. That doesn't
    >> seem like a good approach since it would require a new cgroups interface
    >> "can_detach()".

    >
    > Detaching from the old cgroup happens at the same time as attaching to
    > the new cgroup, so can_attach() would work here.


    And the whole can_attach()/attach() protocol needs reworking anyway,
    see my email (hopefully) later today.

    Paul
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  10. Re: [PATCH 2/4] Container Freezer: Make refrigerator always available

    Quoting Matt Helsley (matthltc@us.ibm.com):
    > From: Cedric Le Goater
    > Subject: [PATCH 2/4] Container Freezer: Make refrigerator always available
    >
    > Now that the TIF_FREEZE flag is available in all architectures,
    > extract the refrigerator() and freeze_task() from kernel/power/process.c
    > and make it available to all.
    >
    > The refrigerator() can now be used in a control group subsystem
    > implementing a control group freezer.
    >
    > Signed-off-by: Cedric Le Goater
    > Signed-off-by: Matt Helsley
    > Tested-by: Matt Helsley


    Hi Matt,

    I'm pretty sure that a long long time ago this patchset had my
    Acked-by on it.

    It sounds like for patch 3 we may have a few issues to be addressed when
    Paul sends out an email about the cgroup attach process. But in the
    meantime, Rafael would you mind putting at least the first two patches
    into your tree?

    thanks,
    -serge

    > ---
    > include/linux/freezer.h | 24 +++++----
    > kernel/Makefile | 2
    > kernel/freezer.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++
    > kernel/power/process.c | 116 ---------------------------------------------
    > 4 files changed, 136 insertions(+), 128 deletions(-)
    >
    > Index: linux-2.6.26-rc5-mm2/include/linux/freezer.h
    > ================================================== =================
    > --- linux-2.6.26-rc5-mm2.orig/include/linux/freezer.h
    > +++ linux-2.6.26-rc5-mm2/include/linux/freezer.h
    > @@ -4,11 +4,10 @@
    > #define FREEZER_H_INCLUDED
    >
    > #include
    > #include
    >
    > -#ifdef CONFIG_PM_SLEEP
    > /*
    > * Check if a process has been frozen
    > */
    > static inline int frozen(struct task_struct *p)
    > {
    > @@ -37,10 +36,15 @@ static inline void set_freeze_flag(struc
    > static inline void clear_freeze_flag(struct task_struct *p)
    > {
    > clear_tsk_thread_flag(p, TIF_FREEZE);
    > }
    >
    > +static inline bool should_send_signal(struct task_struct *p)
    > +{
    > + return !(p->flags & PF_FREEZER_NOSIG);
    > +}
    > +
    > /*
    > * Wake up a frozen process
    > *
    > * task_lock() is taken to prevent the race with refrigerator() which may
    > * occur if the freezing of tasks fails. Namely, without the lock, if the
    > @@ -61,22 +65,28 @@ static inline int thaw_process(struct ta
    > task_unlock(p);
    > return 0;
    > }
    >
    > extern void refrigerator(void);
    > -extern int freeze_processes(void);
    > -extern void thaw_processes(void);
    >
    > static inline int try_to_freeze(void)
    > {
    > if (freezing(current)) {
    > refrigerator();
    > return 1;
    > } else
    > return 0;
    > }
    >
    > +extern bool freeze_task(struct task_struct *p, bool sig_only);
    > +extern void cancel_freezing(struct task_struct *p);
    > +
    > +#ifdef CONFIG_PM_SLEEP
    > +
    > +extern int freeze_processes(void);
    > +extern void thaw_processes(void);
    > +
    > /*
    > * The PF_FREEZER_SKIP flag should be set by a vfork parent right before it
    > * calls wait_for_completion(&vfork) and reset right after it returns from this
    > * function. Next, the parent should call try_to_freeze() to freeze itself
    > * appropriately in case the child has exited before the freezing of tasks is
    > @@ -165,22 +175,14 @@ static inline void set_freezable_with_si
    > __retval); \
    > } while (try_to_freeze()); \
    > __retval; \
    > })
    > #else /* !CONFIG_PM_SLEEP */
    > -static inline int frozen(struct task_struct *p) { return 0; }
    > -static inline int freezing(struct task_struct *p) { return 0; }
    > -static inline void set_freeze_flag(struct task_struct *p) {}
    > -static inline void clear_freeze_flag(struct task_struct *p) {}
    > -static inline int thaw_process(struct task_struct *p) { return 1; }
    >
    > -static inline void refrigerator(void) {}
    > static inline int freeze_processes(void) { BUG(); return 0; }
    > static inline void thaw_processes(void) {}
    >
    > -static inline int try_to_freeze(void) { return 0; }
    > -
    > static inline void freezer_do_not_count(void) {}
    > static inline void freezer_count(void) {}
    > static inline int freezer_should_skip(struct task_struct *p) { return 0; }
    > static inline void set_freezable(void) {}
    > static inline void set_freezable_with_signal(void) {}
    > Index: linux-2.6.26-rc5-mm2/kernel/Makefile
    > ================================================== =================
    > --- linux-2.6.26-rc5-mm2.orig/kernel/Makefile
    > +++ linux-2.6.26-rc5-mm2/kernel/Makefile
    > @@ -3,11 +3,11 @@
    > #
    >
    > obj-y = sched.o fork.o exec_domain.o panic.o printk.o \
    > exit.o itimer.o time.o softirq.o resource.o \
    > sysctl.o capability.o ptrace.o timer.o user.o \
    > - signal.o sys.o kmod.o workqueue.o pid.o \
    > + signal.o sys.o kmod.o workqueue.o pid.o freezer.o \
    > rcupdate.o extable.o params.o posix-timers.o \
    > kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
    > hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
    > notifier.o ksysfs.o pm_qos_params.o sched_clock.o
    >
    > Index: linux-2.6.26-rc5-mm2/kernel/freezer.c
    > ================================================== =================
    > --- /dev/null
    > +++ linux-2.6.26-rc5-mm2/kernel/freezer.c
    > @@ -0,0 +1,122 @@
    > +/*
    > + * kernel/freezer.c - Function to freeze a process
    > + *
    > + * Originally from kernel/power/process.c
    > + */
    > +
    > +#include
    > +#include
    > +#include
    > +#include
    > +#include
    > +
    > +/*
    > + * freezing is complete, mark current process as frozen
    > + */
    > +static inline void frozen_process(void)
    > +{
    > + if (!unlikely(current->flags & PF_NOFREEZE)) {
    > + current->flags |= PF_FROZEN;
    > + wmb();
    > + }
    > + clear_freeze_flag(current);
    > +}
    > +
    > +/* Refrigerator is place where frozen processes are stored :-). */
    > +void refrigerator(void)
    > +{
    > + /* Hmm, should we be allowed to suspend when there are realtime
    > + processes around? */
    > + long save;
    > +
    > + task_lock(current);
    > + if (freezing(current)) {
    > + frozen_process();
    > + task_unlock(current);
    > + } else {
    > + task_unlock(current);
    > + return;
    > + }
    > + save = current->state;
    > + pr_debug("%s entered refrigerator\n", current->comm);
    > +
    > + spin_lock_irq(&current->sighand->siglock);
    > + recalc_sigpending(); /* We sent fake signal, clean it up */
    > + spin_unlock_irq(&current->sighand->siglock);
    > +
    > + for (; {
    > + set_current_state(TASK_UNINTERRUPTIBLE);
    > + if (!frozen(current))
    > + break;
    > + schedule();
    > + }
    > + pr_debug("%s left refrigerator\n", current->comm);
    > + __set_current_state(save);
    > +}
    > +EXPORT_SYMBOL(refrigerator);
    > +
    > +static void fake_signal_wake_up(struct task_struct *p)
    > +{
    > + unsigned long flags;
    > +
    > + spin_lock_irqsave(&p->sighand->siglock, flags);
    > + signal_wake_up(p, 0);
    > + spin_unlock_irqrestore(&p->sighand->siglock, flags);
    > +}
    > +
    > +/**
    > + * freeze_task - send a freeze request to given task
    > + * @p: task to send the request to
    > + * @sig_only: if set, the request will only be sent if the task has the
    > + * PF_FREEZER_NOSIG flag unset
    > + * Return value: 'false', if @sig_only is set and the task has
    > + * PF_FREEZER_NOSIG set or the task is frozen, 'true', otherwise
    > + *
    > + * The freeze request is sent by setting the tasks's TIF_FREEZE flag and
    > + * either sending a fake signal to it or waking it up, depending on whether
    > + * or not it has PF_FREEZER_NOSIG set. If @sig_only is set and the task
    > + * has PF_FREEZER_NOSIG set (ie. it is a typical kernel thread), its
    > + * TIF_FREEZE flag will not be set.
    > + */
    > +bool freeze_task(struct task_struct *p, bool sig_only)
    > +{
    > + /*
    > + * We first check if the task is freezing and next if it has already
    > + * been frozen to avoid the race with frozen_process() which first marks
    > + * the task as frozen and next clears its TIF_FREEZE.
    > + */
    > + if (!freezing(p)) {
    > + rmb();
    > + if (frozen(p))
    > + return false;
    > +
    > + if (!sig_only || should_send_signal(p))
    > + set_freeze_flag(p);
    > + else
    > + return false;
    > + }
    > +
    > + if (should_send_signal(p)) {
    > + if (!signal_pending(p))
    > + fake_signal_wake_up(p);
    > + } else if (sig_only) {
    > + return false;
    > + } else {
    > + wake_up_state(p, TASK_INTERRUPTIBLE);
    > + }
    > +
    > + return true;
    > +}
    > +
    > +void cancel_freezing(struct task_struct *p)
    > +{
    > + unsigned long flags;
    > +
    > + if (freezing(p)) {
    > + pr_debug(" clean up: %s\n", p->comm);
    > + clear_freeze_flag(p);
    > + spin_lock_irqsave(&p->sighand->siglock, flags);
    > + recalc_sigpending_and_wake(p);
    > + spin_unlock_irqrestore(&p->sighand->siglock, flags);
    > + }
    > +}
    > Index: linux-2.6.26-rc5-mm2/kernel/power/process.c
    > ================================================== =================
    > --- linux-2.6.26-rc5-mm2.orig/kernel/power/process.c
    > +++ linux-2.6.26-rc5-mm2/kernel/power/process.c
    > @@ -26,125 +26,10 @@ static inline int freezeable(struct task
    > (p->exit_state != 0))
    > return 0;
    > return 1;
    > }
    >
    > -/*
    > - * freezing is complete, mark current process as frozen
    > - */
    > -static inline void frozen_process(void)
    > -{
    > - if (!unlikely(current->flags & PF_NOFREEZE)) {
    > - current->flags |= PF_FROZEN;
    > - wmb();
    > - }
    > - clear_freeze_flag(current);
    > -}
    > -
    > -/* Refrigerator is place where frozen processes are stored :-). */
    > -void refrigerator(void)
    > -{
    > - /* Hmm, should we be allowed to suspend when there are realtime
    > - processes around? */
    > - long save;
    > -
    > - task_lock(current);
    > - if (freezing(current)) {
    > - frozen_process();
    > - task_unlock(current);
    > - } else {
    > - task_unlock(current);
    > - return;
    > - }
    > - save = current->state;
    > - pr_debug("%s entered refrigerator\n", current->comm);
    > -
    > - spin_lock_irq(&current->sighand->siglock);
    > - recalc_sigpending(); /* We sent fake signal, clean it up */
    > - spin_unlock_irq(&current->sighand->siglock);
    > -
    > - for (; {
    > - set_current_state(TASK_UNINTERRUPTIBLE);
    > - if (!frozen(current))
    > - break;
    > - schedule();
    > - }
    > - pr_debug("%s left refrigerator\n", current->comm);
    > - __set_current_state(save);
    > -}
    > -
    > -static void fake_signal_wake_up(struct task_struct *p)
    > -{
    > - unsigned long flags;
    > -
    > - spin_lock_irqsave(&p->sighand->siglock, flags);
    > - signal_wake_up(p, 0);
    > - spin_unlock_irqrestore(&p->sighand->siglock, flags);
    > -}
    > -
    > -static inline bool should_send_signal(struct task_struct *p)
    > -{
    > - return !(p->flags & PF_FREEZER_NOSIG);
    > -}
    > -
    > -/**
    > - * freeze_task - send a freeze request to given task
    > - * @p: task to send the request to
    > - * @sig_only: if set, the request will only be sent if the task has the
    > - * PF_FREEZER_NOSIG flag unset
    > - * Return value: 'false', if @sig_only is set and the task has
    > - * PF_FREEZER_NOSIG set or the task is frozen, 'true', otherwise
    > - *
    > - * The freeze request is sent by setting the tasks's TIF_FREEZE flag and
    > - * either sending a fake signal to it or waking it up, depending on whether
    > - * or not it has PF_FREEZER_NOSIG set. If @sig_only is set and the task
    > - * has PF_FREEZER_NOSIG set (ie. it is a typical kernel thread), its
    > - * TIF_FREEZE flag will not be set.
    > - */
    > -static bool freeze_task(struct task_struct *p, bool sig_only)
    > -{
    > - /*
    > - * We first check if the task is freezing and next if it has already
    > - * been frozen to avoid the race with frozen_process() which first marks
    > - * the task as frozen and next clears its TIF_FREEZE.
    > - */
    > - if (!freezing(p)) {
    > - rmb();
    > - if (frozen(p))
    > - return false;
    > -
    > - if (!sig_only || should_send_signal(p))
    > - set_freeze_flag(p);
    > - else
    > - return false;
    > - }
    > -
    > - if (should_send_signal(p)) {
    > - if (!signal_pending(p))
    > - fake_signal_wake_up(p);
    > - } else if (sig_only) {
    > - return false;
    > - } else {
    > - wake_up_state(p, TASK_INTERRUPTIBLE);
    > - }
    > -
    > - return true;
    > -}
    > -
    > -static void cancel_freezing(struct task_struct *p)
    > -{
    > - unsigned long flags;
    > -
    > - if (freezing(p)) {
    > - pr_debug(" clean up: %s\n", p->comm);
    > - clear_freeze_flag(p);
    > - spin_lock_irqsave(&p->sighand->siglock, flags);
    > - recalc_sigpending_and_wake(p);
    > - spin_unlock_irqrestore(&p->sighand->siglock, flags);
    > - }
    > -}
    > -
    > static int try_to_freeze_tasks(bool sig_only)
    > {
    > struct task_struct *g, *p;
    > unsigned long end_time;
    > unsigned int todo;
    > @@ -262,6 +147,5 @@ void thaw_processes(void)
    > thaw_tasks(false);
    > schedule();
    > printk("done.\n");
    > }
    >
    > -EXPORT_SYMBOL(refrigerator);
    >
    > --
    > _______________________________________________
    > Containers mailing list
    > Containers@lists.linux-foundation.org
    > https://lists.linux-foundation.org/m...nfo/containers

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  11. Re: [PATCH 0/4] Container Freezer: Reuse Suspend Freezer


    On Tue, 2008-07-08 at 13:07 -0700, Paul Menage wrote:
    > On Tue, Jul 8, 2008 at 1:06 PM, Paul Menage wrote:
    > > On Tue, Jul 8, 2008 at 12:39 PM, Matt Helsley wrote:
    > >>
    > >> One is to try and disallow users from moving frozen tasks. That doesn't
    > >> seem like a good approach since it would require a new cgroups interface
    > >> "can_detach()".

    > >
    > > Detaching from the old cgroup happens at the same time as attaching to
    > > the new cgroup, so can_attach() would work here.


    Update: I've made a patch implementing this. However it might be better
    to just modify attach() to thaw the moving task rather than disallow
    moving the frozen task. Serge, Cedric, Kame-san, do you have any
    thoughts on which is more useful and/or intuitive?

    > And the whole can_attach()/attach() protocol needs reworking anyway,
    > see my email (hopefully) later today.
    >
    > Paul


    Interesting. I look forward to seeing this.

    Cheers,
    -Matt

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  12. Re: [PATCH 0/4] Container Freezer: Reuse Suspend Freezer

    On Wed, 09 Jul 2008 14:58:43 -0700
    Matt Helsley wrote:

    >
    > On Tue, 2008-07-08 at 13:07 -0700, Paul Menage wrote:
    > > On Tue, Jul 8, 2008 at 1:06 PM, Paul Menage wrote:
    > > > On Tue, Jul 8, 2008 at 12:39 PM, Matt Helsley wrote:
    > > >>
    > > >> One is to try and disallow users from moving frozen tasks. That doesn't
    > > >> seem like a good approach since it would require a new cgroups interface
    > > >> "can_detach()".
    > > >
    > > > Detaching from the old cgroup happens at the same time as attaching to
    > > > the new cgroup, so can_attach() would work here.

    >
    > Update: I've made a patch implementing this. However it might be better
    > to just modify attach() to thaw the moving task rather than disallow
    > moving the frozen task. Serge, Cedric, Kame-san, do you have any
    > thoughts on which is more useful and/or intuitive?
    >


    Thank you for explanation in previous mail.

    Hmm, just thawing seems atractive but it will confuse people (I think).

    I think some kind of process-group is freezed by this freezer and "moving
    freezed task" is wrong(unexpected) operation in general. And there will
    be no demand to do that from users.
    I think just taking "moving freezed task" as error-operation and returning
    -EBUSY is better.

    Thanks,
    -Kame

    > > And the whole can_attach()/attach() protocol needs reworking anyway,
    > > see my email (hopefully) later today.
    > >
    > > Paul

    >
    > Interesting. I look forward to seeing this.
    >
    > Cheers,
    > -Matt
    >
    >


    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  13. [RFC][PATCH] Container Freezer: Don't Let Frozen Stuff Change


    On Thu, 2008-07-10 at 09:42 +0900, KAMEZAWA Hiroyuki wrote:
    > On Wed, 09 Jul 2008 14:58:43 -0700
    > Matt Helsley wrote:
    >
    > >
    > > On Tue, 2008-07-08 at 13:07 -0700, Paul Menage wrote:
    > > > On Tue, Jul 8, 2008 at 1:06 PM, Paul Menage wrote:
    > > > > On Tue, Jul 8, 2008 at 12:39 PM, Matt Helsley wrote:
    > > > >>
    > > > >> One is to try and disallow users from moving frozen tasks. That doesn't
    > > > >> seem like a good approach since it would require a new cgroups interface
    > > > >> "can_detach()".
    > > > >
    > > > > Detaching from the old cgroup happens at the same time as attaching to
    > > > > the new cgroup, so can_attach() would work here.

    > >
    > > Update: I've made a patch implementing this. However it might be better
    > > to just modify attach() to thaw the moving task rather than disallow
    > > moving the frozen task. Serge, Cedric, Kame-san, do you have any
    > > thoughts on which is more useful and/or intuitive?
    > >

    >
    > Thank you for explanation in previous mail.
    >
    > Hmm, just thawing seems atractive but it will confuse people (I think).
    >
    > I think some kind of process-group is freezed by this freezer and "moving
    > freezed task" is wrong(unexpected) operation in general. And there will
    > be no demand to do that from users.
    > I think just taking "moving freezed task" as error-operation and returning
    > -EBUSY is better.


    Kame-san,

    I've been working on changes to the can_attach() code so it was pretty
    easy to try this out.

    Don't let frozen tasks or cgroups change. This means frozen tasks can't
    leave their current cgroup for another cgroup. It also means that tasks
    cannot be added to or removed from a cgroup in the FROZEN state. We
    enforce these rules by checking for frozen tasks and cgroups in the
    can_attach() function.

    Signed-off-by: Matt Helsley
    ---
    Builds, boots, passes testing against 2.6.26-rc5-mm2

    kernel/cgroup_freezer.c | 42 +++++++++++++++++++++++++-----------------
    1 file changed, 25 insertions(+), 17 deletions(-)

    Index: linux-2.6.26-rc5-mm2/kernel/cgroup_freezer.c
    ================================================== =================
    --- linux-2.6.26-rc5-mm2.orig/kernel/cgroup_freezer.c
    +++ linux-2.6.26-rc5-mm2/kernel/cgroup_freezer.c
    @@ -89,26 +89,43 @@ static void freezer_destroy(struct cgrou
    struct cgroup *cgroup)
    {
    kfree(cgroup_freezer(cgroup));
    }

    +/* Task is frozen or will freeze immediately when next it gets woken */
    +static bool is_task_frozen_enough(struct task_struct *task)
    +{
    + return (frozen(task) || (task_is_stopped_or_traced(task) && freezing(task)));
    +}

    +/*
    + * The call to cgroup_lock() in the freezer.state write method prevents
    + * a write to that file racing against an attach, and hence the
    + * can_attach() result will remain valid until the attach completes.
    + */
    static int freezer_can_attach(struct cgroup_subsys *ss,
    struct cgroup *new_cgroup,
    struct task_struct *task)
    {
    struct freezer *freezer;
    - int retval = 0;
    + int retval;
    +
    + /* Anything frozen can't move or be moved to/from */
    +
    + if (is_task_frozen_enough(task))
    + return -EBUSY;

    - /*
    - * The call to cgroup_lock() in the freezer.state write method prevents
    - * a write to that file racing against an attach, and hence the
    - * can_attach() result will remain valid until the attach completes.
    - */
    freezer = cgroup_freezer(new_cgroup);
    if (freezer->state == STATE_FROZEN)
    + return -EBUSY;
    +
    + retval = 0;
    + task_lock(task);
    + freezer = task_freezer(task);
    + if (freezer->state == STATE_FROZEN)
    retval = -EBUSY;
    + task_unlock(task);
    return retval;
    }

    static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task)
    {
    @@ -139,16 +156,11 @@ static void check_if_frozen(struct cgrou
    unsigned int nfrozen = 0, ntotal = 0;

    cgroup_iter_start(cgroup, &it);
    while ((task = cgroup_iter_next(cgroup, &it))) {
    ntotal++;
    - /*
    - * Task is frozen or will freeze immediately when next it gets
    - * woken
    - */
    - if (frozen(task) ||
    - (task_is_stopped_or_traced(task) && freezing(task)))
    + if (is_task_frozen_enough(task))
    nfrozen++;
    }

    /*
    * Transition to FROZEN when no new tasks can be added ensures
    @@ -195,15 +207,11 @@ static int try_to_freeze_cgroup(struct c
    freezer->state = STATE_FREEZING;
    cgroup_iter_start(cgroup, &it);
    while ((task = cgroup_iter_next(cgroup, &it))) {
    if (!freeze_task(task, true))
    continue;
    - if (task_is_stopped_or_traced(task) && freezing(task))
    - /*
    - * The freeze flag is set so these tasks will
    - * immediately go into the fridge upon waking.
    - */
    + if (is_task_frozen_enough(task))
    continue;
    if (!freezing(task) && !freezer_should_skip(task))
    num_cant_freeze_now++;
    }
    cgroup_iter_end(cgroup, &it);


    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  14. Re: [RFC][PATCH] Container Freezer: Don't Let Frozen Stuff Change

    Matt Helsley wrote:
    > On Thu, 2008-07-10 at 09:42 +0900, KAMEZAWA Hiroyuki wrote:
    >> On Wed, 09 Jul 2008 14:58:43 -0700
    >> Matt Helsley wrote:
    >>
    >>> On Tue, 2008-07-08 at 13:07 -0700, Paul Menage wrote:
    >>>> On Tue, Jul 8, 2008 at 1:06 PM, Paul Menage wrote:
    >>>>> On Tue, Jul 8, 2008 at 12:39 PM, Matt Helsley wrote:
    >>>>>> One is to try and disallow users from moving frozen tasks. That doesn't
    >>>>>> seem like a good approach since it would require a new cgroups interface
    >>>>>> "can_detach()".
    >>>>> Detaching from the old cgroup happens at the same time as attaching to
    >>>>> the new cgroup, so can_attach() would work here.
    >>> Update: I've made a patch implementing this. However it might be better
    >>> to just modify attach() to thaw the moving task rather than disallow
    >>> moving the frozen task. Serge, Cedric, Kame-san, do you have any
    >>> thoughts on which is more useful and/or intuitive?
    >>>

    >> Thank you for explanation in previous mail.
    >>
    >> Hmm, just thawing seems atractive but it will confuse people (I think).
    >>
    >> I think some kind of process-group is freezed by this freezer and "moving
    >> freezed task" is wrong(unexpected) operation in general. And there will
    >> be no demand to do that from users.
    >> I think just taking "moving freezed task" as error-operation and returning
    >> -EBUSY is better.

    >
    > Kame-san,
    >
    > I've been working on changes to the can_attach() code so it was pretty
    > easy to try this out.
    >
    > Don't let frozen tasks or cgroups change. This means frozen tasks can't
    > leave their current cgroup for another cgroup. It also means that tasks
    > cannot be added to or removed from a cgroup in the FROZEN state. We
    > enforce these rules by checking for frozen tasks and cgroups in the
    > can_attach() function.
    >
    > Signed-off-by: Matt Helsley
    > ---
    > Builds, boots, passes testing against 2.6.26-rc5-mm2
    >
    > kernel/cgroup_freezer.c | 42 +++++++++++++++++++++++++-----------------
    > 1 file changed, 25 insertions(+), 17 deletions(-)
    >
    > Index: linux-2.6.26-rc5-mm2/kernel/cgroup_freezer.c
    > ================================================== =================
    > --- linux-2.6.26-rc5-mm2.orig/kernel/cgroup_freezer.c
    > +++ linux-2.6.26-rc5-mm2/kernel/cgroup_freezer.c
    > @@ -89,26 +89,43 @@ static void freezer_destroy(struct cgrou
    > struct cgroup *cgroup)
    > {
    > kfree(cgroup_freezer(cgroup));
    > }
    >
    > +/* Task is frozen or will freeze immediately when next it gets woken */
    > +static bool is_task_frozen_enough(struct task_struct *task)
    > +{
    > + return (frozen(task) || (task_is_stopped_or_traced(task) && freezing(task)));
    > +}
    >
    > +/*
    > + * The call to cgroup_lock() in the freezer.state write method prevents
    > + * a write to that file racing against an attach, and hence the
    > + * can_attach() result will remain valid until the attach completes.
    > + */
    > static int freezer_can_attach(struct cgroup_subsys *ss,
    > struct cgroup *new_cgroup,
    > struct task_struct *task)
    > {
    > struct freezer *freezer;
    > - int retval = 0;
    > + int retval;
    > +
    > + /* Anything frozen can't move or be moved to/from */
    > +
    > + if (is_task_frozen_enough(task))
    > + return -EBUSY;
    >


    cgroup_lock() can prevent the state change of old_cgroup and new_cgroup, but
    will the following racy happen ?
    1 2
    can_attach(tsk)
    is_task_frozen_enough(tsk) == false
    freeze_task(tsk)
    attach(tsk)

    i.e., will is_task_frozen_enough(tsk) remain valid through can_attach() and attach()?

    > - /*
    > - * The call to cgroup_lock() in the freezer.state write method prevents
    > - * a write to that file racing against an attach, and hence the
    > - * can_attach() result will remain valid until the attach completes.
    > - */
    > freezer = cgroup_freezer(new_cgroup);
    > if (freezer->state == STATE_FROZEN)
    > + return -EBUSY;
    > +
    > + retval = 0;
    > + task_lock(task);
    > + freezer = task_freezer(task);
    > + if (freezer->state == STATE_FROZEN)
    > retval = -EBUSY;
    > + task_unlock(task);
    > return retval;
    > }
    >
    > static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task)
    > {
    > @@ -139,16 +156,11 @@ static void check_if_frozen(struct cgrou
    > unsigned int nfrozen = 0, ntotal = 0;
    >
    > cgroup_iter_start(cgroup, &it);
    > while ((task = cgroup_iter_next(cgroup, &it))) {
    > ntotal++;
    > - /*
    > - * Task is frozen or will freeze immediately when next it gets
    > - * woken
    > - */
    > - if (frozen(task) ||
    > - (task_is_stopped_or_traced(task) && freezing(task)))
    > + if (is_task_frozen_enough(task))
    > nfrozen++;
    > }
    >
    > /*
    > * Transition to FROZEN when no new tasks can be added ensures
    > @@ -195,15 +207,11 @@ static int try_to_freeze_cgroup(struct c
    > freezer->state = STATE_FREEZING;
    > cgroup_iter_start(cgroup, &it);
    > while ((task = cgroup_iter_next(cgroup, &it))) {
    > if (!freeze_task(task, true))
    > continue;
    > - if (task_is_stopped_or_traced(task) && freezing(task))
    > - /*
    > - * The freeze flag is set so these tasks will
    > - * immediately go into the fridge upon waking.
    > - */
    > + if (is_task_frozen_enough(task))
    > continue;
    > if (!freezing(task) && !freezer_should_skip(task))
    > num_cant_freeze_now++;
    > }
    > cgroup_iter_end(cgroup, &it);
    >

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  15. Re: [PATCH 0/4] Container Freezer: Reuse Suspend Freezer

    Quoting KAMEZAWA Hiroyuki (kamezawa.hiroyu@jp.fujitsu.com):
    > On Wed, 09 Jul 2008 14:58:43 -0700
    > Matt Helsley wrote:
    >
    > >
    > > On Tue, 2008-07-08 at 13:07 -0700, Paul Menage wrote:
    > > > On Tue, Jul 8, 2008 at 1:06 PM, Paul Menage wrote:
    > > > > On Tue, Jul 8, 2008 at 12:39 PM, Matt Helsley wrote:
    > > > >>
    > > > >> One is to try and disallow users from moving frozen tasks. That doesn't
    > > > >> seem like a good approach since it would require a new cgroups interface
    > > > >> "can_detach()".
    > > > >
    > > > > Detaching from the old cgroup happens at the same time as attaching to
    > > > > the new cgroup, so can_attach() would work here.

    > >
    > > Update: I've made a patch implementing this. However it might be better
    > > to just modify attach() to thaw the moving task rather than disallow
    > > moving the frozen task. Serge, Cedric, Kame-san, do you have any
    > > thoughts on which is more useful and/or intuitive?
    > >

    >
    > Thank you for explanation in previous mail.
    >
    > Hmm, just thawing seems atractive but it will confuse people (I think).
    >
    > I think some kind of process-group is freezed by this freezer and "moving
    > freezed task" is wrong(unexpected) operation in general. And there will
    > be no demand to do that from users.
    > I think just taking "moving freezed task" as error-operation and returning
    > -EBUSY is better.
    >
    > Thanks,
    > -Kame


    I'm torn. Allowing the moves is kind of cool, but I think I agree that
    we should start out with the simpler semantics, which in this case is
    disallowing the move. The race Li may have found will only become more
    complicated when both sides of the race can change the task's frozen
    state.

    -serge
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  16. Re: [RFC][PATCH] Container Freezer: Don't Let Frozen Stuff Change


    On Thu, 2008-07-10 at 11:20 +0800, Li Zefan wrote:
    > Matt Helsley wrote:
    > > On Thu, 2008-07-10 at 09:42 +0900, KAMEZAWA Hiroyuki wrote:
    > >> On Wed, 09 Jul 2008 14:58:43 -0700
    > >> Matt Helsley wrote:
    > >>
    > >>> On Tue, 2008-07-08 at 13:07 -0700, Paul Menage wrote:
    > >>>> On Tue, Jul 8, 2008 at 1:06 PM, Paul Menage wrote:
    > >>>>> On Tue, Jul 8, 2008 at 12:39 PM, Matt Helsley wrote:
    > >>>>>> One is to try and disallow users from moving frozen tasks. That doesn't
    > >>>>>> seem like a good approach since it would require a new cgroups interface
    > >>>>>> "can_detach()".
    > >>>>> Detaching from the old cgroup happens at the same time as attaching to
    > >>>>> the new cgroup, so can_attach() would work here.
    > >>> Update: I've made a patch implementing this. However it might be better
    > >>> to just modify attach() to thaw the moving task rather than disallow
    > >>> moving the frozen task. Serge, Cedric, Kame-san, do you have any
    > >>> thoughts on which is more useful and/or intuitive?
    > >>>
    > >> Thank you for explanation in previous mail.
    > >>
    > >> Hmm, just thawing seems atractive but it will confuse people (I think).
    > >>
    > >> I think some kind of process-group is freezed by this freezer and "moving
    > >> freezed task" is wrong(unexpected) operation in general. And there will
    > >> be no demand to do that from users.
    > >> I think just taking "moving freezed task" as error-operation and returning
    > >> -EBUSY is better.

    > >
    > > Kame-san,
    > >
    > > I've been working on changes to the can_attach() code so it was pretty
    > > easy to try this out.
    > >
    > > Don't let frozen tasks or cgroups change. This means frozen tasks can't
    > > leave their current cgroup for another cgroup. It also means that tasks
    > > cannot be added to or removed from a cgroup in the FROZEN state. We
    > > enforce these rules by checking for frozen tasks and cgroups in the
    > > can_attach() function.
    > >
    > > Signed-off-by: Matt Helsley
    > > ---
    > > Builds, boots, passes testing against 2.6.26-rc5-mm2
    > >
    > > kernel/cgroup_freezer.c | 42 +++++++++++++++++++++++++-----------------
    > > 1 file changed, 25 insertions(+), 17 deletions(-)
    > >
    > > Index: linux-2.6.26-rc5-mm2/kernel/cgroup_freezer.c
    > > ================================================== =================
    > > --- linux-2.6.26-rc5-mm2.orig/kernel/cgroup_freezer.c
    > > +++ linux-2.6.26-rc5-mm2/kernel/cgroup_freezer.c
    > > @@ -89,26 +89,43 @@ static void freezer_destroy(struct cgrou
    > > struct cgroup *cgroup)
    > > {
    > > kfree(cgroup_freezer(cgroup));
    > > }
    > >
    > > +/* Task is frozen or will freeze immediately when next it gets woken */
    > > +static bool is_task_frozen_enough(struct task_struct *task)
    > > +{
    > > + return (frozen(task) || (task_is_stopped_or_traced(task) && freezing(task)));
    > > +}
    > >
    > > +/*
    > > + * The call to cgroup_lock() in the freezer.state write method prevents
    > > + * a write to that file racing against an attach, and hence the
    > > + * can_attach() result will remain valid until the attach completes.
    > > + */
    > > static int freezer_can_attach(struct cgroup_subsys *ss,
    > > struct cgroup *new_cgroup,
    > > struct task_struct *task)
    > > {
    > > struct freezer *freezer;
    > > - int retval = 0;
    > > + int retval;
    > > +
    > > + /* Anything frozen can't move or be moved to/from */
    > > +
    > > + if (is_task_frozen_enough(task))
    > > + return -EBUSY;
    > >

    >
    > cgroup_lock() can prevent the state change of old_cgroup and new_cgroup, but
    > will the following racy happen ?
    > 1 2


    For most of the paths using these functions we have:

    cgroup_lock() cgroup_lock()
    .... ...
    > can_attach(tsk)
    > is_task_frozen_enough(tsk) == false
    > freeze_task(tsk)

    or thaw_process(tsk)
    > attach(tsk)

    .... ...
    cgroup_unlock() cgroup_unlock()

    I've checked the cgroup freezer subsystem and the cgroup "core" and
    this interleaving isn't possible between those two pieces. Only the
    swsusp invocation of freeze_task() does not protect freeze/thaw with the
    cgroup_lock. I'll be looking into this some more to see if that's really
    a problem and if so how we might solve it.

    Thanks for this excellent question.

    Cheers,
    -Matt Helsley

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

+ Reply to Thread