Commit ae8086ce15fdab2b57599d7a3242a114ba4b8597

Authored by Tejun Heo
1 parent efeb77b2f1

cpuset: introduce cpuset_for_each_child()

Instead of iterating cgroup->children directly, introduce and use
cpuset_for_each_child() which wraps cgroup_for_each_child() and
performs online check.  As it uses the generic iterator, it requires
RCU read locking too.

As cpuset is currently protected by cgroup_mutex, non-online cpusets
aren't visible to all the iterations and this patch currently doesn't
make any functional difference.  This will be used to de-couple cpuset
locking from cgroup core.

Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Li Zefan <lizefan@huawei.com>

Showing 1 changed file with 54 additions and 31 deletions Side-by-side Diff

... ... @@ -200,6 +200,19 @@
200 200 (1 << CS_MEM_EXCLUSIVE)),
201 201 };
202 202  
  203 +/**
  204 + * cpuset_for_each_child - traverse online children of a cpuset
  205 + * @child_cs: loop cursor pointing to the current child
  206 + * @pos_cgrp: used for iteration
  207 + * @parent_cs: target cpuset to walk children of
  208 + *
  209 + * Walk @child_cs through the online children of @parent_cs. Must be used
  210 + * with RCU read locked.
  211 + */
  212 +#define cpuset_for_each_child(child_cs, pos_cgrp, parent_cs) \
  213 + cgroup_for_each_child((pos_cgrp), (parent_cs)->css.cgroup) \
  214 + if (is_cpuset_online(((child_cs) = cgroup_cs((pos_cgrp)))))
  215 +
203 216 /*
204 217 * There are two global mutexes guarding cpuset structures. The first
205 218 * is the main control groups cgroup_mutex, accessed via
206 219  
207 220  
208 221  
209 222  
210 223  
211 224  
212 225  
213 226  
214 227  
215 228  
216 229  
... ... @@ -419,48 +432,55 @@
419 432 {
420 433 struct cgroup *cont;
421 434 struct cpuset *c, *par;
  435 + int ret;
422 436  
  437 + rcu_read_lock();
  438 +
423 439 /* Each of our child cpusets must be a subset of us */
424   - list_for_each_entry(cont, &cur->css.cgroup->children, sibling) {
425   - if (!is_cpuset_subset(cgroup_cs(cont), trial))
426   - return -EBUSY;
427   - }
  440 + ret = -EBUSY;
  441 + cpuset_for_each_child(c, cont, cur)
  442 + if (!is_cpuset_subset(c, trial))
  443 + goto out;
428 444  
429 445 /* Remaining checks don't apply to root cpuset */
  446 + ret = 0;
430 447 if (cur == &top_cpuset)
431   - return 0;
  448 + goto out;
432 449  
433 450 par = cur->parent;
434 451  
435 452 /* We must be a subset of our parent cpuset */
  453 + ret = -EACCES;
436 454 if (!is_cpuset_subset(trial, par))
437   - return -EACCES;
  455 + goto out;
438 456  
439 457 /*
440 458 * If either I or some sibling (!= me) is exclusive, we can't
441 459 * overlap
442 460 */
443   - list_for_each_entry(cont, &par->css.cgroup->children, sibling) {
444   - c = cgroup_cs(cont);
  461 + ret = -EINVAL;
  462 + cpuset_for_each_child(c, cont, par) {
445 463 if ((is_cpu_exclusive(trial) || is_cpu_exclusive(c)) &&
446 464 c != cur &&
447 465 cpumask_intersects(trial->cpus_allowed, c->cpus_allowed))
448   - return -EINVAL;
  466 + goto out;
449 467 if ((is_mem_exclusive(trial) || is_mem_exclusive(c)) &&
450 468 c != cur &&
451 469 nodes_intersects(trial->mems_allowed, c->mems_allowed))
452   - return -EINVAL;
  470 + goto out;
453 471 }
454 472  
455 473 /* Cpusets with tasks can't have empty cpus_allowed or mems_allowed */
456   - if (cgroup_task_count(cur->css.cgroup)) {
457   - if (cpumask_empty(trial->cpus_allowed) ||
458   - nodes_empty(trial->mems_allowed)) {
459   - return -ENOSPC;
460   - }
461   - }
  474 + ret = -ENOSPC;
  475 + if (cgroup_task_count(cur->css.cgroup) &&
  476 + (cpumask_empty(trial->cpus_allowed) ||
  477 + nodes_empty(trial->mems_allowed)))
  478 + goto out;
462 479  
463   - return 0;
  480 + ret = 0;
  481 +out:
  482 + rcu_read_unlock();
  483 + return ret;
464 484 }
465 485  
466 486 #ifdef CONFIG_SMP
467 487  
... ... @@ -501,10 +521,10 @@
501 521 if (is_sched_load_balance(cp))
502 522 update_domain_attr(dattr, cp);
503 523  
504   - list_for_each_entry(cont, &cp->css.cgroup->children, sibling) {
505   - child = cgroup_cs(cont);
  524 + rcu_read_lock();
  525 + cpuset_for_each_child(child, cont, cp)
506 526 list_add_tail(&child->stack_list, &q);
507   - }
  527 + rcu_read_unlock();
508 528 }
509 529 }
510 530  
511 531  
... ... @@ -623,10 +643,10 @@
623 643 continue;
624 644 }
625 645  
626   - list_for_each_entry(cont, &cp->css.cgroup->children, sibling) {
627   - child = cgroup_cs(cont);
  646 + rcu_read_lock();
  647 + cpuset_for_each_child(child, cont, cp)
628 648 list_add_tail(&child->stack_list, &q);
629   - }
  649 + rcu_read_unlock();
630 650 }
631 651  
632 652 for (i = 0; i < csn; i++)
... ... @@ -1824,7 +1844,8 @@
1824 1844 {
1825 1845 struct cpuset *cs = cgroup_cs(cgrp);
1826 1846 struct cpuset *parent = cs->parent;
1827   - struct cgroup *tmp_cg;
  1847 + struct cpuset *tmp_cs;
  1848 + struct cgroup *pos_cg;
1828 1849  
1829 1850 if (!parent)
1830 1851 return 0;
1831 1852  
1832 1853  
... ... @@ -1853,12 +1874,14 @@
1853 1874 * changed to grant parent->cpus_allowed-sibling_cpus_exclusive
1854 1875 * (and likewise for mems) to the new cgroup.
1855 1876 */
1856   - list_for_each_entry(tmp_cg, &cgrp->parent->children, sibling) {
1857   - struct cpuset *tmp_cs = cgroup_cs(tmp_cg);
1858   -
1859   - if (is_mem_exclusive(tmp_cs) || is_cpu_exclusive(tmp_cs))
  1877 + rcu_read_lock();
  1878 + cpuset_for_each_child(tmp_cs, pos_cg, parent) {
  1879 + if (is_mem_exclusive(tmp_cs) || is_cpu_exclusive(tmp_cs)) {
  1880 + rcu_read_unlock();
1860 1881 return 0;
  1882 + }
1861 1883 }
  1884 + rcu_read_unlock();
1862 1885  
1863 1886 mutex_lock(&callback_mutex);
1864 1887 cs->mems_allowed = parent->mems_allowed;
1865 1888  
... ... @@ -2027,10 +2050,10 @@
2027 2050  
2028 2051 cp = list_first_entry(queue, struct cpuset, stack_list);
2029 2052 list_del(queue->next);
2030   - list_for_each_entry(cont, &cp->css.cgroup->children, sibling) {
2031   - child = cgroup_cs(cont);
  2053 + rcu_read_lock();
  2054 + cpuset_for_each_child(child, cont, cp)
2032 2055 list_add_tail(&child->stack_list, queue);
2033   - }
  2056 + rcu_read_unlock();
2034 2057  
2035 2058 return cp;
2036 2059 }