aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cgroup.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r--kernel/cgroup.c100
1 files changed, 56 insertions, 44 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 78017f52c69b..b632981bd9c7 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -175,8 +175,8 @@ static int need_forkexit_callback __read_mostly;
175static struct cftype cgroup_base_files[]; 175static struct cftype cgroup_base_files[];
176 176
177static void cgroup_put(struct cgroup *cgrp); 177static void cgroup_put(struct cgroup *cgrp);
178static int rebind_subsystems(struct cgroupfs_root *root, 178static int rebind_subsystems(struct cgroupfs_root *dst_root,
179 unsigned long added_mask, unsigned removed_mask); 179 unsigned long ss_mask);
180static void cgroup_destroy_css_killed(struct cgroup *cgrp); 180static void cgroup_destroy_css_killed(struct cgroup *cgrp);
181static int cgroup_destroy_locked(struct cgroup *cgrp); 181static int cgroup_destroy_locked(struct cgroup *cgrp);
182static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[], 182static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[],
@@ -739,7 +739,7 @@ static void cgroup_destroy_root(struct cgroupfs_root *root)
739 BUG_ON(!list_empty(&cgrp->children)); 739 BUG_ON(!list_empty(&cgrp->children));
740 740
741 /* Rebind all subsystems back to the default hierarchy */ 741 /* Rebind all subsystems back to the default hierarchy */
742 WARN_ON(rebind_subsystems(root, 0, root->subsys_mask)); 742 rebind_subsystems(&cgroup_dummy_root, root->subsys_mask);
743 743
744 /* 744 /*
745 * Release all the links from cset_links to this hierarchy's 745 * Release all the links from cset_links to this hierarchy's
@@ -976,69 +976,77 @@ static void cgroup_clear_dir(struct cgroup *cgrp, unsigned long subsys_mask)
976 } 976 }
977} 977}
978 978
979static int rebind_subsystems(struct cgroupfs_root *root, 979static int rebind_subsystems(struct cgroupfs_root *dst_root,
980 unsigned long added_mask, unsigned removed_mask) 980 unsigned long ss_mask)
981{ 981{
982 struct cgroup *cgrp = &root->top_cgroup; 982 struct cgroup *dst_top = &dst_root->top_cgroup;
983 struct cgroup_subsys *ss; 983 struct cgroup_subsys *ss;
984 int i, ret; 984 int ssid, ret;
985 985
986 lockdep_assert_held(&cgroup_tree_mutex); 986 lockdep_assert_held(&cgroup_tree_mutex);
987 lockdep_assert_held(&cgroup_mutex); 987 lockdep_assert_held(&cgroup_mutex);
988 988
989 /* Check that any added subsystems are currently free */ 989 for_each_subsys(ss, ssid) {
990 for_each_subsys(ss, i) 990 if (!(ss_mask & (1 << ssid)))
991 if ((added_mask & (1 << i)) && ss->root != &cgroup_dummy_root) 991 continue;
992
993 /* if @ss is on the dummy_root, we can always move it */
994 if (ss->root == &cgroup_dummy_root)
995 continue;
996
997 /* if @ss has non-root cgroups attached to it, can't move */
998 if (!list_empty(&ss->root->top_cgroup.children))
992 return -EBUSY; 999 return -EBUSY;
993 1000
994 ret = cgroup_populate_dir(cgrp, added_mask); 1001 /* can't move between two non-dummy roots either */
995 if (ret) 1002 if (dst_root != &cgroup_dummy_root)
996 return ret; 1003 return -EBUSY;
1004 }
1005
1006 if (dst_root != &cgroup_dummy_root) {
1007 ret = cgroup_populate_dir(dst_top, ss_mask);
1008 if (ret)
1009 return ret;
1010 }
997 1011
998 /* 1012 /*
999 * Nothing can fail from this point on. Remove files for the 1013 * Nothing can fail from this point on. Remove files for the
1000 * removed subsystems and rebind each subsystem. 1014 * removed subsystems and rebind each subsystem.
1001 */ 1015 */
1002 mutex_unlock(&cgroup_mutex); 1016 mutex_unlock(&cgroup_mutex);
1003 cgroup_clear_dir(cgrp, removed_mask); 1017 for_each_subsys(ss, ssid)
1018 if ((ss_mask & (1 << ssid)) && ss->root != &cgroup_dummy_root)
1019 cgroup_clear_dir(&ss->root->top_cgroup, 1 << ssid);
1004 mutex_lock(&cgroup_mutex); 1020 mutex_lock(&cgroup_mutex);
1005 1021
1006 for_each_subsys(ss, i) { 1022 for_each_subsys(ss, ssid) {
1007 unsigned long bit = 1UL << i; 1023 struct cgroupfs_root *src_root;
1008 1024 struct cgroup *src_top;
1009 if (bit & added_mask) { 1025 struct cgroup_subsys_state *css;
1010 /* We're binding this subsystem to this hierarchy */
1011 BUG_ON(cgroup_css(cgrp, ss));
1012 BUG_ON(!cgroup_css(cgroup_dummy_top, ss));
1013 BUG_ON(cgroup_css(cgroup_dummy_top, ss)->cgroup != cgroup_dummy_top);
1014 1026
1015 rcu_assign_pointer(cgrp->subsys[i], 1027 if (!(ss_mask & (1 << ssid)))
1016 cgroup_css(cgroup_dummy_top, ss)); 1028 continue;
1017 cgroup_css(cgrp, ss)->cgroup = cgrp;
1018 1029
1019 ss->root = root; 1030 src_root = ss->root;
1020 if (ss->bind) 1031 src_top = &src_root->top_cgroup;
1021 ss->bind(cgroup_css(cgrp, ss)); 1032 css = cgroup_css(src_top, ss);
1022 1033
1023 /* refcount was already taken, and we're keeping it */ 1034 WARN_ON(!css || cgroup_css(dst_top, ss));
1024 root->subsys_mask |= bit;
1025 } else if (bit & removed_mask) {
1026 /* We're removing this subsystem */
1027 BUG_ON(cgroup_css(cgrp, ss) != cgroup_css(cgroup_dummy_top, ss));
1028 BUG_ON(cgroup_css(cgrp, ss)->cgroup != cgrp);
1029 1035
1030 if (ss->bind) 1036 RCU_INIT_POINTER(src_top->subsys[ssid], NULL);
1031 ss->bind(cgroup_css(cgroup_dummy_top, ss)); 1037 rcu_assign_pointer(dst_top->subsys[ssid], css);
1038 ss->root = dst_root;
1039 css->cgroup = dst_top;
1032 1040
1033 cgroup_css(cgroup_dummy_top, ss)->cgroup = cgroup_dummy_top; 1041 src_root->subsys_mask &= ~(1 << ssid);
1034 RCU_INIT_POINTER(cgrp->subsys[i], NULL); 1042 dst_root->subsys_mask |= 1 << ssid;
1035 1043
1036 cgroup_subsys[i]->root = &cgroup_dummy_root; 1044 if (ss->bind)
1037 root->subsys_mask &= ~bit; 1045 ss->bind(css);
1038 }
1039 } 1046 }
1040 1047
1041 kernfs_activate(cgrp->kn); 1048 if (dst_root != &cgroup_dummy_root)
1049 kernfs_activate(dst_top->kn);
1042 return 0; 1050 return 0;
1043} 1051}
1044 1052
@@ -1277,10 +1285,12 @@ static int cgroup_remount(struct kernfs_root *kf_root, int *flags, char *data)
1277 goto out_unlock; 1285 goto out_unlock;
1278 } 1286 }
1279 1287
1280 ret = rebind_subsystems(root, added_mask, removed_mask); 1288 ret = rebind_subsystems(root, added_mask);
1281 if (ret) 1289 if (ret)
1282 goto out_unlock; 1290 goto out_unlock;
1283 1291
1292 rebind_subsystems(&cgroup_dummy_root, removed_mask);
1293
1284 if (opts.release_agent) { 1294 if (opts.release_agent) {
1285 spin_lock(&release_agent_path_lock); 1295 spin_lock(&release_agent_path_lock);
1286 strcpy(root->release_agent_path, opts.release_agent); 1296 strcpy(root->release_agent_path, opts.release_agent);
@@ -1420,7 +1430,7 @@ static int cgroup_setup_root(struct cgroupfs_root *root, unsigned long ss_mask)
1420 if (ret) 1430 if (ret)
1421 goto destroy_root; 1431 goto destroy_root;
1422 1432
1423 ret = rebind_subsystems(root, ss_mask, 0); 1433 ret = rebind_subsystems(root, ss_mask);
1424 if (ret) 1434 if (ret)
1425 goto destroy_root; 1435 goto destroy_root;
1426 1436
@@ -4026,6 +4036,8 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
4026 4036
4027 BUG_ON(online_css(css)); 4037 BUG_ON(online_css(css));
4028 4038
4039 cgroup_dummy_root.subsys_mask |= 1 << ss->id;
4040
4029 mutex_unlock(&cgroup_mutex); 4041 mutex_unlock(&cgroup_mutex);
4030 mutex_unlock(&cgroup_tree_mutex); 4042 mutex_unlock(&cgroup_tree_mutex);
4031} 4043}