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 | static struct file_system_type cgroup2_fs_type; | 209 | static struct file_system_type cgroup2_fs_type; |
| 210 | static struct cftype cgroup_base_files[]; | 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 | static int cgroup_apply_control(struct cgroup *cgrp); | 228 | static int cgroup_apply_control(struct cgroup *cgrp); |
| 213 | static void cgroup_finalize_control(struct cgroup *cgrp, int ret); | 229 | static void cgroup_finalize_control(struct cgroup *cgrp, int ret); |
| 214 | static void css_task_iter_skip(struct css_task_iter *it, | 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 | * @mgctx: migration context | 2410 | * @mgctx: migration context |
| 2395 | * | 2411 | * |
| 2396 | * Migrate tasks in @mgctx as setup by migration preparation functions. | 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 | psi_trigger_replace(&of->priv, NULL); | 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 | #endif /* CONFIG_PSI */ | 3663 | #endif /* CONFIG_PSI */ |
| 3636 | 3664 | ||
| 3637 | static int cgroup_freeze_show(struct seq_file *seq, void *v) | 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 | return nbytes; | 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 | static int cgroup_file_open(struct kernfs_open_file *of) | 3773 | static int cgroup_file_open(struct kernfs_open_file *of) |
| 3672 | { | 3774 | { |
| 3673 | struct cftype *cft = of_cft(of); | 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 | restart: | 3984 | restart: |
| 3883 | for (cft = cfts; cft != cft_end && cft->name[0] != '\0'; cft++) { | 3985 | for (cft = cfts; cft != cft_end && cft->name[0] != '\0'; cft++) { |
| 3884 | /* does cft->flags tell us to skip this file on @cgrp? */ | 3986 | /* does cft->flags tell us to skip this file on @cgrp? */ |
| 3987 | if ((cft->flags & CFTYPE_PRESSURE) && !cgroup_psi_enabled()) | ||
| 3988 | continue; | ||
| 3885 | if ((cft->flags & __CFTYPE_ONLY_ON_DFL) && !cgroup_on_dfl(cgrp)) | 3989 | if ((cft->flags & __CFTYPE_ONLY_ON_DFL) && !cgroup_on_dfl(cgrp)) |
| 3886 | continue; | 3990 | continue; |
| 3887 | if ((cft->flags & __CFTYPE_NOT_ON_DFL) && cgroup_on_dfl(cgrp)) | 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 | WARN_ON(cft->ss || cft->kf_ops); | 4064 | WARN_ON(cft->ss || cft->kf_ops); |
| 3961 | 4065 | ||
| 4066 | if ((cft->flags & CFTYPE_PRESSURE) && !cgroup_psi_enabled()) | ||
| 4067 | continue; | ||
| 4068 | |||
| 3962 | if (cft->seq_start) | 4069 | if (cft->seq_start) |
| 3963 | kf_ops = &cgroup_kf_ops; | 4070 | kf_ops = &cgroup_kf_ops; |
| 3964 | else | 4071 | else |
| @@ -4860,6 +4967,11 @@ static struct cftype cgroup_base_files[] = { · 895 unmodified lines | |||
| 4860 | .seq_show = cgroup_freeze_show, | 4967 | .seq_show = cgroup_freeze_show, |
| 4861 | .write = cgroup_freeze_write, | 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 | .name = "cpu.stat", | 4976 | .name = "cpu.stat", |
| 4865 | .seq_show = cpu_stat_show, | 4977 | .seq_show = cpu_stat_show, |
| @@ -4867,6 +4979,7 @@ static struct cftype cgroup_base_files[] = { · 1 unmodified line | |||
| 4867 | #ifdef CONFIG_PSI | 4979 | #ifdef CONFIG_PSI |
| 4868 | { | 4980 | { |
| 4869 | .name = "io.pressure", | 4981 | .name = "io.pressure", |
| 4982 | .flags = CFTYPE_PRESSURE, | ||
| 4870 | .seq_show = cgroup_io_pressure_show, | 4983 | .seq_show = cgroup_io_pressure_show, |
| 4871 | .write = cgroup_io_pressure_write, | 4984 | .write = cgroup_io_pressure_write, |
| 4872 | .poll = cgroup_pressure_poll, | 4985 | .poll = cgroup_pressure_poll, |
| @@ -4874,6 +4987,7 @@ static struct cftype cgroup_base_files[] = { · 1 unmodified line | |||
| 4874 | }, | 4987 | }, |
| 4875 | { | 4988 | { |
| 4876 | .name = "memory.pressure", | 4989 | .name = "memory.pressure", |
| 4990 | .flags = CFTYPE_PRESSURE, | ||
| 4877 | .seq_show = cgroup_memory_pressure_show, | 4991 | .seq_show = cgroup_memory_pressure_show, |
| 4878 | .write = cgroup_memory_pressure_write, | 4992 | .write = cgroup_memory_pressure_write, |
| 4879 | .poll = cgroup_pressure_poll, | 4993 | .poll = cgroup_pressure_poll, |
| @@ -4881,6 +4995,7 @@ static struct cftype cgroup_base_files[] = { · 1 unmodified line | |||
| 4881 | }, | 4995 | }, |
| 4882 | { | 4996 | { |
| 4883 | .name = "cpu.pressure", | 4997 | .name = "cpu.pressure", |
| 4998 | .flags = CFTYPE_PRESSURE, | ||
| 4884 | .seq_show = cgroup_cpu_pressure_show, | 4999 | .seq_show = cgroup_cpu_pressure_show, |
| 4885 | .write = cgroup_cpu_pressure_write, | 5000 | .write = cgroup_cpu_pressure_write, |
| 4886 | .poll = cgroup_pressure_poll, | 5001 | .poll = cgroup_pressure_poll, |
| @@ -6080,6 +6195,8 @@ void cgroup_post_fork(struct task_struct *child, · 1193 unmodified lines | |||
| 6080 | struct kernel_clone_args *kargs) | 6195 | struct kernel_clone_args *kargs) |
| 6081 | __releases(&cgroup_threadgroup_rwsem) __releases(&cgroup_mutex) | 6196 | __releases(&cgroup_threadgroup_rwsem) __releases(&cgroup_mutex) |
| 6082 | { | 6197 | { |
| 6198 | unsigned long cgrp_flags = 0; | ||
| 6199 | bool kill = false; | ||
| 6083 | struct cgroup_subsys *ss; | 6200 | struct cgroup_subsys *ss; |
| 6084 | struct css_set *cset; | 6201 | struct css_set *cset; |
| 6085 | int i; | 6202 | int i; |
| @@ -6091,6 +6208,11 @@ void cgroup_post_fork(struct task_struct *child, · 5 unmodified lines | |||
| 6091 | 6208 | ||
| 6092 | /* init tasks are special, only link regular threads */ | 6209 | /* init tasks are special, only link regular threads */ |
| 6093 | if (likely(child->pid)) { | 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 | WARN_ON_ONCE(!list_empty(&child->cg_list)); | 6216 | WARN_ON_ONCE(!list_empty(&child->cg_list)); |
| 6095 | cset->nr_tasks++; | 6217 | cset->nr_tasks++; |
| 6096 | css_set_move_task(child, NULL, cset, false); | 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 | cset = NULL; | 6221 | cset = NULL; |
| 6100 | } | 6222 | } |
| 6101 | 6223 | ||
| 6102 | /* | 6224 | if (!(child->flags & PF_KTHREAD)) { |
| 6103 | * If the cgroup has to be frozen, the new task has too. Let's set | 6225 | if (unlikely(test_bit(CGRP_FREEZE, &cgrp_flags))) { |
| 6104 | * the JOBCTL_TRAP_FREEZE jobctl bit to get the task into the | 6226 | /* |
| 6105 | * frozen state. | 6227 | * If the cgroup has to be frozen, the new task has |
| 6106 | */ | 6228 | * too. Let's set the JOBCTL_TRAP_FREEZE jobctl bit to |
| 6107 | if (unlikely(cgroup_task_freeze(child))) { | 6229 | * get the task into the frozen state. |
| 6108 | spin_lock(&child->sighand->siglock); | 6230 | */ |
| 6109 | WARN_ON_ONCE(child->frozen); | 6231 | spin_lock(&child->sighand->siglock); |
| 6110 | child->jobctl |= JOBCTL_TRAP_FREEZE; | 6232 | WARN_ON_ONCE(child->frozen); |
| 6111 | spin_unlock(&child->sighand->siglock); | 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, | 6245 | * If the cgroup is to be killed notice it now and take the |
| 6115 | * because it will be called anyway a bit later from | 6246 | * child down right after we finished preparing it for |
| 6116 | * do_freezer_trap(). So we avoid cgroup's transient switch | 6247 | * userspace. |
| 6117 | * from the frozen state and back. | ||
| 6118 | */ | 6248 | */ |
| 6249 | kill = test_bit(CGRP_KILL, &cgrp_flags); | ||
| 6119 | } | 6250 | } |
| 6120 | 6251 | ||
| 6121 | spin_unlock_irq(&css_set_lock); | 6252 | spin_unlock_irq(&css_set_lock); |
| @@ -6138,6 +6269,10 @@ void cgroup_post_fork(struct task_struct *child, · 16 unmodified lines | |||
| 6138 | put_css_set(rcset); | 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 | cgroup_css_set_put_fork(kargs); | 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 | cset->nr_tasks--; | 6298 | cset->nr_tasks--; |
| 6164 | 6299 | ||
| 6165 | WARN_ON_ONCE(cgroup_task_frozen(tsk)); | 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 | cgroup_update_frozen(task_dfl_cgroup(tsk)); | 6303 | cgroup_update_frozen(task_dfl_cgroup(tsk)); |
| 6168 | 6304 | ||
| 6169 | spin_unlock_irq(&css_set_lock); | 6305 | spin_unlock_irq(&css_set_lock); |
| @@ -6214,6 +6350,15 @@ static int __init cgroup_disable(char *str) · 44 unmodified lines | |||
| 6214 | pr_info("Disabling %s control group subsystem\n", | 6350 | pr_info("Disabling %s control group subsystem\n", |
| 6215 | ss->name); | 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 | return 1; | 6363 | return 1; |
| 6219 | } | 6364 | } |
| @@ -6512,6 +6657,9 @@ static ssize_t show_delegatable_files(struct cftype *files, char *buf, · 292 unmodified lines | |||
| 6512 | if (!(cft->flags & CFTYPE_NS_DELEGATABLE)) | 6657 | if (!(cft->flags & CFTYPE_NS_DELEGATABLE)) |
| 6513 | continue; | 6658 | continue; |
| 6514 | 6659 | ||
| 6660 | if ((cft->flags & CFTYPE_PRESSURE) && !cgroup_psi_enabled()) | ||
| 6661 | continue; | ||
| 6662 | |||
| 6515 | if (prefix) | 6663 | if (prefix) |
| 6516 | ret += snprintf(buf + ret, size - ret, "%s.", prefix); | 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 | * @cgrp: target cgroup | 224 | * @cgrp: target cgroup |
| 225 | * | 225 | * |
| 226 | * Flush stats in @cgrp's subtree and prevent further flushes. Must be | 226 | * Flush stats in @cgrp's subtree and prevent further flushes. Must be |
| @@ -148,6 +148,7 @@ · 147 unmodified lines | |||
| 148 | static int psi_bug __read_mostly; | 148 | static int psi_bug __read_mostly; |
| 149 | 149 | ||
| 150 | DEFINE_STATIC_KEY_FALSE(psi_disabled); | 150 | DEFINE_STATIC_KEY_FALSE(psi_disabled); |
| 151 | DEFINE_STATIC_KEY_TRUE(psi_cgroups_enabled); | ||
| 151 | 152 | ||
| 152 | #ifdef CONFIG_PSI_DEFAULT_DISABLED | 153 | #ifdef CONFIG_PSI_DEFAULT_DISABLED |
| 153 | static bool psi_enable; | 154 | static bool psi_enable; |
| @@ -215,6 +216,9 @@ void __init psi_init(void) · 61 unmodified lines | |||
| 215 | return; | 216 | return; |
| 216 | } | 217 | } |
| 217 | 218 | ||
| 219 | if (!cgroup_psi_enabled()) | ||
| 220 | static_branch_disable(&psi_cgroups_enabled); | ||
| 221 | |||
| 218 | psi_period = jiffies_to_nsecs(PSI_FREQ); | 222 | psi_period = jiffies_to_nsecs(PSI_FREQ); |
| 219 | group_init(&psi_system); | 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 | static struct psi_group *iterate_groups(struct task_struct *task, void **iter) | 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 | #ifdef CONFIG_CGROUPS | 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) | 762 | if (!*iter) |
| 755 | cgroup = task->cgroups->dfl_cgrp; | 763 | cgroup = task->cgroups->dfl_cgrp; |
| 756 | else if (*iter == &psi_system) | 764 | else |
| 757 | return NULL; | 765 | cgroup = cgroup_parent(*iter); |
| 758 | else | ||
| 759 | cgroup = cgroup_parent(*iter); | ||
| 760 | 766 | ||
| 761 | if (cgroup && cgroup_parent(cgroup)) { | 767 | if (cgroup && cgroup_parent(cgroup)) { |
| 762 | *iter = cgroup; | 768 | *iter = cgroup; |
| 763 | return cgroup_psi(cgroup); | 769 | return cgroup_psi(cgroup); |
| 770 | } | ||
| 764 | } | 771 | } |
| 765 | #else | ||
| 766 | if (*iter) | ||
| 767 | return NULL; | ||
| 768 | #endif | 772 | #endif |
| 769 | *iter = &psi_system; | 773 | *iter = &psi_system; |
| 770 | return &psi_system; | 774 | return &psi_system; |