Pull cgroup updates from Tejun Heo: - cgroup.kill is added which implements atomic killing of the whole subtree. Down the line, this should be able to replace the multiple userland implementations of "keep killing till empty". - PSI can now be turned off at boot time to avoid overhead for configurations which don't care about PSI. * 'for-5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup: cgroup: make per-cgroup pressure stall tracking configurable cgroup: Fix kernel-doc cgroup: inline cgroup_task_freeze() tests/cgroup: test cgroup.kill tests/cgroup: move cg_wait_for(), cg_prepare_for_wait() tests/cgroup: use cgroup.kill in cg_killall() docs/cgroup: add entry for cgroup.kill cgroup: introduce cgroup.kill
Showing the changes to kernel (3 of 13 files). Show all
Unified · Split
| @@ -209,6 +209,22 @@ struct cgroup_namespace init_cgroup_ns = { · 208 unmodified lines | ||
| 209 | 209 | static struct file_system_type cgroup2_fs_type; |
| 210 | 210 | static struct cftype cgroup_base_files[]; |
| 211 | 211 | |
| 212 | +/* cgroup optional features */ | |
| 213 | +enum cgroup_opt_features { | |
| 214 | +#ifdef CONFIG_PSI | |
| 215 | + OPT_FEATURE_PRESSURE, | |
| 216 | +#endif | |
| 217 | + OPT_FEATURE_COUNT | |
| 218 | +}; | |
| 219 | + | |
| 220 | +static const char *cgroup_opt_feature_names[OPT_FEATURE_COUNT] = { | |
| 221 | +#ifdef CONFIG_PSI | |
| 222 | + "pressure", | |
| 223 | +#endif | |
| 224 | +}; | |
| 225 | + | |
| 226 | +static u16 cgroup_feature_disable_mask __read_mostly; | |
| 227 | + | |
| 212 | 228 | static int cgroup_apply_control(struct cgroup *cgrp); |
| 213 | 229 | static void cgroup_finalize_control(struct cgroup *cgrp, int ret); |
| 214 | 230 | static void css_task_iter_skip(struct css_task_iter *it, |
| @@ -2390,7 +2406,7 @@ struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset, · 2175 unmodified lines | ||
| 2390 | 2406 | } |
| 2391 | 2407 | |
| 2392 | 2408 | /** |
| 2393 | − * cgroup_taskset_migrate - migrate a taskset | |
| 2409 | + * cgroup_migrate_execute - migrate a taskset | |
| 2394 | 2410 | * @mgctx: migration context |
| 2395 | 2411 | * |
| 2396 | 2412 | * Migrate tasks in @mgctx as setup by migration preparation functions. |
| @@ -3632,6 +3648,18 @@ static void cgroup_pressure_release(struct kernfs_open_file *of) · 1235 unmodified lines | ||
| 3632 | 3648 | { |
| 3633 | 3649 | psi_trigger_replace(&of->priv, NULL); |
| 3634 | 3650 | } |
| 3651 | + | |
| 3652 | +bool cgroup_psi_enabled(void) | |
| 3653 | +{ | |
| 3654 | + return (cgroup_feature_disable_mask & (1 << OPT_FEATURE_PRESSURE)) == 0; | |
| 3655 | +} | |
| 3656 | + | |
| 3657 | +#else /* CONFIG_PSI */ | |
| 3658 | +bool cgroup_psi_enabled(void) | |
| 3659 | +{ | |
| 3660 | + return false; | |
| 3661 | +} | |
| 3662 | + | |
| 3635 | 3663 | #endif /* CONFIG_PSI */ |
| 3636 | 3664 | |
| 3637 | 3665 | static int cgroup_freeze_show(struct seq_file *seq, void *v) |
| @@ -3668,6 +3696,80 @@ static ssize_t cgroup_freeze_write(struct kernfs_open_file *of, · 30 unmodified lines | ||
| 3668 | 3696 | return nbytes; |
| 3669 | 3697 | } |
| 3670 | 3698 | |
| 3699 | +static void __cgroup_kill(struct cgroup *cgrp) | |
| 3700 | +{ | |
| 3701 | + struct css_task_iter it; | |
| 3702 | + struct task_struct *task; | |
| 3703 | + | |
| 3704 | + lockdep_assert_held(&cgroup_mutex); | |
| 3705 | + | |
| 3706 | + spin_lock_irq(&css_set_lock); | |
| 3707 | + set_bit(CGRP_KILL, &cgrp->flags); | |
| 3708 | + spin_unlock_irq(&css_set_lock); | |
| 3709 | + | |
| 3710 | + css_task_iter_start(&cgrp->self, CSS_TASK_ITER_PROCS | CSS_TASK_ITER_THREADED, &it); | |
| 3711 | + while ((task = css_task_iter_next(&it))) { | |
| 3712 | + /* Ignore kernel threads here. */ | |
| 3713 | + if (task->flags & PF_KTHREAD) | |
| 3714 | + continue; | |
| 3715 | + | |
| 3716 | + /* Skip tasks that are already dying. */ | |
| 3717 | + if (__fatal_signal_pending(task)) | |
| 3718 | + continue; | |
| 3719 | + | |
| 3720 | + send_sig(SIGKILL, task, 0); | |
| 3721 | + } | |
| 3722 | + css_task_iter_end(&it); | |
| 3723 | + | |
| 3724 | + spin_lock_irq(&css_set_lock); | |
| 3725 | + clear_bit(CGRP_KILL, &cgrp->flags); | |
| 3726 | + spin_unlock_irq(&css_set_lock); | |
| 3727 | +} | |
| 3728 | + | |
| 3729 | +static void cgroup_kill(struct cgroup *cgrp) | |
| 3730 | +{ | |
| 3731 | + struct cgroup_subsys_state *css; | |
| 3732 | + struct cgroup *dsct; | |
| 3733 | + | |
| 3734 | + lockdep_assert_held(&cgroup_mutex); | |
| 3735 | + | |
| 3736 | + cgroup_for_each_live_descendant_pre(dsct, css, cgrp) | |
| 3737 | + __cgroup_kill(dsct); | |
| 3738 | +} | |
| 3739 | + | |
| 3740 | +static ssize_t cgroup_kill_write(struct kernfs_open_file *of, char *buf, | |
| 3741 | + size_t nbytes, loff_t off) | |
| 3742 | +{ | |
| 3743 | + ssize_t ret = 0; | |
| 3744 | + int kill; | |
| 3745 | + struct cgroup *cgrp; | |
| 3746 | + | |
| 3747 | + ret = kstrtoint(strstrip(buf), 0, &kill); | |
| 3748 | + if (ret) | |
| 3749 | + return ret; | |
| 3750 | + | |
| 3751 | + if (kill != 1) | |
| 3752 | + return -ERANGE; | |
| 3753 | + | |
| 3754 | + cgrp = cgroup_kn_lock_live(of->kn, false); | |
| 3755 | + if (!cgrp) | |
| 3756 | + return -ENOENT; | |
| 3757 | + | |
| 3758 | + /* | |
| 3759 | + * Killing is a process directed operation, i.e. the whole thread-group | |
| 3760 | + * is taken down so act like we do for cgroup.procs and only make this | |
| 3761 | + * writable in non-threaded cgroups. | |
| 3762 | + */ | |
| 3763 | + if (cgroup_is_threaded(cgrp)) | |
| 3764 | + ret = -EOPNOTSUPP; | |
| 3765 | + else | |
| 3766 | + cgroup_kill(cgrp); | |
| 3767 | + | |
| 3768 | + cgroup_kn_unlock(of->kn); | |
| 3769 | + | |
| 3770 | + return ret ?: nbytes; | |
| 3771 | +} | |
| 3772 | + | |
| 3671 | 3773 | static int cgroup_file_open(struct kernfs_open_file *of) |
| 3672 | 3774 | { |
| 3673 | 3775 | struct cftype *cft = of_cft(of); |
| @@ -3882,6 +3984,8 @@ static int cgroup_addrm_files(struct cgroup_subsys_state *css, · 208 unmodified lines | ||
| 3882 | 3984 | restart: |
| 3883 | 3985 | for (cft = cfts; cft != cft_end && cft->name[0] != '\0'; cft++) { |
| 3884 | 3986 | /* does cft->flags tell us to skip this file on @cgrp? */ |
| 3987 | + if ((cft->flags & CFTYPE_PRESSURE) && !cgroup_psi_enabled()) | |
| 3988 | + continue; | |
| 3885 | 3989 | if ((cft->flags & __CFTYPE_ONLY_ON_DFL) && !cgroup_on_dfl(cgrp)) |
| 3886 | 3990 | continue; |
| 3887 | 3991 | if ((cft->flags & __CFTYPE_NOT_ON_DFL) && cgroup_on_dfl(cgrp)) |
| @@ -3959,6 +4063,9 @@ static int cgroup_init_cftypes(struct cgroup_subsys *ss, struct cftype *cfts) · 71 unmodified lines | ||
| 3959 | 4063 | |
| 3960 | 4064 | WARN_ON(cft->ss || cft->kf_ops); |
| 3961 | 4065 | |
| 4066 | + if ((cft->flags & CFTYPE_PRESSURE) && !cgroup_psi_enabled()) | |
| 4067 | + continue; | |
| 4068 | + | |
| 3962 | 4069 | if (cft->seq_start) |
| 3963 | 4070 | kf_ops = &cgroup_kf_ops; |
| 3964 | 4071 | else |
| @@ -4860,6 +4967,11 @@ static struct cftype cgroup_base_files[] = { · 895 unmodified lines | ||
| 4860 | 4967 | .seq_show = cgroup_freeze_show, |
| 4861 | 4968 | .write = cgroup_freeze_write, |
| 4862 | 4969 | }, |
| 4970 | + { | |
| 4971 | + .name = "cgroup.kill", | |
| 4972 | + .flags = CFTYPE_NOT_ON_ROOT, | |
| 4973 | + .write = cgroup_kill_write, | |
| 4974 | + }, | |
| 4863 | 4975 | { |
| 4864 | 4976 | .name = "cpu.stat", |
| 4865 | 4977 | .seq_show = cpu_stat_show, |
| @@ -4867,6 +4979,7 @@ static struct cftype cgroup_base_files[] = { · 1 unmodified line | ||
| 4867 | 4979 | #ifdef CONFIG_PSI |
| 4868 | 4980 | { |
| 4869 | 4981 | .name = "io.pressure", |
| 4982 | + .flags = CFTYPE_PRESSURE, | |
| 4870 | 4983 | .seq_show = cgroup_io_pressure_show, |
| 4871 | 4984 | .write = cgroup_io_pressure_write, |
| 4872 | 4985 | .poll = cgroup_pressure_poll, |
| @@ -4874,6 +4987,7 @@ static struct cftype cgroup_base_files[] = { · 1 unmodified line | ||
| 4874 | 4987 | }, |
| 4875 | 4988 | { |
| 4876 | 4989 | .name = "memory.pressure", |
| 4990 | + .flags = CFTYPE_PRESSURE, | |
| 4877 | 4991 | .seq_show = cgroup_memory_pressure_show, |
| 4878 | 4992 | .write = cgroup_memory_pressure_write, |
| 4879 | 4993 | .poll = cgroup_pressure_poll, |
| @@ -4881,6 +4995,7 @@ static struct cftype cgroup_base_files[] = { · 1 unmodified line | ||
| 4881 | 4995 | }, |
| 4882 | 4996 | { |
| 4883 | 4997 | .name = "cpu.pressure", |
| 4998 | + .flags = CFTYPE_PRESSURE, | |
| 4884 | 4999 | .seq_show = cgroup_cpu_pressure_show, |
| 4885 | 5000 | .write = cgroup_cpu_pressure_write, |
| 4886 | 5001 | .poll = cgroup_pressure_poll, |
| @@ -6080,6 +6195,8 @@ void cgroup_post_fork(struct task_struct *child, · 1193 unmodified lines | ||
| 6080 | 6195 | struct kernel_clone_args *kargs) |
| 6081 | 6196 | __releases(&cgroup_threadgroup_rwsem) __releases(&cgroup_mutex) |
| 6082 | 6197 | { |
| 6198 | + unsigned long cgrp_flags = 0; | |
| 6199 | + bool kill = false; | |
| 6083 | 6200 | struct cgroup_subsys *ss; |
| 6084 | 6201 | struct css_set *cset; |
| 6085 | 6202 | int i; |
| @@ -6091,6 +6208,11 @@ void cgroup_post_fork(struct task_struct *child, · 5 unmodified lines | ||
| 6091 | 6208 | |
| 6092 | 6209 | /* init tasks are special, only link regular threads */ |
| 6093 | 6210 | if (likely(child->pid)) { |
| 6211 | + if (kargs->cgrp) | |
| 6212 | + cgrp_flags = kargs->cgrp->flags; | |
| 6213 | + else | |
| 6214 | + cgrp_flags = cset->dfl_cgrp->flags; | |
| 6215 | + | |
| 6094 | 6216 | WARN_ON_ONCE(!list_empty(&child->cg_list)); |
| 6095 | 6217 | cset->nr_tasks++; |
| 6096 | 6218 | css_set_move_task(child, NULL, cset, false); |
| @@ -6099,23 +6221,32 @@ void cgroup_post_fork(struct task_struct *child, · 2 unmodified lines | ||
| 6099 | 6221 | cset = NULL; |
| 6100 | 6222 | } |
| 6101 | 6223 | |
| 6102 | − /* | |
| 6103 | − * If the cgroup has to be frozen, the new task has too. Let's set | |
| 6104 | − * the JOBCTL_TRAP_FREEZE jobctl bit to get the task into the | |
| 6105 | − * frozen state. | |
| 6106 | − */ | |
| 6107 | − if (unlikely(cgroup_task_freeze(child))) { | |
| 6108 | − spin_lock(&child->sighand->siglock); | |
| 6109 | − WARN_ON_ONCE(child->frozen); | |
| 6110 | − child->jobctl |= JOBCTL_TRAP_FREEZE; | |
| 6111 | − spin_unlock(&child->sighand->siglock); | |
| 6224 | + if (!(child->flags & PF_KTHREAD)) { | |
| 6225 | + if (unlikely(test_bit(CGRP_FREEZE, &cgrp_flags))) { | |
| 6226 | + /* | |
| 6227 | + * If the cgroup has to be frozen, the new task has | |
| 6228 | + * too. Let's set the JOBCTL_TRAP_FREEZE jobctl bit to | |
| 6229 | + * get the task into the frozen state. | |
| 6230 | + */ | |
| 6231 | + spin_lock(&child->sighand->siglock); | |
| 6232 | + WARN_ON_ONCE(child->frozen); | |
| 6233 | + child->jobctl |= JOBCTL_TRAP_FREEZE; | |
| 6234 | + spin_unlock(&child->sighand->siglock); | |
| 6235 | + | |
| 6236 | + /* | |
| 6237 | + * Calling cgroup_update_frozen() isn't required here, | |
| 6238 | + * because it will be called anyway a bit later from | |
| 6239 | + * do_freezer_trap(). So we avoid cgroup's transient | |
| 6240 | + * switch from the frozen state and back. | |
| 6241 | + */ | |
| 6242 | + } | |
| 6112 | 6243 | |
| 6113 | 6244 | /* |
| 6114 | − * Calling cgroup_update_frozen() isn't required here, | |
| 6115 | − * because it will be called anyway a bit later from | |
| 6116 | − * do_freezer_trap(). So we avoid cgroup's transient switch | |
| 6117 | − * from the frozen state and back. | |
| 6245 | + * If the cgroup is to be killed notice it now and take the | |
| 6246 | + * child down right after we finished preparing it for | |
| 6247 | + * userspace. | |
| 6118 | 6248 | */ |
| 6249 | + kill = test_bit(CGRP_KILL, &cgrp_flags); | |
| 6119 | 6250 | } |
| 6120 | 6251 | |
| 6121 | 6252 | spin_unlock_irq(&css_set_lock); |
| @@ -6138,6 +6269,10 @@ void cgroup_post_fork(struct task_struct *child, · 16 unmodified lines | ||
| 6138 | 6269 | put_css_set(rcset); |
| 6139 | 6270 | } |
| 6140 | 6271 | |
| 6272 | + /* Cgroup has to be killed so take down child immediately. */ | |
| 6273 | + if (unlikely(kill)) | |
| 6274 | + do_send_sig_info(SIGKILL, SEND_SIG_NOINFO, child, PIDTYPE_TGID); | |
| 6275 | + | |
| 6141 | 6276 | cgroup_css_set_put_fork(kargs); |
| 6142 | 6277 | } |
| 6143 | 6278 | |
| @@ -6163,7 +6298,8 @@ void cgroup_exit(struct task_struct *tsk) · 19 unmodified lines | ||
| 6163 | 6298 | cset->nr_tasks--; |
| 6164 | 6299 | |
| 6165 | 6300 | WARN_ON_ONCE(cgroup_task_frozen(tsk)); |
| 6166 | − if (unlikely(cgroup_task_freeze(tsk))) | |
| 6301 | + if (unlikely(!(tsk->flags & PF_KTHREAD) && | |
| 6302 | + test_bit(CGRP_FREEZE, &task_dfl_cgroup(tsk)->flags))) | |
| 6167 | 6303 | cgroup_update_frozen(task_dfl_cgroup(tsk)); |
| 6168 | 6304 | |
| 6169 | 6305 | spin_unlock_irq(&css_set_lock); |
| @@ -6214,6 +6350,15 @@ static int __init cgroup_disable(char *str) · 44 unmodified lines | ||
| 6214 | 6350 | pr_info("Disabling %s control group subsystem\n", |
| 6215 | 6351 | ss->name); |
| 6216 | 6352 | } |
| 6353 | + | |
| 6354 | + for (i = 0; i < OPT_FEATURE_COUNT; i++) { | |
| 6355 | + if (strcmp(token, cgroup_opt_feature_names[i])) | |
| 6356 | + continue; | |
| 6357 | + cgroup_feature_disable_mask |= 1 << i; | |
| 6358 | + pr_info("Disabling %s control group feature\n", | |
| 6359 | + cgroup_opt_feature_names[i]); | |
| 6360 | + break; | |
| 6361 | + } | |
| 6217 | 6362 | } |
| 6218 | 6363 | return 1; |
| 6219 | 6364 | } |
| @@ -6512,6 +6657,9 @@ static ssize_t show_delegatable_files(struct cftype *files, char *buf, · 292 unmodified lines | ||
| 6512 | 6657 | if (!(cft->flags & CFTYPE_NS_DELEGATABLE)) |
| 6513 | 6658 | continue; |
| 6514 | 6659 | |
| 6660 | + if ((cft->flags & CFTYPE_PRESSURE) && !cgroup_psi_enabled()) | |
| 6661 | + continue; | |
| 6662 | + | |
| 6515 | 6663 | if (prefix) |
| 6516 | 6664 | ret += snprintf(buf + ret, size - ret, "%s.", prefix); |
| 6517 | 6665 | |
| @@ -220,7 +220,7 @@ void cgroup_rstat_flush_irqsafe(struct cgroup *cgrp) · 219 unmodified lines | ||
| 220 | 220 | } |
| 221 | 221 | |
| 222 | 222 | /** |
| 223 | − * cgroup_rstat_flush_begin - flush stats in @cgrp's subtree and hold | |
| 223 | + * cgroup_rstat_flush_hold - flush stats in @cgrp's subtree and hold | |
| 224 | 224 | * @cgrp: target cgroup |
| 225 | 225 | * |
| 226 | 226 | * Flush stats in @cgrp's subtree and prevent further flushes. Must be |
| @@ -148,6 +148,7 @@ · 147 unmodified lines | ||
| 148 | 148 | static int psi_bug __read_mostly; |
| 149 | 149 | |
| 150 | 150 | DEFINE_STATIC_KEY_FALSE(psi_disabled); |
| 151 | +DEFINE_STATIC_KEY_TRUE(psi_cgroups_enabled); | |
| 151 | 152 | |
| 152 | 153 | #ifdef CONFIG_PSI_DEFAULT_DISABLED |
| 153 | 154 | static bool psi_enable; |
| @@ -215,6 +216,9 @@ void __init psi_init(void) · 61 unmodified lines | ||
| 215 | 216 | return; |
| 216 | 217 | } |
| 217 | 218 | |
| 219 | + if (!cgroup_psi_enabled()) | |
| 220 | + static_branch_disable(&psi_cgroups_enabled); | |
| 221 | + | |
| 218 | 222 | psi_period = jiffies_to_nsecs(PSI_FREQ); |
| 219 | 223 | group_init(&psi_system); |
| 220 | 224 | } |
| @@ -748,23 +752,23 @@ static void psi_group_change(struct psi_group *group, int cpu, · 527 unmodified lines | ||
| 748 | 752 | |
| 749 | 753 | static struct psi_group *iterate_groups(struct task_struct *task, void **iter) |
| 750 | 754 | { |
| 755 | + if (*iter == &psi_system) | |
| 756 | + return NULL; | |
| 757 | + | |
| 751 | 758 | #ifdef CONFIG_CGROUPS |
| 752 | − struct cgroup *cgroup = NULL; | |
| 759 | + if (static_branch_likely(&psi_cgroups_enabled)) { | |
| 760 | + struct cgroup *cgroup = NULL; | |
| 753 | 761 | |
| 754 | − if (!*iter) | |
| 755 | − cgroup = task->cgroups->dfl_cgrp; | |
| 756 | − else if (*iter == &psi_system) | |
| 757 | − return NULL; | |
| 758 | − else | |
| 759 | − cgroup = cgroup_parent(*iter); | |
| 762 | + if (!*iter) | |
| 763 | + cgroup = task->cgroups->dfl_cgrp; | |
| 764 | + else | |
| 765 | + cgroup = cgroup_parent(*iter); | |
| 760 | 766 | |
| 761 | − if (cgroup && cgroup_parent(cgroup)) { | |
| 762 | − *iter = cgroup; | |
| 763 | − return cgroup_psi(cgroup); | |
| 767 | + if (cgroup && cgroup_parent(cgroup)) { | |
| 768 | + *iter = cgroup; | |
| 769 | + return cgroup_psi(cgroup); | |
| 770 | + } | |
| 764 | 771 | } |
| 765 | −#else | |
| 766 | − if (*iter) | |
| 767 | − return NULL; | |
| 768 | 772 | #endif |
| 769 | 773 | *iter = &psi_system; |
| 770 | 774 | return &psi_system; |