Skip to content

Commit

Permalink
cgroup: rename ->create/post_create/pre_destroy/destroy() to ->css_al…
Browse files Browse the repository at this point in the history
…loc/online/offline/free()

Rename cgroup_subsys css lifetime related callbacks to better describe
what their roles are.  Also, update documentation.

Signed-off-by: Tejun Heo <[email protected]>
Acked-by: Li Zefan <[email protected]>
  • Loading branch information
htejun committed Nov 19, 2012
1 parent b1929db commit 92fb974
Show file tree
Hide file tree
Showing 13 changed files with 132 additions and 121 deletions.
49 changes: 29 additions & 20 deletions Documentation/cgroups/cgroups.txt
Original file line number Diff line number Diff line change
Expand Up @@ -553,16 +553,16 @@ call to cgroup_unload_subsys(). It should also set its_subsys.module =
THIS_MODULE in its .c file.

Each subsystem may export the following methods. The only mandatory
methods are create/destroy. Any others that are null are presumed to
methods are css_alloc/free. Any others that are null are presumed to
be successful no-ops.

struct cgroup_subsys_state *create(struct cgroup *cgrp)
struct cgroup_subsys_state *css_alloc(struct cgroup *cgrp)
(cgroup_mutex held by caller)

Called to create a subsystem state object for a cgroup. The
Called to allocate a subsystem state object for a cgroup. The
subsystem should allocate its subsystem state object for the passed
cgroup, returning a pointer to the new object on success or a
negative error code. On success, the subsystem pointer should point to
ERR_PTR() value. On success, the subsystem pointer should point to
a structure of type cgroup_subsys_state (typically embedded in a
larger subsystem-specific object), which will be initialized by the
cgroup system. Note that this will be called at initialization to
Expand All @@ -571,24 +571,33 @@ identified by the passed cgroup object having a NULL parent (since
it's the root of the hierarchy) and may be an appropriate place for
initialization code.

void destroy(struct cgroup *cgrp)
int css_online(struct cgroup *cgrp)
(cgroup_mutex held by caller)

The cgroup system is about to destroy the passed cgroup; the subsystem
should do any necessary cleanup and free its subsystem state
object. By the time this method is called, the cgroup has already been
unlinked from the file system and from the child list of its parent;
cgroup->parent is still valid. (Note - can also be called for a
newly-created cgroup if an error occurs after this subsystem's
create() method has been called for the new cgroup).

int pre_destroy(struct cgroup *cgrp);

Called before checking the reference count on each subsystem. This may
be useful for subsystems which have some extra references even if
there are not tasks in the cgroup. If pre_destroy() returns error code,
rmdir() will fail with it. From this behavior, pre_destroy() can be
called multiple times against a cgroup.
Called after @cgrp successfully completed all allocations and made
visible to cgroup_for_each_child/descendant_*() iterators. The
subsystem may choose to fail creation by returning -errno. This
callback can be used to implement reliable state sharing and
propagation along the hierarchy. See the comment on
cgroup_for_each_descendant_pre() for details.

void css_offline(struct cgroup *cgrp);

This is the counterpart of css_online() and called iff css_online()
has succeeded on @cgrp. This signifies the beginning of the end of
@cgrp. @cgrp is being removed and the subsystem should start dropping
all references it's holding on @cgrp. When all references are dropped,
cgroup removal will proceed to the next step - css_free(). After this
callback, @cgrp should be considered dead to the subsystem.

void css_free(struct cgroup *cgrp)
(cgroup_mutex held by caller)

The cgroup system is about to free @cgrp; the subsystem should free
its subsystem state object. By the time this method is called, @cgrp
is completely unused; @cgrp->parent is still valid. (Note - can also
be called for a newly-created cgroup if an error occurs after this
subsystem's create() method has been called for the new cgroup).

int can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
(cgroup_mutex held by caller)
Expand Down
14 changes: 7 additions & 7 deletions block/blk-cgroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ struct cftype blkcg_files[] = {
};

/**
* blkcg_pre_destroy - cgroup pre_destroy callback
* blkcg_css_offline - cgroup css_offline callback
* @cgroup: cgroup of interest
*
* This function is called when @cgroup is about to go away and responsible
Expand All @@ -610,7 +610,7 @@ struct cftype blkcg_files[] = {
*
* This is the blkcg counterpart of ioc_release_fn().
*/
static void blkcg_pre_destroy(struct cgroup *cgroup)
static void blkcg_css_offline(struct cgroup *cgroup)
{
struct blkcg *blkcg = cgroup_to_blkcg(cgroup);

Expand All @@ -634,15 +634,15 @@ static void blkcg_pre_destroy(struct cgroup *cgroup)
spin_unlock_irq(&blkcg->lock);
}

static void blkcg_destroy(struct cgroup *cgroup)
static void blkcg_css_free(struct cgroup *cgroup)
{
struct blkcg *blkcg = cgroup_to_blkcg(cgroup);

if (blkcg != &blkcg_root)
kfree(blkcg);
}

static struct cgroup_subsys_state *blkcg_create(struct cgroup *cgroup)
static struct cgroup_subsys_state *blkcg_css_alloc(struct cgroup *cgroup)
{
static atomic64_t id_seq = ATOMIC64_INIT(0);
struct blkcg *blkcg;
Expand Down Expand Up @@ -739,10 +739,10 @@ static int blkcg_can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)

struct cgroup_subsys blkio_subsys = {
.name = "blkio",
.create = blkcg_create,
.css_alloc = blkcg_css_alloc,
.css_offline = blkcg_css_offline,
.css_free = blkcg_css_free,
.can_attach = blkcg_can_attach,
.pre_destroy = blkcg_pre_destroy,
.destroy = blkcg_destroy,
.subsys_id = blkio_subsys_id,
.base_cftypes = blkcg_files,
.module = THIS_MODULE,
Expand Down
35 changes: 18 additions & 17 deletions include/linux/cgroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ struct cgroup_subsys_state {
/* bits in struct cgroup_subsys_state flags field */
enum {
CSS_ROOT = (1 << 0), /* this CSS is the root of the subsystem */
CSS_ONLINE = (1 << 1), /* between ->post_create() and ->pre_destroy() */
CSS_ONLINE = (1 << 1), /* between ->css_online() and ->css_offline() */
};

/* Caller must verify that the css is not for root cgroup */
Expand Down Expand Up @@ -439,10 +439,11 @@ int cgroup_taskset_size(struct cgroup_taskset *tset);
*/

struct cgroup_subsys {
struct cgroup_subsys_state *(*create)(struct cgroup *cgrp);
int (*post_create)(struct cgroup *cgrp);
void (*pre_destroy)(struct cgroup *cgrp);
void (*destroy)(struct cgroup *cgrp);
struct cgroup_subsys_state *(*css_alloc)(struct cgroup *cgrp);
int (*css_online)(struct cgroup *cgrp);
void (*css_offline)(struct cgroup *cgrp);
void (*css_free)(struct cgroup *cgrp);

int (*can_attach)(struct cgroup *cgrp, struct cgroup_taskset *tset);
void (*cancel_attach)(struct cgroup *cgrp, struct cgroup_taskset *tset);
void (*attach)(struct cgroup *cgrp, struct cgroup_taskset *tset);
Expand Down Expand Up @@ -541,13 +542,13 @@ static inline struct cgroup* task_cgroup(struct task_struct *task,
* @cgroup: cgroup whose children to walk
*
* Walk @cgroup's children. Must be called under rcu_read_lock(). A child
* cgroup which hasn't finished ->post_create() or already has finished
* ->pre_destroy() may show up during traversal and it's each subsystem's
* cgroup which hasn't finished ->css_online() or already has finished
* ->css_offline() may show up during traversal and it's each subsystem's
* responsibility to verify that each @pos is alive.
*
* If a subsystem synchronizes against the parent in its ->post_create()
* and before starting iterating, a cgroup which finished ->post_create()
* is guaranteed to be visible in the future iterations.
* If a subsystem synchronizes against the parent in its ->css_online() and
* before starting iterating, a cgroup which finished ->css_online() is
* guaranteed to be visible in the future iterations.
*/
#define cgroup_for_each_child(pos, cgroup) \
list_for_each_entry_rcu(pos, &(cgroup)->children, sibling)
Expand All @@ -561,19 +562,19 @@ struct cgroup *cgroup_next_descendant_pre(struct cgroup *pos,
* @cgroup: cgroup whose descendants to walk
*
* Walk @cgroup's descendants. Must be called under rcu_read_lock(). A
* descendant cgroup which hasn't finished ->post_create() or already has
* finished ->pre_destroy() may show up during traversal and it's each
* descendant cgroup which hasn't finished ->css_online() or already has
* finished ->css_offline() may show up during traversal and it's each
* subsystem's responsibility to verify that each @pos is alive.
*
* If a subsystem synchronizes against the parent in its ->post_create()
* and before starting iterating, and synchronizes against @pos on each
* iteration, any descendant cgroup which finished ->post_create() is
* If a subsystem synchronizes against the parent in its ->css_online() and
* before starting iterating, and synchronizes against @pos on each
* iteration, any descendant cgroup which finished ->css_offline() is
* guaranteed to be visible in the future iterations.
*
* In other words, the following guarantees that a descendant can't escape
* state updates of its ancestors.
*
* my_post_create(@cgrp)
* my_online(@cgrp)
* {
* Lock @cgrp->parent and @cgrp;
* Inherit state from @cgrp->parent;
Expand Down Expand Up @@ -606,7 +607,7 @@ struct cgroup *cgroup_next_descendant_pre(struct cgroup *pos,
* iteration should lock and unlock both @pos->parent and @pos.
*
* Alternatively, a subsystem may choose to use a single global lock to
* synchronize ->post_create() and ->pre_destroy() against tree-walking
* synchronize ->css_online() and ->css_offline() against tree-walking
* operations.
*/
#define cgroup_for_each_descendant_pre(pos, cgroup) \
Expand Down
51 changes: 26 additions & 25 deletions kernel/cgroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -876,7 +876,7 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
* Release the subsystem state objects.
*/
for_each_subsys(cgrp->root, ss)
ss->destroy(cgrp);
ss->css_free(cgrp);

cgrp->root->number_of_cgroups--;
mutex_unlock(&cgroup_mutex);
Expand Down Expand Up @@ -4048,8 +4048,8 @@ static int online_css(struct cgroup_subsys *ss, struct cgroup *cgrp)

lockdep_assert_held(&cgroup_mutex);

if (ss->post_create)
ret = ss->post_create(cgrp);
if (ss->css_online)
ret = ss->css_online(cgrp);
if (!ret)
cgrp->subsys[ss->subsys_id]->flags |= CSS_ONLINE;
return ret;
Expand All @@ -4067,14 +4067,14 @@ static void offline_css(struct cgroup_subsys *ss, struct cgroup *cgrp)
return;

/*
* pre_destroy() should be called with cgroup_mutex unlocked. See
* css_offline() should be called with cgroup_mutex unlocked. See
* 3fa59dfbc3 ("cgroup: fix potential deadlock in pre_destroy") for
* details. This temporary unlocking should go away once
* cgroup_mutex is unexported from controllers.
*/
if (ss->pre_destroy) {
if (ss->css_offline) {
mutex_unlock(&cgroup_mutex);
ss->pre_destroy(cgrp);
ss->css_offline(cgrp);
mutex_lock(&cgroup_mutex);
}

Expand Down Expand Up @@ -4136,7 +4136,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
for_each_subsys(root, ss) {
struct cgroup_subsys_state *css;

css = ss->create(cgrp);
css = ss->css_alloc(cgrp);
if (IS_ERR(css)) {
err = PTR_ERR(css);
goto err_free_all;
Expand All @@ -4147,7 +4147,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
if (err)
goto err_free_all;
}
/* At error, ->destroy() callback has to free assigned ID. */
/* At error, ->css_free() callback has to free assigned ID. */
if (clone_children(parent) && ss->post_clone)
ss->post_clone(cgrp);

Expand Down Expand Up @@ -4201,7 +4201,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
err_free_all:
for_each_subsys(root, ss) {
if (cgrp->subsys[ss->subsys_id])
ss->destroy(cgrp);
ss->css_free(cgrp);
}
mutex_unlock(&cgroup_mutex);
/* Release the reference count that we took on the superblock */
Expand Down Expand Up @@ -4381,7 +4381,7 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
/* Create the top cgroup state for this subsystem */
list_add(&ss->sibling, &rootnode.subsys_list);
ss->root = &rootnode;
css = ss->create(dummytop);
css = ss->css_alloc(dummytop);
/* We don't handle early failures gracefully */
BUG_ON(IS_ERR(css));
init_cgroup_css(css, ss, dummytop);
Expand Down Expand Up @@ -4425,7 +4425,7 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)

/* check name and function validity */
if (ss->name == NULL || strlen(ss->name) > MAX_CGROUP_TYPE_NAMELEN ||
ss->create == NULL || ss->destroy == NULL)
ss->css_alloc == NULL || ss->css_free == NULL)
return -EINVAL;

/*
Expand Down Expand Up @@ -4454,10 +4454,11 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)
subsys[ss->subsys_id] = ss;

/*
* no ss->create seems to need anything important in the ss struct, so
* this can happen first (i.e. before the rootnode attachment).
* no ss->css_alloc seems to need anything important in the ss
* struct, so this can happen first (i.e. before the rootnode
* attachment).
*/
css = ss->create(dummytop);
css = ss->css_alloc(dummytop);
if (IS_ERR(css)) {
/* failure case - need to deassign the subsys[] slot. */
subsys[ss->subsys_id] = NULL;
Expand Down Expand Up @@ -4577,12 +4578,12 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss)
write_unlock(&css_set_lock);

/*
* remove subsystem's css from the dummytop and free it - need to free
* before marking as null because ss->destroy needs the cgrp->subsys
* pointer to find their state. note that this also takes care of
* freeing the css_id.
* remove subsystem's css from the dummytop and free it - need to
* free before marking as null because ss->css_free needs the
* cgrp->subsys pointer to find their state. note that this also
* takes care of freeing the css_id.
*/
ss->destroy(dummytop);
ss->css_free(dummytop);
dummytop->subsys[ss->subsys_id] = NULL;

mutex_unlock(&cgroup_mutex);
Expand Down Expand Up @@ -4626,8 +4627,8 @@ int __init cgroup_init_early(void)

BUG_ON(!ss->name);
BUG_ON(strlen(ss->name) > MAX_CGROUP_TYPE_NAMELEN);
BUG_ON(!ss->create);
BUG_ON(!ss->destroy);
BUG_ON(!ss->css_alloc);
BUG_ON(!ss->css_free);
if (ss->subsys_id != i) {
printk(KERN_ERR "cgroup: Subsys %s id == %d\n",
ss->name, ss->subsys_id);
Expand Down Expand Up @@ -5439,7 +5440,7 @@ struct cgroup_subsys_state *cgroup_css_from_dir(struct file *f, int id)
}

#ifdef CONFIG_CGROUP_DEBUG
static struct cgroup_subsys_state *debug_create(struct cgroup *cont)
static struct cgroup_subsys_state *debug_css_alloc(struct cgroup *cont)
{
struct cgroup_subsys_state *css = kzalloc(sizeof(*css), GFP_KERNEL);

Expand All @@ -5449,7 +5450,7 @@ static struct cgroup_subsys_state *debug_create(struct cgroup *cont)
return css;
}

static void debug_destroy(struct cgroup *cont)
static void debug_css_free(struct cgroup *cont)
{
kfree(cont->subsys[debug_subsys_id]);
}
Expand Down Expand Up @@ -5578,8 +5579,8 @@ static struct cftype debug_files[] = {

struct cgroup_subsys debug_subsys = {
.name = "debug",
.create = debug_create,
.destroy = debug_destroy,
.css_alloc = debug_css_alloc,
.css_free = debug_css_free,
.subsys_id = debug_subsys_id,
.base_cftypes = debug_files,
};
Expand Down
Loading

0 comments on commit 92fb974

Please sign in to comment.