aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-10-11 13:24:01 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-10-11 13:24:01 -0400
commit0778a9f2dd924c3af41971ba40eec44793aea531 (patch)
tree0df1b3fcfd364447046c88efec32668b20857078
parente5337178f7023bd06a39c06e1fab88817559c0f3 (diff)
parent479adb89a97b0a33e5a9d702119872cc82ca21aa (diff)
Merge branch 'for-4.19-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
Tejun writes: "cgroup fixes for v4.19-rc7 One cgroup2 threaded mode fix for v4.19-rc7. While threaded mode isn't used widely (yet) and the bug requires somewhat convoluted sequence of operations, it causes a userland visible malfunction - EINVAL on a valid attempt to enable threaded mode. This pull request contains the fix" * 'for-4.19-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup: cgroup: Fix dom_cgrp propagation when enabling threaded mode
-rw-r--r--include/linux/cgroup-defs.h1
-rw-r--r--kernel/cgroup/cgroup.c25
2 files changed, 17 insertions, 9 deletions
diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
index ff20b677fb9f..22254c1fe1c5 100644
--- a/include/linux/cgroup-defs.h
+++ b/include/linux/cgroup-defs.h
@@ -412,6 +412,7 @@ struct cgroup {
412 * specific task are charged to the dom_cgrp. 412 * specific task are charged to the dom_cgrp.
413 */ 413 */
414 struct cgroup *dom_cgrp; 414 struct cgroup *dom_cgrp;
415 struct cgroup *old_dom_cgrp; /* used while enabling threaded */
415 416
416 /* per-cpu recursive resource statistics */ 417 /* per-cpu recursive resource statistics */
417 struct cgroup_rstat_cpu __percpu *rstat_cpu; 418 struct cgroup_rstat_cpu __percpu *rstat_cpu;
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index aae10baf1902..4a3dae2a8283 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -2836,11 +2836,12 @@ restart:
2836} 2836}
2837 2837
2838/** 2838/**
2839 * cgroup_save_control - save control masks of a subtree 2839 * cgroup_save_control - save control masks and dom_cgrp of a subtree
2840 * @cgrp: root of the target subtree 2840 * @cgrp: root of the target subtree
2841 * 2841 *
2842 * Save ->subtree_control and ->subtree_ss_mask to the respective old_ 2842 * Save ->subtree_control, ->subtree_ss_mask and ->dom_cgrp to the
2843 * prefixed fields for @cgrp's subtree including @cgrp itself. 2843 * respective old_ prefixed fields for @cgrp's subtree including @cgrp
2844 * itself.
2844 */ 2845 */
2845static void cgroup_save_control(struct cgroup *cgrp) 2846static void cgroup_save_control(struct cgroup *cgrp)
2846{ 2847{
@@ -2850,6 +2851,7 @@ static void cgroup_save_control(struct cgroup *cgrp)
2850 cgroup_for_each_live_descendant_pre(dsct, d_css, cgrp) { 2851 cgroup_for_each_live_descendant_pre(dsct, d_css, cgrp) {
2851 dsct->old_subtree_control = dsct->subtree_control; 2852 dsct->old_subtree_control = dsct->subtree_control;
2852 dsct->old_subtree_ss_mask = dsct->subtree_ss_mask; 2853 dsct->old_subtree_ss_mask = dsct->subtree_ss_mask;
2854 dsct->old_dom_cgrp = dsct->dom_cgrp;
2853 } 2855 }
2854} 2856}
2855 2857
@@ -2875,11 +2877,12 @@ static void cgroup_propagate_control(struct cgroup *cgrp)
2875} 2877}
2876 2878
2877/** 2879/**
2878 * cgroup_restore_control - restore control masks of a subtree 2880 * cgroup_restore_control - restore control masks and dom_cgrp of a subtree
2879 * @cgrp: root of the target subtree 2881 * @cgrp: root of the target subtree
2880 * 2882 *
2881 * Restore ->subtree_control and ->subtree_ss_mask from the respective old_ 2883 * Restore ->subtree_control, ->subtree_ss_mask and ->dom_cgrp from the
2882 * prefixed fields for @cgrp's subtree including @cgrp itself. 2884 * respective old_ prefixed fields for @cgrp's subtree including @cgrp
2885 * itself.
2883 */ 2886 */
2884static void cgroup_restore_control(struct cgroup *cgrp) 2887static void cgroup_restore_control(struct cgroup *cgrp)
2885{ 2888{
@@ -2889,6 +2892,7 @@ static void cgroup_restore_control(struct cgroup *cgrp)
2889 cgroup_for_each_live_descendant_post(dsct, d_css, cgrp) { 2892 cgroup_for_each_live_descendant_post(dsct, d_css, cgrp) {
2890 dsct->subtree_control = dsct->old_subtree_control; 2893 dsct->subtree_control = dsct->old_subtree_control;
2891 dsct->subtree_ss_mask = dsct->old_subtree_ss_mask; 2894 dsct->subtree_ss_mask = dsct->old_subtree_ss_mask;
2895 dsct->dom_cgrp = dsct->old_dom_cgrp;
2892 } 2896 }
2893} 2897}
2894 2898
@@ -3196,6 +3200,8 @@ static int cgroup_enable_threaded(struct cgroup *cgrp)
3196{ 3200{
3197 struct cgroup *parent = cgroup_parent(cgrp); 3201 struct cgroup *parent = cgroup_parent(cgrp);
3198 struct cgroup *dom_cgrp = parent->dom_cgrp; 3202 struct cgroup *dom_cgrp = parent->dom_cgrp;
3203 struct cgroup *dsct;
3204 struct cgroup_subsys_state *d_css;
3199 int ret; 3205 int ret;
3200 3206
3201 lockdep_assert_held(&cgroup_mutex); 3207 lockdep_assert_held(&cgroup_mutex);
@@ -3225,12 +3231,13 @@ static int cgroup_enable_threaded(struct cgroup *cgrp)
3225 */ 3231 */
3226 cgroup_save_control(cgrp); 3232 cgroup_save_control(cgrp);
3227 3233
3228 cgrp->dom_cgrp = dom_cgrp; 3234 cgroup_for_each_live_descendant_pre(dsct, d_css, cgrp)
3235 if (dsct == cgrp || cgroup_is_threaded(dsct))
3236 dsct->dom_cgrp = dom_cgrp;
3237
3229 ret = cgroup_apply_control(cgrp); 3238 ret = cgroup_apply_control(cgrp);
3230 if (!ret) 3239 if (!ret)
3231 parent->nr_threaded_children++; 3240 parent->nr_threaded_children++;
3232 else
3233 cgrp->dom_cgrp = cgrp;
3234 3241
3235 cgroup_finalize_control(cgrp, ret); 3242 cgroup_finalize_control(cgrp, ret);
3236 return ret; 3243 return ret;