|
@@ -722,23 +722,26 @@ static int rebind_subsystems(struct cgroupfs_root *root,
|
|
|
BUG_ON(cgrp->subsys[i]);
|
|
|
BUG_ON(!dummytop->subsys[i]);
|
|
|
BUG_ON(dummytop->subsys[i]->cgroup != dummytop);
|
|
|
+ mutex_lock(&ss->hierarchy_mutex);
|
|
|
cgrp->subsys[i] = dummytop->subsys[i];
|
|
|
cgrp->subsys[i]->cgroup = cgrp;
|
|
|
list_move(&ss->sibling, &root->subsys_list);
|
|
|
ss->root = root;
|
|
|
if (ss->bind)
|
|
|
ss->bind(ss, cgrp);
|
|
|
-
|
|
|
+ mutex_unlock(&ss->hierarchy_mutex);
|
|
|
} else if (bit & removed_bits) {
|
|
|
/* We're removing this subsystem */
|
|
|
BUG_ON(cgrp->subsys[i] != dummytop->subsys[i]);
|
|
|
BUG_ON(cgrp->subsys[i]->cgroup != cgrp);
|
|
|
+ mutex_lock(&ss->hierarchy_mutex);
|
|
|
if (ss->bind)
|
|
|
ss->bind(ss, dummytop);
|
|
|
dummytop->subsys[i]->cgroup = dummytop;
|
|
|
cgrp->subsys[i] = NULL;
|
|
|
subsys[i]->root = &rootnode;
|
|
|
list_move(&ss->sibling, &rootnode.subsys_list);
|
|
|
+ mutex_unlock(&ss->hierarchy_mutex);
|
|
|
} else if (bit & final_bits) {
|
|
|
/* Subsystem state should already exist */
|
|
|
BUG_ON(!cgrp->subsys[i]);
|
|
@@ -2338,6 +2341,29 @@ static void init_cgroup_css(struct cgroup_subsys_state *css,
|
|
|
cgrp->subsys[ss->subsys_id] = css;
|
|
|
}
|
|
|
|
|
|
+static void cgroup_lock_hierarchy(struct cgroupfs_root *root)
|
|
|
+{
|
|
|
+ /* We need to take each hierarchy_mutex in a consistent order */
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
|
|
|
+ struct cgroup_subsys *ss = subsys[i];
|
|
|
+ if (ss->root == root)
|
|
|
+ mutex_lock_nested(&ss->hierarchy_mutex, i);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void cgroup_unlock_hierarchy(struct cgroupfs_root *root)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
|
|
|
+ struct cgroup_subsys *ss = subsys[i];
|
|
|
+ if (ss->root == root)
|
|
|
+ mutex_unlock(&ss->hierarchy_mutex);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* cgroup_create - create a cgroup
|
|
|
* @parent: cgroup that will be parent of the new cgroup
|
|
@@ -2386,7 +2412,9 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
|
|
|
init_cgroup_css(css, ss, cgrp);
|
|
|
}
|
|
|
|
|
|
+ cgroup_lock_hierarchy(root);
|
|
|
list_add(&cgrp->sibling, &cgrp->parent->children);
|
|
|
+ cgroup_unlock_hierarchy(root);
|
|
|
root->number_of_cgroups++;
|
|
|
|
|
|
err = cgroup_create_dir(cgrp, dentry, mode);
|
|
@@ -2504,8 +2532,12 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
|
|
|
if (!list_empty(&cgrp->release_list))
|
|
|
list_del(&cgrp->release_list);
|
|
|
spin_unlock(&release_list_lock);
|
|
|
- /* delete my sibling from parent->children */
|
|
|
+
|
|
|
+ cgroup_lock_hierarchy(cgrp->root);
|
|
|
+ /* delete this cgroup from parent->children */
|
|
|
list_del(&cgrp->sibling);
|
|
|
+ cgroup_unlock_hierarchy(cgrp->root);
|
|
|
+
|
|
|
spin_lock(&cgrp->dentry->d_lock);
|
|
|
d = dget(cgrp->dentry);
|
|
|
spin_unlock(&d->d_lock);
|
|
@@ -2547,6 +2579,7 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
|
|
|
* need to invoke fork callbacks here. */
|
|
|
BUG_ON(!list_empty(&init_task.tasks));
|
|
|
|
|
|
+ mutex_init(&ss->hierarchy_mutex);
|
|
|
ss->active = 1;
|
|
|
}
|
|
|
|