The test_cgcore_no_internal_process_constraint_on_threads selftest when running with subsystem controlling noise triggers two warnings: > [ 597.443115] WARNING: CPU: 1 PID: 28167 at kernel/cgroup/cgroup.c:3131 cgroup_apply_control_enable+0xe0/0x3f0 > [ 597.443413] WARNING: CPU: 1 PID: 28167 at kernel/cgroup/cgroup.c:3177 cgroup_apply_control_disable+0xa6/0x160 Both stem from a call to cgroup_type_write. The first warning was also triggered by syzkaller. When we're switching cgroup to threaded mode shortly after a subsystem was disabled on it, we can see the respective subsystem css dying there. The warning in cgroup_apply_control_enable is harmless in this case since we're not adding new subsys anyway. The warning in cgroup_apply_control_disable indicates an attempt to kill css of recently disabled subsystem repeatedly. The commit prevents these situations by making cgroup_type_write wait for all dying csses to go away before re-applying subtree controls. When at it, the locations of WARN_ON_ONCE calls are moved so that warning is triggered only when we are about to misuse the dying css.
Unified · Split
| @@ -3055,8 +3055,6 @@ static int cgroup_apply_control_enable(struct cgroup *cgrp) · 3054 unmodified lines | ||
| 3055 | 3055 | for_each_subsys(ss, ssid) { |
| 3056 | 3056 | struct cgroup_subsys_state *css = cgroup_css(dsct, ss); |
| 3057 | 3057 | |
| 3058 | − WARN_ON_ONCE(css && percpu_ref_is_dying(&css->refcnt)); | |
| 3059 | − | |
| 3060 | 3058 | if (!(cgroup_ss_mask(dsct) & (1 << ss->id))) |
| 3061 | 3059 | continue; |
| 3062 | 3060 | |
| @@ -3066,6 +3064,8 @@ static int cgroup_apply_control_enable(struct cgroup *cgrp) · 3 unmodified lines | ||
| 3066 | 3064 | return PTR_ERR(css); |
| 3067 | 3065 | } |
| 3068 | 3066 | |
| 3067 | + WARN_ON_ONCE(percpu_ref_is_dying(&css->refcnt)); | |
| 3068 | + | |
| 3069 | 3069 | if (css_visible(css)) { |
| 3070 | 3070 | ret = css_populate_dir(css); |
| 3071 | 3071 | if (ret) |
| @@ -3101,11 +3101,11 @@ static void cgroup_apply_control_disable(struct cgroup *cgrp) · 29 unmodified lines | ||
| 3101 | 3101 | for_each_subsys(ss, ssid) { |
| 3102 | 3102 | struct cgroup_subsys_state *css = cgroup_css(dsct, ss); |
| 3103 | 3103 | |
| 3104 | − WARN_ON_ONCE(css && percpu_ref_is_dying(&css->refcnt)); | |
| 3105 | − | |
| 3106 | 3104 | if (!css) |
| 3107 | 3105 | continue; |
| 3108 | 3106 | |
| 3107 | + WARN_ON_ONCE(percpu_ref_is_dying(&css->refcnt)); | |
| 3108 | + | |
| 3109 | 3109 | if (css->parent && |
| 3110 | 3110 | !(cgroup_ss_mask(dsct) & (1 << ss->id))) { |
| 3111 | 3111 | kill_css(css); |
| @@ -3392,7 +3392,8 @@ static ssize_t cgroup_type_write(struct kernfs_open_file *of, char *buf, · 280 unmodified lines | ||
| 3392 | 3392 | if (strcmp(strstrip(buf), "threaded")) |
| 3393 | 3393 | return -EINVAL; |
| 3394 | 3394 | |
| 3395 | − cgrp = cgroup_kn_lock_live(of->kn, false); | |
| 3395 | + /* drain dying csses before we re-apply (threaded) subtree control */ | |
| 3396 | + cgrp = cgroup_kn_lock_live(of->kn, true); | |
| 3396 | 3397 | if (!cgrp) |
| 3397 | 3398 | return -ENOENT; |
| 3398 | 3399 | |