Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 165655
b: refs/heads/master
c: 7717f7b
h: refs/heads/master
i:
  165653: f633e70
  165651: 2c84acf
  165647: 243079f
v: v3
  • Loading branch information
Paul Menage authored and Linus Torvalds committed Sep 24, 2009
1 parent b0010ef commit 22b1881
Show file tree
Hide file tree
Showing 2 changed files with 200 additions and 50 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: fe6934354f8e287275500cd6ec73826d4d6ad457
refs/heads/master: 7717f7ba92de485bce8293419a20ffef130f4286
248 changes: 199 additions & 49 deletions trunk/kernel/cgroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ struct cg_cgroup_link {
* cgroup, anchored on cgroup->css_sets
*/
struct list_head cgrp_link_list;
struct cgroup *cgrp;
/*
* List running through cg_cgroup_links pointing at a
* single css_set object, anchored on css_set->cg_links
Expand All @@ -233,8 +234,11 @@ static int cgroup_subsys_init_idr(struct cgroup_subsys *ss);
static DEFINE_RWLOCK(css_set_lock);
static int css_set_count;

/* hash table for cgroup groups. This improves the performance to
* find an existing css_set */
/*
* hash table for cgroup groups. This improves the performance to find
* an existing css_set. This hash doesn't (currently) take into
* account cgroups in empty hierarchies.
*/
#define CSS_SET_HASH_BITS 7
#define CSS_SET_TABLE_SIZE (1 << CSS_SET_HASH_BITS)
static struct hlist_head css_set_table[CSS_SET_TABLE_SIZE];
Expand Down Expand Up @@ -343,6 +347,78 @@ static inline void put_css_set_taskexit(struct css_set *cg)
__put_css_set(cg, 1);
}

/*
* compare_css_sets - helper function for find_existing_css_set().
* @cg: candidate css_set being tested
* @old_cg: existing css_set for a task
* @new_cgrp: cgroup that's being entered by the task
* @template: desired set of css pointers in css_set (pre-calculated)
*
* Returns true if "cg" matches "old_cg" except for the hierarchy
* which "new_cgrp" belongs to, for which it should match "new_cgrp".
*/
static bool compare_css_sets(struct css_set *cg,
struct css_set *old_cg,
struct cgroup *new_cgrp,
struct cgroup_subsys_state *template[])
{
struct list_head *l1, *l2;

if (memcmp(template, cg->subsys, sizeof(cg->subsys))) {
/* Not all subsystems matched */
return false;
}

/*
* Compare cgroup pointers in order to distinguish between
* different cgroups in heirarchies with no subsystems. We
* could get by with just this check alone (and skip the
* memcmp above) but on most setups the memcmp check will
* avoid the need for this more expensive check on almost all
* candidates.
*/

l1 = &cg->cg_links;
l2 = &old_cg->cg_links;
while (1) {
struct cg_cgroup_link *cgl1, *cgl2;
struct cgroup *cg1, *cg2;

l1 = l1->next;
l2 = l2->next;
/* See if we reached the end - both lists are equal length. */
if (l1 == &cg->cg_links) {
BUG_ON(l2 != &old_cg->cg_links);
break;
} else {
BUG_ON(l2 == &old_cg->cg_links);
}
/* Locate the cgroups associated with these links. */
cgl1 = list_entry(l1, struct cg_cgroup_link, cg_link_list);
cgl2 = list_entry(l2, struct cg_cgroup_link, cg_link_list);
cg1 = cgl1->cgrp;
cg2 = cgl2->cgrp;
/* Hierarchies should be linked in the same order. */
BUG_ON(cg1->root != cg2->root);

/*
* If this hierarchy is the hierarchy of the cgroup
* that's changing, then we need to check that this
* css_set points to the new cgroup; if it's any other
* hierarchy, then this css_set should point to the
* same cgroup as the old css_set.
*/
if (cg1->root == new_cgrp->root) {
if (cg1 != new_cgrp)
return false;
} else {
if (cg1 != cg2)
return false;
}
}
return true;
}

/*
* find_existing_css_set() is a helper for
* find_css_set(), and checks to see whether an existing
Expand Down Expand Up @@ -384,10 +460,11 @@ static struct css_set *find_existing_css_set(

hhead = css_set_hash(template);
hlist_for_each_entry(cg, node, hhead, hlist) {
if (!memcmp(template, cg->subsys, sizeof(cg->subsys))) {
/* All subsystems matched */
return cg;
}
if (!compare_css_sets(cg, oldcg, cgrp, template))
continue;

/* This css_set matches what we need */
return cg;
}

/* No existing cgroup group matched */
Expand Down Expand Up @@ -441,8 +518,13 @@ static void link_css_set(struct list_head *tmp_cg_links,
link = list_first_entry(tmp_cg_links, struct cg_cgroup_link,
cgrp_link_list);
link->cg = cg;
link->cgrp = cgrp;
list_move(&link->cgrp_link_list, &cgrp->css_sets);
list_add(&link->cg_link_list, &cg->cg_links);
/*
* Always add links to the tail of the list so that the list
* is sorted by order of hierarchy creation
*/
list_add_tail(&link->cg_link_list, &cg->cg_links);
}

/*
Expand All @@ -462,6 +544,7 @@ static struct css_set *find_css_set(
struct list_head tmp_cg_links;

struct hlist_head *hhead;
struct cg_cgroup_link *link;

/* First see if we already have a cgroup group that matches
* the desired set */
Expand Down Expand Up @@ -497,18 +580,14 @@ static struct css_set *find_css_set(
/* Add reference counts and links from the new css_set. */
for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
struct cgroup *cgrp = res->subsys[i]->cgroup;
struct cgroup_subsys *ss = subsys[i];
atomic_inc(&cgrp->count);
/*
* We want to add a link once per cgroup, so we
* only do it for the first subsystem in each
* hierarchy
*/
if (ss->root->subsys_list.next == &ss->sibling)
link_css_set(&tmp_cg_links, res, cgrp);
}
if (list_empty(&rootnode.subsys_list))
link_css_set(&tmp_cg_links, res, dummytop);
list_for_each_entry(link, &oldcg->cg_links, cg_link_list) {
struct cgroup *c = link->cgrp;
if (c->root == cgrp->root)
c = cgrp;
link_css_set(&tmp_cg_links, res, c);
}

BUG_ON(!list_empty(&tmp_cg_links));

Expand All @@ -523,6 +602,41 @@ static struct css_set *find_css_set(
return res;
}

/*
* Return the cgroup for "task" from the given hierarchy. Must be
* called with cgroup_mutex held.
*/
static struct cgroup *task_cgroup_from_root(struct task_struct *task,
struct cgroupfs_root *root)
{
struct css_set *css;
struct cgroup *res = NULL;

BUG_ON(!mutex_is_locked(&cgroup_mutex));
read_lock(&css_set_lock);
/*
* No need to lock the task - since we hold cgroup_mutex the
* task can't change groups, so the only thing that can happen
* is that it exits and its css is set back to init_css_set.
*/
css = task->cgroups;
if (css == &init_css_set) {
res = &root->top_cgroup;
} else {
struct cg_cgroup_link *link;
list_for_each_entry(link, &css->cg_links, cg_link_list) {
struct cgroup *c = link->cgrp;
if (c->root == root) {
res = c;
break;
}
}
}
read_unlock(&css_set_lock);
BUG_ON(!res);
return res;
}

/*
* There is one global cgroup mutex. We also require taking
* task_lock() when dereferencing a task's cgroup subsys pointers.
Expand Down Expand Up @@ -1361,27 +1475,6 @@ int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
return 0;
}

/*
* Return the first subsystem attached to a cgroup's hierarchy, and
* its subsystem id.
*/

static void get_first_subsys(const struct cgroup *cgrp,
struct cgroup_subsys_state **css, int *subsys_id)
{
const struct cgroupfs_root *root = cgrp->root;
const struct cgroup_subsys *test_ss;
BUG_ON(list_empty(&root->subsys_list));
test_ss = list_entry(root->subsys_list.next,
struct cgroup_subsys, sibling);
if (css) {
*css = cgrp->subsys[test_ss->subsys_id];
BUG_ON(!*css);
}
if (subsys_id)
*subsys_id = test_ss->subsys_id;
}

/**
* cgroup_attach_task - attach task 'tsk' to cgroup 'cgrp'
* @cgrp: the cgroup the task is attaching to
Expand All @@ -1398,12 +1491,9 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
struct css_set *cg;
struct css_set *newcg;
struct cgroupfs_root *root = cgrp->root;
int subsys_id;

get_first_subsys(cgrp, NULL, &subsys_id);

/* Nothing to do if the task is already in that cgroup */
oldcgrp = task_cgroup(tsk, subsys_id);
oldcgrp = task_cgroup_from_root(tsk, root);
if (cgrp == oldcgrp)
return 0;

Expand Down Expand Up @@ -1961,7 +2051,7 @@ int cgroup_task_count(const struct cgroup *cgrp)
* the start of a css_set
*/
static void cgroup_advance_iter(struct cgroup *cgrp,
struct cgroup_iter *it)
struct cgroup_iter *it)
{
struct list_head *l = it->cg_link;
struct cg_cgroup_link *link;
Expand Down Expand Up @@ -2964,6 +3054,7 @@ int __init cgroup_init_early(void)
init_task.cgroups = &init_css_set;

init_css_set_link.cg = &init_css_set;
init_css_set_link.cgrp = dummytop;
list_add(&init_css_set_link.cgrp_link_list,
&rootnode.top_cgroup.css_sets);
list_add(&init_css_set_link.cg_link_list,
Expand Down Expand Up @@ -3071,7 +3162,6 @@ static int proc_cgroup_show(struct seq_file *m, void *v)
for_each_active_root(root) {
struct cgroup_subsys *ss;
struct cgroup *cgrp;
int subsys_id;
int count = 0;

seq_printf(m, "%lu:", root->subsys_bits);
Expand All @@ -3081,8 +3171,7 @@ static int proc_cgroup_show(struct seq_file *m, void *v)
seq_printf(m, "%sname=%s", count ? "," : "",
root->name);
seq_putc(m, ':');
get_first_subsys(&root->top_cgroup, NULL, &subsys_id);
cgrp = task_cgroup(tsk, subsys_id);
cgrp = task_cgroup_from_root(tsk, root);
retval = cgroup_path(cgrp, buf, PAGE_SIZE);
if (retval < 0)
goto out_unlock;
Expand Down Expand Up @@ -3408,13 +3497,11 @@ int cgroup_is_descendant(const struct cgroup *cgrp, struct task_struct *task)
{
int ret;
struct cgroup *target;
int subsys_id;

if (cgrp == dummytop)
return 1;

get_first_subsys(cgrp, NULL, &subsys_id);
target = task_cgroup(task, subsys_id);
target = task_cgroup_from_root(task, cgrp->root);
while (cgrp != target && cgrp!= cgrp->top_cgroup)
cgrp = cgrp->parent;
ret = (cgrp == target);
Expand Down Expand Up @@ -3824,6 +3911,59 @@ static u64 current_css_set_refcount_read(struct cgroup *cont,
return count;
}

static int current_css_set_cg_links_read(struct cgroup *cont,
struct cftype *cft,
struct seq_file *seq)
{
struct cg_cgroup_link *link;
struct css_set *cg;

read_lock(&css_set_lock);
rcu_read_lock();
cg = rcu_dereference(current->cgroups);
list_for_each_entry(link, &cg->cg_links, cg_link_list) {
struct cgroup *c = link->cgrp;
const char *name;

if (c->dentry)
name = c->dentry->d_name.name;
else
name = "?";
seq_printf(seq, "Root %lu group %s\n",
c->root->subsys_bits, name);
}
rcu_read_unlock();
read_unlock(&css_set_lock);
return 0;
}

#define MAX_TASKS_SHOWN_PER_CSS 25
static int cgroup_css_links_read(struct cgroup *cont,
struct cftype *cft,
struct seq_file *seq)
{
struct cg_cgroup_link *link;

read_lock(&css_set_lock);
list_for_each_entry(link, &cont->css_sets, cgrp_link_list) {
struct css_set *cg = link->cg;
struct task_struct *task;
int count = 0;
seq_printf(seq, "css_set %p\n", cg);
list_for_each_entry(task, &cg->tasks, cg_list) {
if (count++ > MAX_TASKS_SHOWN_PER_CSS) {
seq_puts(seq, " ...\n");
break;
} else {
seq_printf(seq, " task %d\n",
task_pid_vnr(task));
}
}
}
read_unlock(&css_set_lock);
return 0;
}

static u64 releasable_read(struct cgroup *cgrp, struct cftype *cft)
{
return test_bit(CGRP_RELEASABLE, &cgrp->flags);
Expand All @@ -3849,6 +3989,16 @@ static struct cftype debug_files[] = {
.read_u64 = current_css_set_refcount_read,
},

{
.name = "current_css_set_cg_links",
.read_seq_string = current_css_set_cg_links_read,
},

{
.name = "cgroup_css_links",
.read_seq_string = cgroup_css_links_read,
},

{
.name = "releasable",
.read_u64 = releasable_read,
Expand Down

0 comments on commit 22b1881

Please sign in to comment.