diff options
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 100 |
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; | |||
175 | static struct cftype cgroup_base_files[]; | 175 | static struct cftype cgroup_base_files[]; |
176 | 176 | ||
177 | static void cgroup_put(struct cgroup *cgrp); | 177 | static void cgroup_put(struct cgroup *cgrp); |
178 | static int rebind_subsystems(struct cgroupfs_root *root, | 178 | static int rebind_subsystems(struct cgroupfs_root *dst_root, |
179 | unsigned long added_mask, unsigned removed_mask); | 179 | unsigned long ss_mask); |
180 | static void cgroup_destroy_css_killed(struct cgroup *cgrp); | 180 | static void cgroup_destroy_css_killed(struct cgroup *cgrp); |
181 | static int cgroup_destroy_locked(struct cgroup *cgrp); | 181 | static int cgroup_destroy_locked(struct cgroup *cgrp); |
182 | static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[], | 182 | static 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 | ||
979 | static int rebind_subsystems(struct cgroupfs_root *root, | 979 | static 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 | } |