Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'cgroup-for-6.3-rc6-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup

Pull cgroup fixes from Tejun Heo:
"This is a relatively big pull request this late in the cycle but the
major contributor is the cpuset bug which is rather significant:

- Fix several cpuset bugs including one where it wasn't applying the
target cgroup when tasks are created with CLONE_INTO_CGROUP

With a few smaller fixes:

- Fix inversed locking order in cgroup1 freezer implementation

- Fix garbage cpu.stat::core_sched.forceidle_usec reporting in the
root cgroup"

* tag 'cgroup-for-6.3-rc6-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup:
cgroup/cpuset: Make cpuset_attach_task() skip subpartitions CPUs for top_cpuset
cgroup/cpuset: Add cpuset_can_fork() and cpuset_cancel_fork() methods
cgroup/cpuset: Make cpuset_fork() handle CLONE_INTO_CGROUP properly
cgroup/cpuset: Wake up cpuset_attach_wq tasks in cpuset_cancel_attach()
cgroup,freezer: hold cpu_hotplug_lock before freezer_mutex
cgroup/cpuset: Fix partition root's cpuset.cpus update bug
cgroup: fix display of forceidle time at root

+151 -40
+145 -35
kernel/cgroup/cpuset.c
··· 1513 1513 spin_unlock_irq(&callback_lock); 1514 1514 1515 1515 if (adding || deleting) 1516 - update_tasks_cpumask(parent, tmp->new_cpus); 1516 + update_tasks_cpumask(parent, tmp->addmask); 1517 1517 1518 1518 /* 1519 1519 * Set or clear CS_SCHED_LOAD_BALANCE when partcmd_update, if necessary. ··· 1770 1770 /* 1771 1771 * Use the cpumasks in trialcs for tmpmasks when they are pointers 1772 1772 * to allocated cpumasks. 1773 + * 1774 + * Note that update_parent_subparts_cpumask() uses only addmask & 1775 + * delmask, but not new_cpus. 1773 1776 */ 1774 1777 tmp.addmask = trialcs->subparts_cpus; 1775 1778 tmp.delmask = trialcs->effective_cpus; 1776 - tmp.new_cpus = trialcs->cpus_allowed; 1779 + tmp.new_cpus = NULL; 1777 1780 #endif 1778 1781 1779 1782 retval = validate_change(cs, trialcs); ··· 1840 1837 } 1841 1838 } 1842 1839 spin_unlock_irq(&callback_lock); 1840 + 1841 + #ifdef CONFIG_CPUMASK_OFFSTACK 1842 + /* Now trialcs->cpus_allowed is available */ 1843 + tmp.new_cpus = trialcs->cpus_allowed; 1844 + #endif 1843 1845 1844 1846 /* effective_cpus will be updated here */ 1845 1847 update_cpumasks_hier(cs, &tmp, false); ··· 2453 2445 2454 2446 static struct cpuset *cpuset_attach_old_cs; 2455 2447 2448 + /* 2449 + * Check to see if a cpuset can accept a new task 2450 + * For v1, cpus_allowed and mems_allowed can't be empty. 2451 + * For v2, effective_cpus can't be empty. 2452 + * Note that in v1, effective_cpus = cpus_allowed. 2453 + */ 2454 + static int cpuset_can_attach_check(struct cpuset *cs) 2455 + { 2456 + if (cpumask_empty(cs->effective_cpus) || 2457 + (!is_in_v2_mode() && nodes_empty(cs->mems_allowed))) 2458 + return -ENOSPC; 2459 + return 0; 2460 + } 2461 + 2456 2462 /* Called by cgroups to determine if a cpuset is usable; cpuset_rwsem held */ 2457 2463 static int cpuset_can_attach(struct cgroup_taskset *tset) 2458 2464 { ··· 2481 2459 2482 2460 percpu_down_write(&cpuset_rwsem); 2483 2461 2484 - /* allow moving tasks into an empty cpuset if on default hierarchy */ 2485 - ret = -ENOSPC; 2486 - if (!is_in_v2_mode() && 2487 - (cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed))) 2488 - goto out_unlock; 2489 - 2490 - /* 2491 - * Task cannot be moved to a cpuset with empty effective cpus. 2492 - */ 2493 - if (cpumask_empty(cs->effective_cpus)) 2462 + /* Check to see if task is allowed in the cpuset */ 2463 + ret = cpuset_can_attach_check(cs); 2464 + if (ret) 2494 2465 goto out_unlock; 2495 2466 2496 2467 cgroup_taskset_for_each(task, css, tset) { ··· 2500 2485 * changes which zero cpus/mems_allowed. 2501 2486 */ 2502 2487 cs->attach_in_progress++; 2503 - ret = 0; 2504 2488 out_unlock: 2505 2489 percpu_up_write(&cpuset_rwsem); 2506 2490 return ret; ··· 2508 2494 static void cpuset_cancel_attach(struct cgroup_taskset *tset) 2509 2495 { 2510 2496 struct cgroup_subsys_state *css; 2497 + struct cpuset *cs; 2511 2498 2512 2499 cgroup_taskset_first(tset, &css); 2500 + cs = css_cs(css); 2513 2501 2514 2502 percpu_down_write(&cpuset_rwsem); 2515 - css_cs(css)->attach_in_progress--; 2503 + cs->attach_in_progress--; 2504 + if (!cs->attach_in_progress) 2505 + wake_up(&cpuset_attach_wq); 2516 2506 percpu_up_write(&cpuset_rwsem); 2517 2507 } 2518 2508 2519 2509 /* 2520 - * Protected by cpuset_rwsem. cpus_attach is used only by cpuset_attach() 2510 + * Protected by cpuset_rwsem. cpus_attach is used only by cpuset_attach_task() 2521 2511 * but we can't allocate it dynamically there. Define it global and 2522 2512 * allocate from cpuset_init(). 2523 2513 */ 2524 2514 static cpumask_var_t cpus_attach; 2515 + static nodemask_t cpuset_attach_nodemask_to; 2516 + 2517 + static void cpuset_attach_task(struct cpuset *cs, struct task_struct *task) 2518 + { 2519 + percpu_rwsem_assert_held(&cpuset_rwsem); 2520 + 2521 + if (cs != &top_cpuset) 2522 + guarantee_online_cpus(task, cpus_attach); 2523 + else 2524 + cpumask_andnot(cpus_attach, task_cpu_possible_mask(task), 2525 + cs->subparts_cpus); 2526 + /* 2527 + * can_attach beforehand should guarantee that this doesn't 2528 + * fail. TODO: have a better way to handle failure here 2529 + */ 2530 + WARN_ON_ONCE(set_cpus_allowed_ptr(task, cpus_attach)); 2531 + 2532 + cpuset_change_task_nodemask(task, &cpuset_attach_nodemask_to); 2533 + cpuset_update_task_spread_flags(cs, task); 2534 + } 2525 2535 2526 2536 static void cpuset_attach(struct cgroup_taskset *tset) 2527 2537 { 2528 - /* static buf protected by cpuset_rwsem */ 2529 - static nodemask_t cpuset_attach_nodemask_to; 2530 2538 struct task_struct *task; 2531 2539 struct task_struct *leader; 2532 2540 struct cgroup_subsys_state *css; ··· 2579 2543 2580 2544 guarantee_online_mems(cs, &cpuset_attach_nodemask_to); 2581 2545 2582 - cgroup_taskset_for_each(task, css, tset) { 2583 - if (cs != &top_cpuset) 2584 - guarantee_online_cpus(task, cpus_attach); 2585 - else 2586 - cpumask_copy(cpus_attach, task_cpu_possible_mask(task)); 2587 - /* 2588 - * can_attach beforehand should guarantee that this doesn't 2589 - * fail. TODO: have a better way to handle failure here 2590 - */ 2591 - WARN_ON_ONCE(set_cpus_allowed_ptr(task, cpus_attach)); 2592 - 2593 - cpuset_change_task_nodemask(task, &cpuset_attach_nodemask_to); 2594 - cpuset_update_task_spread_flags(cs, task); 2595 - } 2546 + cgroup_taskset_for_each(task, css, tset) 2547 + cpuset_attach_task(cs, task); 2596 2548 2597 2549 /* 2598 2550 * Change mm for all threadgroup leaders. This is expensive and may ··· 3272 3248 } 3273 3249 3274 3250 /* 3251 + * In case the child is cloned into a cpuset different from its parent, 3252 + * additional checks are done to see if the move is allowed. 3253 + */ 3254 + static int cpuset_can_fork(struct task_struct *task, struct css_set *cset) 3255 + { 3256 + struct cpuset *cs = css_cs(cset->subsys[cpuset_cgrp_id]); 3257 + bool same_cs; 3258 + int ret; 3259 + 3260 + rcu_read_lock(); 3261 + same_cs = (cs == task_cs(current)); 3262 + rcu_read_unlock(); 3263 + 3264 + if (same_cs) 3265 + return 0; 3266 + 3267 + lockdep_assert_held(&cgroup_mutex); 3268 + percpu_down_write(&cpuset_rwsem); 3269 + 3270 + /* Check to see if task is allowed in the cpuset */ 3271 + ret = cpuset_can_attach_check(cs); 3272 + if (ret) 3273 + goto out_unlock; 3274 + 3275 + ret = task_can_attach(task, cs->effective_cpus); 3276 + if (ret) 3277 + goto out_unlock; 3278 + 3279 + ret = security_task_setscheduler(task); 3280 + if (ret) 3281 + goto out_unlock; 3282 + 3283 + /* 3284 + * Mark attach is in progress. This makes validate_change() fail 3285 + * changes which zero cpus/mems_allowed. 3286 + */ 3287 + cs->attach_in_progress++; 3288 + out_unlock: 3289 + percpu_up_write(&cpuset_rwsem); 3290 + return ret; 3291 + } 3292 + 3293 + static void cpuset_cancel_fork(struct task_struct *task, struct css_set *cset) 3294 + { 3295 + struct cpuset *cs = css_cs(cset->subsys[cpuset_cgrp_id]); 3296 + bool same_cs; 3297 + 3298 + rcu_read_lock(); 3299 + same_cs = (cs == task_cs(current)); 3300 + rcu_read_unlock(); 3301 + 3302 + if (same_cs) 3303 + return; 3304 + 3305 + percpu_down_write(&cpuset_rwsem); 3306 + cs->attach_in_progress--; 3307 + if (!cs->attach_in_progress) 3308 + wake_up(&cpuset_attach_wq); 3309 + percpu_up_write(&cpuset_rwsem); 3310 + } 3311 + 3312 + /* 3275 3313 * Make sure the new task conform to the current state of its parent, 3276 3314 * which could have been changed by cpuset just after it inherits the 3277 3315 * state from the parent and before it sits on the cgroup's task list. 3278 3316 */ 3279 3317 static void cpuset_fork(struct task_struct *task) 3280 3318 { 3281 - if (task_css_is_root(task, cpuset_cgrp_id)) 3282 - return; 3319 + struct cpuset *cs; 3320 + bool same_cs; 3283 3321 3284 - set_cpus_allowed_ptr(task, current->cpus_ptr); 3285 - task->mems_allowed = current->mems_allowed; 3322 + rcu_read_lock(); 3323 + cs = task_cs(task); 3324 + same_cs = (cs == task_cs(current)); 3325 + rcu_read_unlock(); 3326 + 3327 + if (same_cs) { 3328 + if (cs == &top_cpuset) 3329 + return; 3330 + 3331 + set_cpus_allowed_ptr(task, current->cpus_ptr); 3332 + task->mems_allowed = current->mems_allowed; 3333 + return; 3334 + } 3335 + 3336 + /* CLONE_INTO_CGROUP */ 3337 + percpu_down_write(&cpuset_rwsem); 3338 + guarantee_online_mems(cs, &cpuset_attach_nodemask_to); 3339 + cpuset_attach_task(cs, task); 3340 + 3341 + cs->attach_in_progress--; 3342 + if (!cs->attach_in_progress) 3343 + wake_up(&cpuset_attach_wq); 3344 + 3345 + percpu_up_write(&cpuset_rwsem); 3286 3346 } 3287 3347 3288 3348 struct cgroup_subsys cpuset_cgrp_subsys = { ··· 3379 3271 .attach = cpuset_attach, 3380 3272 .post_attach = cpuset_post_attach, 3381 3273 .bind = cpuset_bind, 3274 + .can_fork = cpuset_can_fork, 3275 + .cancel_fork = cpuset_cancel_fork, 3382 3276 .fork = cpuset_fork, 3383 3277 .legacy_cftypes = legacy_files, 3384 3278 .dfl_cftypes = dfl_files,
+5 -2
kernel/cgroup/legacy_freezer.c
··· 22 22 #include <linux/freezer.h> 23 23 #include <linux/seq_file.h> 24 24 #include <linux/mutex.h> 25 + #include <linux/cpu.h> 25 26 26 27 /* 27 28 * A cgroup is freezing if any FREEZING flags are set. FREEZING_SELF is ··· 351 350 352 351 if (freeze) { 353 352 if (!(freezer->state & CGROUP_FREEZING)) 354 - static_branch_inc(&freezer_active); 353 + static_branch_inc_cpuslocked(&freezer_active); 355 354 freezer->state |= state; 356 355 freeze_cgroup(freezer); 357 356 } else { ··· 362 361 if (!(freezer->state & CGROUP_FREEZING)) { 363 362 freezer->state &= ~CGROUP_FROZEN; 364 363 if (was_freezing) 365 - static_branch_dec(&freezer_active); 364 + static_branch_dec_cpuslocked(&freezer_active); 366 365 unfreeze_cgroup(freezer); 367 366 } 368 367 } ··· 380 379 { 381 380 struct cgroup_subsys_state *pos; 382 381 382 + cpus_read_lock(); 383 383 /* 384 384 * Update all its descendants in pre-order traversal. Each 385 385 * descendant will try to inherit its parent's FREEZING state as ··· 409 407 } 410 408 rcu_read_unlock(); 411 409 mutex_unlock(&freezer_mutex); 410 + cpus_read_unlock(); 412 411 } 413 412 414 413 static ssize_t freezer_write(struct kernfs_open_file *of,
+1 -3
kernel/cgroup/rstat.c
··· 457 457 struct task_cputime *cputime = &bstat->cputime; 458 458 int i; 459 459 460 - cputime->stime = 0; 461 - cputime->utime = 0; 462 - cputime->sum_exec_runtime = 0; 460 + memset(bstat, 0, sizeof(*bstat)); 463 461 for_each_possible_cpu(i) { 464 462 struct kernel_cpustat kcpustat; 465 463 u64 *cpustat = kcpustat.cpustat;