aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cgroup.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2014-02-08 10:26:34 -0500
committerTejun Heo <tj@kernel.org>2014-02-08 10:26:34 -0500
commit48573a893303986e3b0b2974d6fb11f3d1bb7064 (patch)
treea01edf5728485e7637a25b08020f210a3ae0d67e /kernel/cgroup.c
parentb58c89986a77a23658682a100eb15d8edb571ebb (diff)
cgroup: fix locking in cgroup_cfts_commit()
cgroup_cfts_commit() walks the cgroup hierarchy that the target subsystem is attached to and tries to apply the file changes. Due to the convolution with inode locking, it can't keep cgroup_mutex locked while iterating. It currently holds only RCU read lock around the actual iteration and then pins the found cgroup using dget(). Unfortunately, this is incorrect. Although the iteration does check cgroup_is_dead() before invoking dget(), there's nothing which prevents the dentry from going away inbetween. Note that this is different from the usual css iterations where css_tryget() is used to pin the css - css_tryget() tests whether the css can be pinned and fails if not. The problem can be solved by simply holding cgroup_mutex instead of RCU read lock around the iteration, which actually reduces LOC. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Li Zefan <lizefan@huawei.com> Cc: stable@vger.kernel.org
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r--kernel/cgroup.c11
1 files changed, 2 insertions, 9 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 0eb7b868e1ab..3edf7163b84f 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -2763,10 +2763,7 @@ static int cgroup_cfts_commit(struct cftype *cfts, bool is_add)
2763 */ 2763 */
2764 update_before = cgroup_serial_nr_next; 2764 update_before = cgroup_serial_nr_next;
2765 2765
2766 mutex_unlock(&cgroup_mutex);
2767
2768 /* add/rm files for all cgroups created before */ 2766 /* add/rm files for all cgroups created before */
2769 rcu_read_lock();
2770 css_for_each_descendant_pre(css, cgroup_css(root, ss)) { 2767 css_for_each_descendant_pre(css, cgroup_css(root, ss)) {
2771 struct cgroup *cgrp = css->cgroup; 2768 struct cgroup *cgrp = css->cgroup;
2772 2769
@@ -2775,23 +2772,19 @@ static int cgroup_cfts_commit(struct cftype *cfts, bool is_add)
2775 2772
2776 inode = cgrp->dentry->d_inode; 2773 inode = cgrp->dentry->d_inode;
2777 dget(cgrp->dentry); 2774 dget(cgrp->dentry);
2778 rcu_read_unlock();
2779
2780 dput(prev); 2775 dput(prev);
2781 prev = cgrp->dentry; 2776 prev = cgrp->dentry;
2782 2777
2778 mutex_unlock(&cgroup_mutex);
2783 mutex_lock(&inode->i_mutex); 2779 mutex_lock(&inode->i_mutex);
2784 mutex_lock(&cgroup_mutex); 2780 mutex_lock(&cgroup_mutex);
2785 if (cgrp->serial_nr < update_before && !cgroup_is_dead(cgrp)) 2781 if (cgrp->serial_nr < update_before && !cgroup_is_dead(cgrp))
2786 ret = cgroup_addrm_files(cgrp, cfts, is_add); 2782 ret = cgroup_addrm_files(cgrp, cfts, is_add);
2787 mutex_unlock(&cgroup_mutex);
2788 mutex_unlock(&inode->i_mutex); 2783 mutex_unlock(&inode->i_mutex);
2789
2790 rcu_read_lock();
2791 if (ret) 2784 if (ret)
2792 break; 2785 break;
2793 } 2786 }
2794 rcu_read_unlock(); 2787 mutex_unlock(&cgroup_mutex);
2795 dput(prev); 2788 dput(prev);
2796 deactivate_super(sb); 2789 deactivate_super(sb);
2797 return ret; 2790 return ret;