aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-06-28 19:24:11 -0400
committerTejun Heo <tj@kernel.org>2013-07-12 15:34:01 -0400
commit9ccece80ae19ed42439fc0ced76858f189cd41e8 (patch)
tree8bab4d142410db148b2a7cbb4029d3b8eb1ab29a
parentb1f28d3109349899e87377e89f9d8ab5bc95ec57 (diff)
cgroup: fix cgroup_add_cftypes() error handling
cgroup_add_cftypes() uses cgroup_cfts_commit() to actually create the files; however, both functions ignore actual file creation errors and just assume success. This can lead to, for example, blkio hierarchy with some of the cgroups with only subset of interface files populated after cfq-iosched is loaded under heavy memory pressure, which is nasty. This patch updates cgroup_cfts_commit() and cgroup_add_cftypes() to guarantee that all files are created on success and no file is created on failure. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Li Zefan <lizefan@huawei.com>
-rw-r--r--kernel/cgroup.c26
1 files changed, 18 insertions, 8 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 9b16d75bec63..36c0ccc921f4 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -2836,8 +2836,8 @@ static void cgroup_cfts_prepare(void)
2836 mutex_lock(&cgroup_mutex); 2836 mutex_lock(&cgroup_mutex);
2837} 2837}
2838 2838
2839static void cgroup_cfts_commit(struct cgroup_subsys *ss, 2839static int cgroup_cfts_commit(struct cgroup_subsys *ss,
2840 struct cftype *cfts, bool is_add) 2840 struct cftype *cfts, bool is_add)
2841 __releases(&cgroup_mutex) 2841 __releases(&cgroup_mutex)
2842{ 2842{
2843 LIST_HEAD(pending); 2843 LIST_HEAD(pending);
@@ -2846,12 +2846,13 @@ static void cgroup_cfts_commit(struct cgroup_subsys *ss,
2846 struct dentry *prev = NULL; 2846 struct dentry *prev = NULL;
2847 struct inode *inode; 2847 struct inode *inode;
2848 u64 update_before; 2848 u64 update_before;
2849 int ret = 0;
2849 2850
2850 /* %NULL @cfts indicates abort and don't bother if @ss isn't attached */ 2851 /* %NULL @cfts indicates abort and don't bother if @ss isn't attached */
2851 if (!cfts || ss->root == &cgroup_dummy_root || 2852 if (!cfts || ss->root == &cgroup_dummy_root ||
2852 !atomic_inc_not_zero(&sb->s_active)) { 2853 !atomic_inc_not_zero(&sb->s_active)) {
2853 mutex_unlock(&cgroup_mutex); 2854 mutex_unlock(&cgroup_mutex);
2854 return; 2855 return 0;
2855 } 2856 }
2856 2857
2857 /* 2858 /*
@@ -2867,10 +2868,13 @@ static void cgroup_cfts_commit(struct cgroup_subsys *ss,
2867 inode = root->dentry->d_inode; 2868 inode = root->dentry->d_inode;
2868 mutex_lock(&inode->i_mutex); 2869 mutex_lock(&inode->i_mutex);
2869 mutex_lock(&cgroup_mutex); 2870 mutex_lock(&cgroup_mutex);
2870 cgroup_addrm_files(root, ss, cfts, is_add); 2871 ret = cgroup_addrm_files(root, ss, cfts, is_add);
2871 mutex_unlock(&cgroup_mutex); 2872 mutex_unlock(&cgroup_mutex);
2872 mutex_unlock(&inode->i_mutex); 2873 mutex_unlock(&inode->i_mutex);
2873 2874
2875 if (ret)
2876 goto out_deact;
2877
2874 /* add/rm files for all cgroups created before */ 2878 /* add/rm files for all cgroups created before */
2875 rcu_read_lock(); 2879 rcu_read_lock();
2876 cgroup_for_each_descendant_pre(cgrp, root) { 2880 cgroup_for_each_descendant_pre(cgrp, root) {
@@ -2887,15 +2891,19 @@ static void cgroup_cfts_commit(struct cgroup_subsys *ss,
2887 mutex_lock(&inode->i_mutex); 2891 mutex_lock(&inode->i_mutex);
2888 mutex_lock(&cgroup_mutex); 2892 mutex_lock(&cgroup_mutex);
2889 if (cgrp->serial_nr < update_before && !cgroup_is_dead(cgrp)) 2893 if (cgrp->serial_nr < update_before && !cgroup_is_dead(cgrp))
2890 cgroup_addrm_files(cgrp, ss, cfts, is_add); 2894 ret = cgroup_addrm_files(cgrp, ss, cfts, is_add);
2891 mutex_unlock(&cgroup_mutex); 2895 mutex_unlock(&cgroup_mutex);
2892 mutex_unlock(&inode->i_mutex); 2896 mutex_unlock(&inode->i_mutex);
2893 2897
2894 rcu_read_lock(); 2898 rcu_read_lock();
2899 if (ret)
2900 break;
2895 } 2901 }
2896 rcu_read_unlock(); 2902 rcu_read_unlock();
2897 dput(prev); 2903 dput(prev);
2904out_deact:
2898 deactivate_super(sb); 2905 deactivate_super(sb);
2906 return ret;
2899} 2907}
2900 2908
2901/** 2909/**
@@ -2915,6 +2923,7 @@ static void cgroup_cfts_commit(struct cgroup_subsys *ss,
2915int cgroup_add_cftypes(struct cgroup_subsys *ss, struct cftype *cfts) 2923int cgroup_add_cftypes(struct cgroup_subsys *ss, struct cftype *cfts)
2916{ 2924{
2917 struct cftype_set *set; 2925 struct cftype_set *set;
2926 int ret;
2918 2927
2919 set = kzalloc(sizeof(*set), GFP_KERNEL); 2928 set = kzalloc(sizeof(*set), GFP_KERNEL);
2920 if (!set) 2929 if (!set)
@@ -2923,9 +2932,10 @@ int cgroup_add_cftypes(struct cgroup_subsys *ss, struct cftype *cfts)
2923 cgroup_cfts_prepare(); 2932 cgroup_cfts_prepare();
2924 set->cfts = cfts; 2933 set->cfts = cfts;
2925 list_add_tail(&set->node, &ss->cftsets); 2934 list_add_tail(&set->node, &ss->cftsets);
2926 cgroup_cfts_commit(ss, cfts, true); 2935 ret = cgroup_cfts_commit(ss, cfts, true);
2927 2936 if (ret)
2928 return 0; 2937 cgroup_rm_cftypes(ss, cfts);
2938 return ret;
2929} 2939}
2930EXPORT_SYMBOL_GPL(cgroup_add_cftypes); 2940EXPORT_SYMBOL_GPL(cgroup_add_cftypes);
2931 2941