diff options
author | Tejun Heo <tj@kernel.org> | 2014-02-11 11:52:47 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2014-02-11 11:52:47 -0500 |
commit | ace2bee8135a3dc725958b8d08c55ee9df813d39 (patch) | |
tree | 8221115e4d100e566a9405bb25db79b0a751c480 /kernel/cgroup.c | |
parent | 5a17f543ed6808e9085063277fe46795dea484bd (diff) |
cgroup: introduce cgroup_tree_mutex
Currently cgroup uses combination of inode->i_mutex'es and
cgroup_mutex for synchronization. With the scheduled kernfs
conversion, i_mutex'es will be removed. Unfortunately, just using
cgroup_mutex isn't possible. All kernfs file and syscall operations,
most of which require grabbing cgroup_mutex, will be called with
kernfs active ref held and, if we try to perform kernfs removals under
cgroup_mutex, it can deadlock as kernfs_remove() tries to drain the
target node.
Let's introduce a new outer mutex, cgroup_tree_mutex, which protects
stuff used during hierarchy changing operations - cftypes and all the
operations which may affect the cgroupfs. It also covers css
association and iteration. This allows cgroup_css(), for_each_css()
and other css iterators to be called under cgroup_tree_mutex. The new
mutex will nest above both kernfs's active ref protection and
cgroup_mutex. By protecting tree modifications with a separate outer
mutex, we can get rid of the forementioned deadlock condition.
Actual file additions and removals now require cgroup_tree_mutex
instead of cgroup_mutex. Currently, cgroup_tree_mutex is never used
without cgroup_mutex; however, we'll soon add hierarchy modification
sections which are only protected by cgroup_tree_mutex. In the
future, we might want to make the locking more granular by better
splitting the coverages of the two mutexes. For now, this should do.
v2: Rebased on top of 0ab02ca8f887 ("cgroup: protect modifications to
cgroup_idr with cgroup_mutex").
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Li Zefan <lizefan@huawei.com>
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 66 |
1 files changed, 53 insertions, 13 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index fc2db071d95e..cb20d12cb096 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -68,6 +68,15 @@ | |||
68 | #define CGROUP_PIDLIST_DESTROY_DELAY HZ | 68 | #define CGROUP_PIDLIST_DESTROY_DELAY HZ |
69 | 69 | ||
70 | /* | 70 | /* |
71 | * cgroup_tree_mutex nests above cgroup_mutex and protects cftypes, file | ||
72 | * creation/removal and hierarchy changing operations including cgroup | ||
73 | * creation, removal, css association and controller rebinding. This outer | ||
74 | * lock is needed mainly to resolve the circular dependency between kernfs | ||
75 | * active ref and cgroup_mutex. cgroup_tree_mutex nests above both. | ||
76 | */ | ||
77 | static DEFINE_MUTEX(cgroup_tree_mutex); | ||
78 | |||
79 | /* | ||
71 | * cgroup_mutex is the master lock. Any modification to cgroup or its | 80 | * cgroup_mutex is the master lock. Any modification to cgroup or its |
72 | * hierarchy must be performed while holding it. | 81 | * hierarchy must be performed while holding it. |
73 | */ | 82 | */ |
@@ -84,10 +93,11 @@ static DEFINE_MUTEX(cgroup_mutex); | |||
84 | */ | 93 | */ |
85 | static DEFINE_SPINLOCK(release_agent_path_lock); | 94 | static DEFINE_SPINLOCK(release_agent_path_lock); |
86 | 95 | ||
87 | #define cgroup_assert_mutex_or_rcu_locked() \ | 96 | #define cgroup_assert_mutexes_or_rcu_locked() \ |
88 | rcu_lockdep_assert(rcu_read_lock_held() || \ | 97 | rcu_lockdep_assert(rcu_read_lock_held() || \ |
98 | lockdep_is_held(&cgroup_tree_mutex) || \ | ||
89 | lockdep_is_held(&cgroup_mutex), \ | 99 | lockdep_is_held(&cgroup_mutex), \ |
90 | "cgroup_mutex or RCU read lock required"); | 100 | "cgroup_[tree_]mutex or RCU read lock required"); |
91 | 101 | ||
92 | /* | 102 | /* |
93 | * cgroup destruction makes heavy use of work items and there can be a lot | 103 | * cgroup destruction makes heavy use of work items and there can be a lot |
@@ -179,7 +189,8 @@ static struct cgroup_subsys_state *cgroup_css(struct cgroup *cgrp, | |||
179 | { | 189 | { |
180 | if (ss) | 190 | if (ss) |
181 | return rcu_dereference_check(cgrp->subsys[ss->id], | 191 | return rcu_dereference_check(cgrp->subsys[ss->id], |
182 | lockdep_is_held(&cgroup_mutex)); | 192 | lockdep_is_held(&cgroup_tree_mutex) || |
193 | lockdep_is_held(&cgroup_mutex)); | ||
183 | else | 194 | else |
184 | return &cgrp->dummy_css; | 195 | return &cgrp->dummy_css; |
185 | } | 196 | } |
@@ -235,6 +246,7 @@ static int notify_on_release(const struct cgroup *cgrp) | |||
235 | for ((ssid) = 0; (ssid) < CGROUP_SUBSYS_COUNT; (ssid)++) \ | 246 | for ((ssid) = 0; (ssid) < CGROUP_SUBSYS_COUNT; (ssid)++) \ |
236 | if (!((css) = rcu_dereference_check( \ | 247 | if (!((css) = rcu_dereference_check( \ |
237 | (cgrp)->subsys[(ssid)], \ | 248 | (cgrp)->subsys[(ssid)], \ |
249 | lockdep_is_held(&cgroup_tree_mutex) || \ | ||
238 | lockdep_is_held(&cgroup_mutex)))) { } \ | 250 | lockdep_is_held(&cgroup_mutex)))) { } \ |
239 | else | 251 | else |
240 | 252 | ||
@@ -883,7 +895,7 @@ static void cgroup_rm_file(struct cgroup *cgrp, const struct cftype *cft) | |||
883 | struct cfent *cfe; | 895 | struct cfent *cfe; |
884 | 896 | ||
885 | lockdep_assert_held(&cgrp->dentry->d_inode->i_mutex); | 897 | lockdep_assert_held(&cgrp->dentry->d_inode->i_mutex); |
886 | lockdep_assert_held(&cgroup_mutex); | 898 | lockdep_assert_held(&cgroup_tree_mutex); |
887 | 899 | ||
888 | /* | 900 | /* |
889 | * If we're doing cleanup due to failure of cgroup_create(), | 901 | * If we're doing cleanup due to failure of cgroup_create(), |
@@ -948,7 +960,8 @@ static int rebind_subsystems(struct cgroupfs_root *root, | |||
948 | struct cgroup_subsys *ss; | 960 | struct cgroup_subsys *ss; |
949 | int i, ret; | 961 | int i, ret; |
950 | 962 | ||
951 | BUG_ON(!mutex_is_locked(&cgroup_mutex)); | 963 | lockdep_assert_held(&cgroup_tree_mutex); |
964 | lockdep_assert_held(&cgroup_mutex); | ||
952 | 965 | ||
953 | /* Check that any added subsystems are currently free */ | 966 | /* Check that any added subsystems are currently free */ |
954 | for_each_subsys(ss, i) | 967 | for_each_subsys(ss, i) |
@@ -1220,6 +1233,7 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data) | |||
1220 | } | 1233 | } |
1221 | 1234 | ||
1222 | mutex_lock(&cgrp->dentry->d_inode->i_mutex); | 1235 | mutex_lock(&cgrp->dentry->d_inode->i_mutex); |
1236 | mutex_lock(&cgroup_tree_mutex); | ||
1223 | mutex_lock(&cgroup_mutex); | 1237 | mutex_lock(&cgroup_mutex); |
1224 | 1238 | ||
1225 | /* See what subsystems are wanted */ | 1239 | /* See what subsystems are wanted */ |
@@ -1263,6 +1277,7 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data) | |||
1263 | kfree(opts.release_agent); | 1277 | kfree(opts.release_agent); |
1264 | kfree(opts.name); | 1278 | kfree(opts.name); |
1265 | mutex_unlock(&cgroup_mutex); | 1279 | mutex_unlock(&cgroup_mutex); |
1280 | mutex_unlock(&cgroup_tree_mutex); | ||
1266 | mutex_unlock(&cgrp->dentry->d_inode->i_mutex); | 1281 | mutex_unlock(&cgrp->dentry->d_inode->i_mutex); |
1267 | return ret; | 1282 | return ret; |
1268 | } | 1283 | } |
@@ -1494,6 +1509,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, | |||
1494 | inode = sb->s_root->d_inode; | 1509 | inode = sb->s_root->d_inode; |
1495 | 1510 | ||
1496 | mutex_lock(&inode->i_mutex); | 1511 | mutex_lock(&inode->i_mutex); |
1512 | mutex_lock(&cgroup_tree_mutex); | ||
1497 | mutex_lock(&cgroup_mutex); | 1513 | mutex_lock(&cgroup_mutex); |
1498 | 1514 | ||
1499 | ret = idr_alloc(&root->cgroup_idr, root_cgrp, 0, 1, GFP_KERNEL); | 1515 | ret = idr_alloc(&root->cgroup_idr, root_cgrp, 0, 1, GFP_KERNEL); |
@@ -1568,6 +1584,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, | |||
1568 | BUG_ON(root->number_of_cgroups != 1); | 1584 | BUG_ON(root->number_of_cgroups != 1); |
1569 | 1585 | ||
1570 | mutex_unlock(&cgroup_mutex); | 1586 | mutex_unlock(&cgroup_mutex); |
1587 | mutex_unlock(&cgroup_tree_mutex); | ||
1571 | mutex_unlock(&inode->i_mutex); | 1588 | mutex_unlock(&inode->i_mutex); |
1572 | } else { | 1589 | } else { |
1573 | /* | 1590 | /* |
@@ -1598,6 +1615,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, | |||
1598 | unlock_drop: | 1615 | unlock_drop: |
1599 | cgroup_exit_root_id(root); | 1616 | cgroup_exit_root_id(root); |
1600 | mutex_unlock(&cgroup_mutex); | 1617 | mutex_unlock(&cgroup_mutex); |
1618 | mutex_unlock(&cgroup_tree_mutex); | ||
1601 | mutex_unlock(&inode->i_mutex); | 1619 | mutex_unlock(&inode->i_mutex); |
1602 | drop_new_super: | 1620 | drop_new_super: |
1603 | deactivate_locked_super(sb); | 1621 | deactivate_locked_super(sb); |
@@ -1620,6 +1638,7 @@ static void cgroup_kill_sb(struct super_block *sb) | |||
1620 | BUG_ON(!list_empty(&cgrp->children)); | 1638 | BUG_ON(!list_empty(&cgrp->children)); |
1621 | 1639 | ||
1622 | mutex_lock(&cgrp->dentry->d_inode->i_mutex); | 1640 | mutex_lock(&cgrp->dentry->d_inode->i_mutex); |
1641 | mutex_lock(&cgroup_tree_mutex); | ||
1623 | mutex_lock(&cgroup_mutex); | 1642 | mutex_lock(&cgroup_mutex); |
1624 | 1643 | ||
1625 | /* Rebind all subsystems back to the default hierarchy */ | 1644 | /* Rebind all subsystems back to the default hierarchy */ |
@@ -1650,6 +1669,7 @@ static void cgroup_kill_sb(struct super_block *sb) | |||
1650 | cgroup_exit_root_id(root); | 1669 | cgroup_exit_root_id(root); |
1651 | 1670 | ||
1652 | mutex_unlock(&cgroup_mutex); | 1671 | mutex_unlock(&cgroup_mutex); |
1672 | mutex_unlock(&cgroup_tree_mutex); | ||
1653 | mutex_unlock(&cgrp->dentry->d_inode->i_mutex); | 1673 | mutex_unlock(&cgrp->dentry->d_inode->i_mutex); |
1654 | 1674 | ||
1655 | simple_xattrs_free(&cgrp->xattrs); | 1675 | simple_xattrs_free(&cgrp->xattrs); |
@@ -2625,7 +2645,7 @@ static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[], | |||
2625 | int ret; | 2645 | int ret; |
2626 | 2646 | ||
2627 | lockdep_assert_held(&cgrp->dentry->d_inode->i_mutex); | 2647 | lockdep_assert_held(&cgrp->dentry->d_inode->i_mutex); |
2628 | lockdep_assert_held(&cgroup_mutex); | 2648 | lockdep_assert_held(&cgroup_tree_mutex); |
2629 | 2649 | ||
2630 | for (cft = cfts; cft->name[0] != '\0'; cft++) { | 2650 | for (cft = cfts; cft->name[0] != '\0'; cft++) { |
2631 | /* does cft->flags tell us to skip this file on @cgrp? */ | 2651 | /* does cft->flags tell us to skip this file on @cgrp? */ |
@@ -2659,6 +2679,7 @@ static void cgroup_cfts_prepare(void) | |||
2659 | * Instead, we use css_for_each_descendant_pre() and drop RCU read | 2679 | * Instead, we use css_for_each_descendant_pre() and drop RCU read |
2660 | * lock before calling cgroup_addrm_files(). | 2680 | * lock before calling cgroup_addrm_files(). |
2661 | */ | 2681 | */ |
2682 | mutex_lock(&cgroup_tree_mutex); | ||
2662 | mutex_lock(&cgroup_mutex); | 2683 | mutex_lock(&cgroup_mutex); |
2663 | } | 2684 | } |
2664 | 2685 | ||
@@ -2679,6 +2700,7 @@ static int cgroup_cfts_commit(struct cftype *cfts, bool is_add) | |||
2679 | if (!cfts || ss->root == &cgroup_dummy_root || | 2700 | if (!cfts || ss->root == &cgroup_dummy_root || |
2680 | !atomic_inc_not_zero(&sb->s_active)) { | 2701 | !atomic_inc_not_zero(&sb->s_active)) { |
2681 | mutex_unlock(&cgroup_mutex); | 2702 | mutex_unlock(&cgroup_mutex); |
2703 | mutex_unlock(&cgroup_tree_mutex); | ||
2682 | return 0; | 2704 | return 0; |
2683 | } | 2705 | } |
2684 | 2706 | ||
@@ -2702,7 +2724,9 @@ static int cgroup_cfts_commit(struct cftype *cfts, bool is_add) | |||
2702 | prev = cgrp->dentry; | 2724 | prev = cgrp->dentry; |
2703 | 2725 | ||
2704 | mutex_unlock(&cgroup_mutex); | 2726 | mutex_unlock(&cgroup_mutex); |
2727 | mutex_unlock(&cgroup_tree_mutex); | ||
2705 | mutex_lock(&inode->i_mutex); | 2728 | mutex_lock(&inode->i_mutex); |
2729 | mutex_lock(&cgroup_tree_mutex); | ||
2706 | mutex_lock(&cgroup_mutex); | 2730 | mutex_lock(&cgroup_mutex); |
2707 | if (cgrp->serial_nr < update_before && !cgroup_is_dead(cgrp)) | 2731 | if (cgrp->serial_nr < update_before && !cgroup_is_dead(cgrp)) |
2708 | ret = cgroup_addrm_files(cgrp, cfts, is_add); | 2732 | ret = cgroup_addrm_files(cgrp, cfts, is_add); |
@@ -2711,6 +2735,7 @@ static int cgroup_cfts_commit(struct cftype *cfts, bool is_add) | |||
2711 | break; | 2735 | break; |
2712 | } | 2736 | } |
2713 | mutex_unlock(&cgroup_mutex); | 2737 | mutex_unlock(&cgroup_mutex); |
2738 | mutex_unlock(&cgroup_tree_mutex); | ||
2714 | dput(prev); | 2739 | dput(prev); |
2715 | deactivate_super(sb); | 2740 | deactivate_super(sb); |
2716 | return ret; | 2741 | return ret; |
@@ -2856,7 +2881,7 @@ css_next_child(struct cgroup_subsys_state *pos_css, | |||
2856 | struct cgroup *cgrp = parent_css->cgroup; | 2881 | struct cgroup *cgrp = parent_css->cgroup; |
2857 | struct cgroup *next; | 2882 | struct cgroup *next; |
2858 | 2883 | ||
2859 | cgroup_assert_mutex_or_rcu_locked(); | 2884 | cgroup_assert_mutexes_or_rcu_locked(); |
2860 | 2885 | ||
2861 | /* | 2886 | /* |
2862 | * @pos could already have been removed. Once a cgroup is removed, | 2887 | * @pos could already have been removed. Once a cgroup is removed, |
@@ -2914,7 +2939,7 @@ css_next_descendant_pre(struct cgroup_subsys_state *pos, | |||
2914 | { | 2939 | { |
2915 | struct cgroup_subsys_state *next; | 2940 | struct cgroup_subsys_state *next; |
2916 | 2941 | ||
2917 | cgroup_assert_mutex_or_rcu_locked(); | 2942 | cgroup_assert_mutexes_or_rcu_locked(); |
2918 | 2943 | ||
2919 | /* if first iteration, visit @root */ | 2944 | /* if first iteration, visit @root */ |
2920 | if (!pos) | 2945 | if (!pos) |
@@ -2955,7 +2980,7 @@ css_rightmost_descendant(struct cgroup_subsys_state *pos) | |||
2955 | { | 2980 | { |
2956 | struct cgroup_subsys_state *last, *tmp; | 2981 | struct cgroup_subsys_state *last, *tmp; |
2957 | 2982 | ||
2958 | cgroup_assert_mutex_or_rcu_locked(); | 2983 | cgroup_assert_mutexes_or_rcu_locked(); |
2959 | 2984 | ||
2960 | do { | 2985 | do { |
2961 | last = pos; | 2986 | last = pos; |
@@ -3003,7 +3028,7 @@ css_next_descendant_post(struct cgroup_subsys_state *pos, | |||
3003 | { | 3028 | { |
3004 | struct cgroup_subsys_state *next; | 3029 | struct cgroup_subsys_state *next; |
3005 | 3030 | ||
3006 | cgroup_assert_mutex_or_rcu_locked(); | 3031 | cgroup_assert_mutexes_or_rcu_locked(); |
3007 | 3032 | ||
3008 | /* if first iteration, visit leftmost descendant which may be @root */ | 3033 | /* if first iteration, visit leftmost descendant which may be @root */ |
3009 | if (!pos) | 3034 | if (!pos) |
@@ -3977,6 +4002,7 @@ static int online_css(struct cgroup_subsys_state *css) | |||
3977 | struct cgroup_subsys *ss = css->ss; | 4002 | struct cgroup_subsys *ss = css->ss; |
3978 | int ret = 0; | 4003 | int ret = 0; |
3979 | 4004 | ||
4005 | lockdep_assert_held(&cgroup_tree_mutex); | ||
3980 | lockdep_assert_held(&cgroup_mutex); | 4006 | lockdep_assert_held(&cgroup_mutex); |
3981 | 4007 | ||
3982 | if (ss->css_online) | 4008 | if (ss->css_online) |
@@ -3994,6 +4020,7 @@ static void offline_css(struct cgroup_subsys_state *css) | |||
3994 | { | 4020 | { |
3995 | struct cgroup_subsys *ss = css->ss; | 4021 | struct cgroup_subsys *ss = css->ss; |
3996 | 4022 | ||
4023 | lockdep_assert_held(&cgroup_tree_mutex); | ||
3997 | lockdep_assert_held(&cgroup_mutex); | 4024 | lockdep_assert_held(&cgroup_mutex); |
3998 | 4025 | ||
3999 | if (!(css->flags & CSS_ONLINE)) | 4026 | if (!(css->flags & CSS_ONLINE)) |
@@ -4093,6 +4120,8 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, | |||
4093 | } | 4120 | } |
4094 | rcu_assign_pointer(cgrp->name, name); | 4121 | rcu_assign_pointer(cgrp->name, name); |
4095 | 4122 | ||
4123 | mutex_lock(&cgroup_tree_mutex); | ||
4124 | |||
4096 | /* | 4125 | /* |
4097 | * Only live parents can have children. Note that the liveliness | 4126 | * Only live parents can have children. Note that the liveliness |
4098 | * check isn't strictly necessary because cgroup_mkdir() and | 4127 | * check isn't strictly necessary because cgroup_mkdir() and |
@@ -4102,7 +4131,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, | |||
4102 | */ | 4131 | */ |
4103 | if (!cgroup_lock_live_group(parent)) { | 4132 | if (!cgroup_lock_live_group(parent)) { |
4104 | err = -ENODEV; | 4133 | err = -ENODEV; |
4105 | goto err_free_name; | 4134 | goto err_unlock_tree; |
4106 | } | 4135 | } |
4107 | 4136 | ||
4108 | /* | 4137 | /* |
@@ -4176,6 +4205,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, | |||
4176 | } | 4205 | } |
4177 | 4206 | ||
4178 | mutex_unlock(&cgroup_mutex); | 4207 | mutex_unlock(&cgroup_mutex); |
4208 | mutex_unlock(&cgroup_tree_mutex); | ||
4179 | mutex_unlock(&cgrp->dentry->d_inode->i_mutex); | 4209 | mutex_unlock(&cgrp->dentry->d_inode->i_mutex); |
4180 | 4210 | ||
4181 | return 0; | 4211 | return 0; |
@@ -4186,7 +4216,8 @@ err_free_id: | |||
4186 | deactivate_super(sb); | 4216 | deactivate_super(sb); |
4187 | err_unlock: | 4217 | err_unlock: |
4188 | mutex_unlock(&cgroup_mutex); | 4218 | mutex_unlock(&cgroup_mutex); |
4189 | err_free_name: | 4219 | err_unlock_tree: |
4220 | mutex_unlock(&cgroup_tree_mutex); | ||
4190 | kfree(rcu_dereference_raw(cgrp->name)); | 4221 | kfree(rcu_dereference_raw(cgrp->name)); |
4191 | err_free_cgrp: | 4222 | err_free_cgrp: |
4192 | kfree(cgrp); | 4223 | kfree(cgrp); |
@@ -4195,6 +4226,7 @@ err_free_cgrp: | |||
4195 | err_destroy: | 4226 | err_destroy: |
4196 | cgroup_destroy_locked(cgrp); | 4227 | cgroup_destroy_locked(cgrp); |
4197 | mutex_unlock(&cgroup_mutex); | 4228 | mutex_unlock(&cgroup_mutex); |
4229 | mutex_unlock(&cgroup_tree_mutex); | ||
4198 | mutex_unlock(&dentry->d_inode->i_mutex); | 4230 | mutex_unlock(&dentry->d_inode->i_mutex); |
4199 | return err; | 4231 | return err; |
4200 | } | 4232 | } |
@@ -4217,6 +4249,7 @@ static void css_killed_work_fn(struct work_struct *work) | |||
4217 | container_of(work, struct cgroup_subsys_state, destroy_work); | 4249 | container_of(work, struct cgroup_subsys_state, destroy_work); |
4218 | struct cgroup *cgrp = css->cgroup; | 4250 | struct cgroup *cgrp = css->cgroup; |
4219 | 4251 | ||
4252 | mutex_lock(&cgroup_tree_mutex); | ||
4220 | mutex_lock(&cgroup_mutex); | 4253 | mutex_lock(&cgroup_mutex); |
4221 | 4254 | ||
4222 | /* | 4255 | /* |
@@ -4234,6 +4267,7 @@ static void css_killed_work_fn(struct work_struct *work) | |||
4234 | cgroup_destroy_css_killed(cgrp); | 4267 | cgroup_destroy_css_killed(cgrp); |
4235 | 4268 | ||
4236 | mutex_unlock(&cgroup_mutex); | 4269 | mutex_unlock(&cgroup_mutex); |
4270 | mutex_unlock(&cgroup_tree_mutex); | ||
4237 | 4271 | ||
4238 | /* | 4272 | /* |
4239 | * Put the css refs from kill_css(). Each css holds an extra | 4273 | * Put the css refs from kill_css(). Each css holds an extra |
@@ -4321,6 +4355,7 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) | |||
4321 | int ssid; | 4355 | int ssid; |
4322 | 4356 | ||
4323 | lockdep_assert_held(&d->d_inode->i_mutex); | 4357 | lockdep_assert_held(&d->d_inode->i_mutex); |
4358 | lockdep_assert_held(&cgroup_tree_mutex); | ||
4324 | lockdep_assert_held(&cgroup_mutex); | 4359 | lockdep_assert_held(&cgroup_mutex); |
4325 | 4360 | ||
4326 | /* | 4361 | /* |
@@ -4407,6 +4442,7 @@ static void cgroup_destroy_css_killed(struct cgroup *cgrp) | |||
4407 | struct cgroup *parent = cgrp->parent; | 4442 | struct cgroup *parent = cgrp->parent; |
4408 | struct dentry *d = cgrp->dentry; | 4443 | struct dentry *d = cgrp->dentry; |
4409 | 4444 | ||
4445 | lockdep_assert_held(&cgroup_tree_mutex); | ||
4410 | lockdep_assert_held(&cgroup_mutex); | 4446 | lockdep_assert_held(&cgroup_mutex); |
4411 | 4447 | ||
4412 | /* delete this cgroup from parent->children */ | 4448 | /* delete this cgroup from parent->children */ |
@@ -4422,9 +4458,11 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry) | |||
4422 | { | 4458 | { |
4423 | int ret; | 4459 | int ret; |
4424 | 4460 | ||
4461 | mutex_lock(&cgroup_tree_mutex); | ||
4425 | mutex_lock(&cgroup_mutex); | 4462 | mutex_lock(&cgroup_mutex); |
4426 | ret = cgroup_destroy_locked(dentry->d_fsdata); | 4463 | ret = cgroup_destroy_locked(dentry->d_fsdata); |
4427 | mutex_unlock(&cgroup_mutex); | 4464 | mutex_unlock(&cgroup_mutex); |
4465 | mutex_unlock(&cgroup_tree_mutex); | ||
4428 | 4466 | ||
4429 | return ret; | 4467 | return ret; |
4430 | } | 4468 | } |
@@ -4454,6 +4492,7 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss) | |||
4454 | 4492 | ||
4455 | printk(KERN_INFO "Initializing cgroup subsys %s\n", ss->name); | 4493 | printk(KERN_INFO "Initializing cgroup subsys %s\n", ss->name); |
4456 | 4494 | ||
4495 | mutex_lock(&cgroup_tree_mutex); | ||
4457 | mutex_lock(&cgroup_mutex); | 4496 | mutex_lock(&cgroup_mutex); |
4458 | 4497 | ||
4459 | /* init base cftset */ | 4498 | /* init base cftset */ |
@@ -4482,6 +4521,7 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss) | |||
4482 | BUG_ON(online_css(css)); | 4521 | BUG_ON(online_css(css)); |
4483 | 4522 | ||
4484 | mutex_unlock(&cgroup_mutex); | 4523 | mutex_unlock(&cgroup_mutex); |
4524 | mutex_unlock(&cgroup_tree_mutex); | ||
4485 | } | 4525 | } |
4486 | 4526 | ||
4487 | /** | 4527 | /** |
@@ -5021,7 +5061,7 @@ struct cgroup_subsys_state *css_from_id(int id, struct cgroup_subsys *ss) | |||
5021 | { | 5061 | { |
5022 | struct cgroup *cgrp; | 5062 | struct cgroup *cgrp; |
5023 | 5063 | ||
5024 | cgroup_assert_mutex_or_rcu_locked(); | 5064 | cgroup_assert_mutexes_or_rcu_locked(); |
5025 | 5065 | ||
5026 | cgrp = idr_find(&ss->root->cgroup_idr, id); | 5066 | cgrp = idr_find(&ss->root->cgroup_idr, id); |
5027 | if (cgrp) | 5067 | if (cgrp) |