History

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

Pull cgroup updates from Tejun Heo: - Per-cpu cpu usage stats are now tracked This currently isn't printed out in the cgroupfs interface and can only be accessed through e.g. BPF. Should decide on a not-too-ugly way to show per-cpu stats in cgroupfs - cpuset received some cleanups and prepatory patches for the pending cpus.exclusive patchset which will allow cpuset partitions to be created below non-partition parents, which should ease the management of partition cpusets - A lot of code and documentation cleanup patches - tools/testing/selftests/cgroup/test_cpuset.c added * tag 'cgroup-for-6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup: (32 commits) cgroup: Avoid -Wstringop-overflow warnings cgroup:namespace: Remove unused cgroup_namespaces_init() cgroup/rstat: Record the cumulative per-cpu time of cgroup and its descendants cgroup: clean up if condition in cgroup_pidlist_start() cgroup: fix obsolete function name in cgroup_destroy_locked() Documentation: cgroup-v2.rst: Correct number of stats entries cgroup: fix obsolete function name above css_free_rwork_fn() cgroup/cpuset: fix kernel-doc cgroup: clean up printk() cgroup: fix obsolete comment above cgroup_create() docs: cgroup-v1: fix typo docs: cgroup-v1: correct the term of Page Cache organization in inode cgroup/misc: Store atomic64_t reads to u64 cgroup/misc: Change counters to be explicit 64bit types cgroup/misc: update struct members descriptions cgroup: remove cgrp->kn check in css_populate_dir() cgroup: fix obsolete function name cgroup: use cached local variable parent in for loop cgroup: remove obsolete comment above struct cgroupstats cgroup: put cgroup_tryget_css() inside CONFIG_CGROUP_SCHED ...

Linus Torvalds committed 3 years ago

Commit 7716f382 parents e987af4 78d44b819 files · +560 −204Browse files

Unified · Split

19 files
  1. Documentation/admin-guide/cgroup-v1/memory.rst +3 −3
  2. Documentation/admin-guide/cgroup-v2.rst +1 −1
  3. MAINTAINERS +2 −0
  4. include/linux/cgroup-defs.h +14 −0
  5. include/linux/misc_cgroup.h +13 −15
  6. include/uapi/linux/cgroupstats.h +0 −2
  7. kernel/cgroup/cgroup-v1.c +1 −1
  8. kernel/cgroup/cgroup.c +41 −44
  9. kernel/cgroup/cpuset.c +164 −100
  10. kernel/cgroup/misc.c +27 −28
  11. kernel/cgroup/namespace.c +0 −6
  12. kernel/cgroup/rstat.c +10 −2
  13. tools/testing/selftests/cgroup/.gitignore +1 −0
  14. tools/testing/selftests/cgroup/Makefile +2 −0
  15. tools/testing/selftests/cgroup/cgroup_util.c +2 −0
  16. tools/testing/selftests/cgroup/cgroup_util.h +2 −0
  17. tools/testing/selftests/cgroup/test_core.c +1 −1
  18. tools/testing/selftests/cgroup/test_cpuset.c +275 −0
  19. tools/testing/selftests/cgroup/test_cpuset_prs.sh +1 −1
Documentation/admin-guide/cgroup-v1/memory.rst+3−3
@@ -195,11 +195,11 @@ are not accounted. We just account pages under usual VM management. · 194 unmodified lines
195195
196196 RSS pages are accounted at page_fault unless they've already been accounted
197197 for earlier. A file page will be accounted for as Page Cache when it's
198−inserted into inode (radix-tree). While it's mapped into the page tables of
198+inserted into inode (xarray). While it's mapped into the page tables of
199199 processes, duplicate accounting is carefully avoided.
200200
201201 An RSS page is unaccounted when it's fully unmapped. A PageCache page is
202−unaccounted when it's removed from radix-tree. Even if RSS pages are fully
202+unaccounted when it's removed from xarray. Even if RSS pages are fully
203203 unmapped (by kswapd), they may exist as SwapCache in the system until they
204204 are really freed. Such SwapCaches are also accounted.
205205 A swapped-in page is accounted after adding into swapcache.
@@ -907,7 +907,7 @@ experiences some pressure. In this situation, only group C will receive the · 701 unmodified lines
907907 notification, i.e. groups A and B will not receive it. This is done to avoid
908908 excessive "broadcasting" of messages, which disturbs the system and which is
909909 especially bad if we are low on memory or thrashing. Group B, will receive
910−notification only if there are no event listers for group C.
910+notification only if there are no event listeners for group C.
911911
912912 There are three optional modes that specify different propagation behavior:
913913
Documentation/admin-guide/cgroup-v2.rst+1−1
@@ -1045,7 +1045,7 @@ All time durations are in microseconds. · 1044 unmodified lines
10451045 - user_usec
10461046 - system_usec
10471047
1048− and the following three when the controller is enabled:
1048+ and the following five when the controller is enabled:
10491049
10501050 - nr_periods
10511051 - nr_throttled
MAINTAINERS+2−0
@@ -5255,6 +5255,8 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git · 5254 unmodified lines
52555255 F: Documentation/admin-guide/cgroup-v1/cpusets.rst
52565256 F: include/linux/cpuset.h
52575257 F: kernel/cgroup/cpuset.c
5258+F: tools/testing/selftests/cgroup/test_cpuset.c
5259+F: tools/testing/selftests/cgroup/test_cpuset_prs.sh
52585260
52595261 CONTROL GROUP - MEMORY RESOURCE CONTROLLER (MEMCG)
52605262 M: Johannes Weiner <hannes@cmpxchg.org>
include/linux/cgroup-defs.h+14−0
@@ -341,6 +341,20 @@ struct cgroup_rstat_cpu { · 340 unmodified lines
341341 */
342342 struct cgroup_base_stat last_bstat;
343343
344+ /*
345+ * This field is used to record the cumulative per-cpu time of
346+ * the cgroup and its descendants. Currently it can be read via
347+ * eBPF/drgn etc, and we are still trying to determine how to
348+ * expose it in the cgroupfs interface.
349+ */
350+ struct cgroup_base_stat subtree_bstat;
351+
352+ /*
353+ * Snapshots at the last reading. These are used to calculate the
354+ * deltas to propagate to the per-cpu subtree_bstat.
355+ */
356+ struct cgroup_base_stat last_subtree_bstat;
357+
344358 /*
345359 * Child cgroups with stat updates on this cpu since the last read
346360 * are linked on the parent's ->updated_children through
include/linux/misc_cgroup.h+13−15
@@ -31,17 +31,18 @@ struct misc_cg; · 30 unmodified lines
3131 * struct misc_res: Per cgroup per misc type resource
3232 * @max: Maximum limit on the resource.
3333 * @usage: Current usage of the resource.
34− * @failed: True if charged failed for the resource in a cgroup.
34+ * @events: Number of times, the resource limit exceeded.
3535 */
3636 struct misc_res {
37− unsigned long max;
38− atomic_long_t usage;
39− atomic_long_t events;
37+ u64 max;
38+ atomic64_t usage;
39+ atomic64_t events;
4040 };
4141
4242 /**
4343 * struct misc_cg - Miscellaneous controller's cgroup structure.
4444 * @css: cgroup subsys state object.
45+ * @events_file: Handle for the misc resources events file.
4546 * @res: Array of misc resources usage in the cgroup.
4647 */
4748 struct misc_cg {
@@ -53,12 +54,10 @@ struct misc_cg { · 5 unmodified lines
5354 struct misc_res res[MISC_CG_RES_TYPES];
5455 };
5556
56−unsigned long misc_cg_res_total_usage(enum misc_res_type type);
57−int misc_cg_set_capacity(enum misc_res_type type, unsigned long capacity);
58−int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg,
59− unsigned long amount);
60−void misc_cg_uncharge(enum misc_res_type type, struct misc_cg *cg,
61− unsigned long amount);
57+u64 misc_cg_res_total_usage(enum misc_res_type type);
58+int misc_cg_set_capacity(enum misc_res_type type, u64 capacity);
59+int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg, u64 amount);
60+void misc_cg_uncharge(enum misc_res_type type, struct misc_cg *cg, u64 amount);
6261
6362 /**
6463 * css_misc() - Get misc cgroup from the css.
@@ -99,27 +98,26 @@ static inline void put_misc_cg(struct misc_cg *cg) · 34 unmodified lines
9998
10099 #else /* !CONFIG_CGROUP_MISC */
101100
102−static inline unsigned long misc_cg_res_total_usage(enum misc_res_type type)
101+static inline u64 misc_cg_res_total_usage(enum misc_res_type type)
103102 {
104103 return 0;
105104 }
106105
107−static inline int misc_cg_set_capacity(enum misc_res_type type,
108− unsigned long capacity)
106+static inline int misc_cg_set_capacity(enum misc_res_type type, u64 capacity)
109107 {
110108 return 0;
111109 }
112110
113111 static inline int misc_cg_try_charge(enum misc_res_type type,
114112 struct misc_cg *cg,
115− unsigned long amount)
113+ u64 amount)
116114 {
117115 return 0;
118116 }
119117
120118 static inline void misc_cg_uncharge(enum misc_res_type type,
121119 struct misc_cg *cg,
122− unsigned long amount)
120+ u64 amount)
123121 {
124122 }
125123
include/uapi/linux/cgroupstats.h+0−2
@@ -24,8 +24,6 @@ · 23 unmodified lines
2424 * basis. This data is shared using taskstats.
2525 *
2626 * Most of these states are derived by looking at the task->state value
27− * For the nr_io_wait state, a flag in the delay accounting structure
28− * indicates that the task is waiting on IO
2927 *
3028 * Each member is aligned to a 8 byte boundary.
3129 */
kernel/cgroup/cgroup-v1.c+1−1
@@ -431,7 +431,7 @@ static void *cgroup_pidlist_start(struct seq_file *s, loff_t *pos) · 430 unmodified lines
431431 if (l->list[mid] == pid) {
432432 index = mid;
433433 break;
434− } else if (l->list[mid] <= pid)
434+ } else if (l->list[mid] < pid)
435435 index = mid + 1;
436436 else
437437 end = mid;
kernel/cgroup/cgroup.c+41−44
@@ -492,28 +492,6 @@ static struct cgroup_subsys_state *cgroup_css(struct cgroup *cgrp, · 491 unmodified lines
492492 return &cgrp->self;
493493 }
494494
495−/**
496− * cgroup_tryget_css - try to get a cgroup's css for the specified subsystem
497− * @cgrp: the cgroup of interest
498− * @ss: the subsystem of interest
499− *
500− * Find and get @cgrp's css associated with @ss. If the css doesn't exist
501− * or is offline, %NULL is returned.
502− */
503−static struct cgroup_subsys_state *cgroup_tryget_css(struct cgroup *cgrp,
504− struct cgroup_subsys *ss)
505−{
506− struct cgroup_subsys_state *css;
507−
508− rcu_read_lock();
509− css = cgroup_css(cgrp, ss);
510− if (css && !css_tryget_online(css))
511− css = NULL;
512− rcu_read_unlock();
513−
514− return css;
515−}
516−
517495 /**
518496 * cgroup_e_css_by_mask - obtain a cgroup's effective css for the specified ss
519497 * @cgrp: the cgroup of interest
@@ -679,7 +657,7 @@ EXPORT_SYMBOL_GPL(of_css); · 159 unmodified lines
679657 * @ssid: the index of the subsystem, CGROUP_SUBSYS_COUNT after reaching the end
680658 * @cgrp: the target cgroup to iterate css's of
681659 *
682− * Should be called under cgroup_[tree_]mutex.
660+ * Should be called under cgroup_mutex.
683661 */
684662 #define for_each_css(css, ssid, cgrp) \
685663 for ((ssid) = 0; (ssid) < CGROUP_SUBSYS_COUNT; (ssid)++) \
@@ -929,7 +907,7 @@ static void css_set_move_task(struct task_struct *task, · 243 unmodified lines
929907 #define CSS_SET_HASH_BITS 7
930908 static DEFINE_HASHTABLE(css_set_table, CSS_SET_HASH_BITS);
931909
932−static unsigned long css_set_hash(struct cgroup_subsys_state *css[])
910+static unsigned long css_set_hash(struct cgroup_subsys_state **css)
933911 {
934912 unsigned long key = 0UL;
935913 struct cgroup_subsys *ss;
@@ -1070,7 +1048,7 @@ static bool compare_css_sets(struct css_set *cset, · 134 unmodified lines
10701048 */
10711049 static struct css_set *find_existing_css_set(struct css_set *old_cset,
10721050 struct cgroup *cgrp,
1073− struct cgroup_subsys_state *template[])
1051+ struct cgroup_subsys_state **template)
10741052 {
10751053 struct cgroup_root *root = cgrp->root;
10761054 struct cgroup_subsys *ss;
@@ -1736,7 +1714,7 @@ static int css_populate_dir(struct cgroup_subsys_state *css) · 659 unmodified lines
17361714 struct cftype *cfts, *failed_cfts;
17371715 int ret;
17381716
1739− if ((css->flags & CSS_VISIBLE) || !cgrp->kn)
1717+ if (css->flags & CSS_VISIBLE)
17401718 return 0;
17411719
17421720 if (!css->ss) {
@@ -2499,7 +2477,7 @@ struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset, · 756 unmodified lines
24992477
25002478 /*
25012479 * This function may be called both before and
2502− * after cgroup_taskset_migrate(). The two cases
2480+ * after cgroup_migrate_execute(). The two cases
25032481 * can be distinguished by looking at whether @cset
25042482 * has its ->mg_dst_cset set.
25052483 */
@@ -3654,9 +3632,32 @@ static int cgroup_stat_show(struct seq_file *seq, void *v) · 1148 unmodified lines
36543632 return 0;
36553633 }
36563634
3657−static int __maybe_unused cgroup_extra_stat_show(struct seq_file *seq,
3658− struct cgroup *cgrp, int ssid)
3635+#ifdef CONFIG_CGROUP_SCHED
3636+/**
3637+ * cgroup_tryget_css - try to get a cgroup's css for the specified subsystem
3638+ * @cgrp: the cgroup of interest
3639+ * @ss: the subsystem of interest
3640+ *
3641+ * Find and get @cgrp's css associated with @ss. If the css doesn't exist
3642+ * or is offline, %NULL is returned.
3643+ */
3644+static struct cgroup_subsys_state *cgroup_tryget_css(struct cgroup *cgrp,
3645+ struct cgroup_subsys *ss)
36593646 {
3647+ struct cgroup_subsys_state *css;
3648+
3649+ rcu_read_lock();
3650+ css = cgroup_css(cgrp, ss);
3651+ if (css && !css_tryget_online(css))
3652+ css = NULL;
3653+ rcu_read_unlock();
3654+
3655+ return css;
3656+}
3657+
3658+static int cgroup_extra_stat_show(struct seq_file *seq, int ssid)
3659+{
3660+ struct cgroup *cgrp = seq_css(seq)->cgroup;
36603661 struct cgroup_subsys *ss = cgroup_subsys[ssid];
36613662 struct cgroup_subsys_state *css;
36623663 int ret;
@@ -3672,15 +3673,15 @@ static int __maybe_unused cgroup_extra_stat_show(struct seq_file *seq, · 9 unmodified lines
36723673 css_put(css);
36733674 return ret;
36743675 }
3676+#endif
36753677
36763678 static int cpu_stat_show(struct seq_file *seq, void *v)
36773679 {
3678− struct cgroup __maybe_unused *cgrp = seq_css(seq)->cgroup;
36793680 int ret = 0;
36803681
36813682 cgroup_base_stat_cputime_show(seq);
36823683 #ifdef CONFIG_CGROUP_SCHED
3683− ret = cgroup_extra_stat_show(seq, cgrp, cpu_cgrp_id);
3684+ ret = cgroup_extra_stat_show(seq, cpu_cgrp_id);
36843685 #endif
36853686 return ret;
36863687 }
@@ -4350,14 +4351,13 @@ static int cgroup_init_cftypes(struct cgroup_subsys *ss, struct cftype *cfts) · 663 unmodified lines
43504351 return ret;
43514352 }
43524353
4353−static int cgroup_rm_cftypes_locked(struct cftype *cfts)
4354+static void cgroup_rm_cftypes_locked(struct cftype *cfts)
43544355 {
43554356 lockdep_assert_held(&cgroup_mutex);
43564357
43574358 list_del(&cfts->node);
43584359 cgroup_apply_cftypes(cfts, false);
43594360 cgroup_exit_cftypes(cfts);
4360− return 0;
43614361 }
43624362
43634363 /**
@@ -4373,8 +4373,6 @@ static int cgroup_rm_cftypes_locked(struct cftype *cfts) · 9 unmodified lines
43734373 */
43744374 int cgroup_rm_cftypes(struct cftype *cfts)
43754375 {
4376− int ret;
4377−
43784376 if (!cfts || cfts[0].name[0] == '\0')
43794377 return 0;
43804378
@@ -4382,9 +4380,9 @@ int cgroup_rm_cftypes(struct cftype *cfts) · 1 unmodified line
43824380 return -ENOENT;
43834381
43844382 cgroup_lock();
4385− ret = cgroup_rm_cftypes_locked(cfts);
4383+ cgroup_rm_cftypes_locked(cfts);
43864384 cgroup_unlock();
4387− return ret;
4385+ return 0;
43884386 }
43894387
43904388 /**
@@ -5337,7 +5335,7 @@ static struct cftype cgroup_psi_files[] = { · 946 unmodified lines
53375335 * RCU callback.
53385336 *
53395337 * 4. After the grace period, the css can be freed. Implemented in
5340− * css_free_work_fn().
5338+ * css_free_rwork_fn().
53415339 *
53425340 * It is actually hairier because both step 2 and 4 require process context
53435341 * and thus involve punting to css->destroy_work adding two additional
@@ -5581,8 +5579,7 @@ err_free_css: · 237 unmodified lines
55815579
55825580 /*
55835581 * The returned cgroup is fully initialized including its control mask, but
5584− * it isn't associated with its kernfs_node and doesn't have the control
5585− * mask applied.
5582+ * it doesn't have the control mask applied.
55865583 */
55875584 static struct cgroup *cgroup_create(struct cgroup *parent, const char *name,
55885585 umode_t mode)
@@ -5908,7 +5905,7 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) · 319 unmodified lines
59085905 /*
59095906 * Mark @cgrp and the associated csets dead. The former prevents
59105907 * further task migration and child creation by disabling
5911− * cgroup_lock_live_group(). The latter makes the csets ignored by
5908+ * cgroup_kn_lock_live(). The latter makes the csets ignored by
59125909 * the migration path.
59135910 */
59145911 cgrp->self.flags &= ~CSS_ONLINE;
@@ -5930,7 +5927,7 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) · 15 unmodified lines
59305927 parent->nr_threaded_children--;
59315928
59325929 spin_lock_irq(&css_set_lock);
5933− for (tcgrp = cgroup_parent(cgrp); tcgrp; tcgrp = cgroup_parent(tcgrp)) {
5930+ for (tcgrp = parent; tcgrp; tcgrp = cgroup_parent(tcgrp)) {
59345931 tcgrp->nr_descendants--;
59355932 tcgrp->nr_dying_descendants++;
59365933 /*
@@ -6123,8 +6120,8 @@ int __init cgroup_init(void) · 186 unmodified lines
61236120 continue;
61246121
61256122 if (cgroup1_ssid_disabled(ssid))
6126− printk(KERN_INFO "Disabling %s control group subsystem in v1 mounts\n",
6127− ss->name);
6123+ pr_info("Disabling %s control group subsystem in v1 mounts\n",
6124+ ss->name);
61286125
61296126 cgrp_dfl_root.subsys_mask |= 1 << ss->id;
61306127
kernel/cgroup/cpuset.c+164−100
@@ -1230,7 +1230,7 @@ static void update_tasks_cpumask(struct cpuset *cs, struct cpumask *new_cpus) · 1229 unmodified lines
12301230 /*
12311231 * Percpu kthreads in top_cpuset are ignored
12321232 */
1233− if ((task->flags & PF_KTHREAD) && kthread_is_per_cpu(task))
1233+ if (kthread_is_per_cpu(task))
12341234 continue;
12351235 cpumask_andnot(new_cpus, possible_mask, cs->subparts_cpus);
12361236 } else {
@@ -1255,7 +1255,7 @@ static void update_tasks_cpumask(struct cpuset *cs, struct cpumask *new_cpus) · 18 unmodified lines
12551255 static void compute_effective_cpumask(struct cpumask *new_cpus,
12561256 struct cpuset *cs, struct cpuset *parent)
12571257 {
1258− if (parent->nr_subparts_cpus) {
1258+ if (parent->nr_subparts_cpus && is_partition_valid(cs)) {
12591259 cpumask_or(new_cpus, parent->effective_cpus,
12601260 parent->subparts_cpus);
12611261 cpumask_and(new_cpus, new_cpus, cs->cpus_allowed);
@@ -1277,6 +1277,52 @@ enum subparts_cmd { · 15 unmodified lines
12771277
12781278 static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs,
12791279 int turning_on);
1280+static void update_sibling_cpumasks(struct cpuset *parent, struct cpuset *cs,
1281+ struct tmpmasks *tmp);
1282+
1283+/*
1284+ * Update partition exclusive flag
1285+ *
1286+ * Return: 0 if successful, an error code otherwise
1287+ */
1288+static int update_partition_exclusive(struct cpuset *cs, int new_prs)
1289+{
1290+ bool exclusive = (new_prs > 0);
1291+
1292+ if (exclusive && !is_cpu_exclusive(cs)) {
1293+ if (update_flag(CS_CPU_EXCLUSIVE, cs, 1))
1294+ return PERR_NOTEXCL;
1295+ } else if (!exclusive && is_cpu_exclusive(cs)) {
1296+ /* Turning off CS_CPU_EXCLUSIVE will not return error */
1297+ update_flag(CS_CPU_EXCLUSIVE, cs, 0);
1298+ }
1299+ return 0;
1300+}
1301+
1302+/*
1303+ * Update partition load balance flag and/or rebuild sched domain
1304+ *
1305+ * Changing load balance flag will automatically call
1306+ * rebuild_sched_domains_locked().
1307+ */
1308+static void update_partition_sd_lb(struct cpuset *cs, int old_prs)
1309+{
1310+ int new_prs = cs->partition_root_state;
1311+ bool new_lb = (new_prs != PRS_ISOLATED);
1312+ bool rebuild_domains = (new_prs > 0) || (old_prs > 0);
1313+
1314+ if (new_lb != !!is_sched_load_balance(cs)) {
1315+ rebuild_domains = true;
1316+ if (new_lb)
1317+ set_bit(CS_SCHED_LOAD_BALANCE, &cs->flags);
1318+ else
1319+ clear_bit(CS_SCHED_LOAD_BALANCE, &cs->flags);
1320+ }
1321+
1322+ if (rebuild_domains)
1323+ rebuild_sched_domains_locked();
1324+}
1325+
12801326 /**
12811327 * update_parent_subparts_cpumask - update subparts_cpus mask of parent cpuset
12821328 * @cs: The cpuset that requests change in partition root state
@@ -1336,8 +1382,7 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd, · 53 unmodified lines
13361382 return is_partition_invalid(parent)
13371383 ? PERR_INVPARENT : PERR_NOTPART;
13381384 }
1339− if ((newmask && cpumask_empty(newmask)) ||
1340− (!newmask && cpumask_empty(cs->cpus_allowed)))
1385+ if (!newmask && cpumask_empty(cs->cpus_allowed))
13411386 return PERR_CPUSEMPTY;
13421387
13431388 /*
@@ -1403,11 +1448,16 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd, · 59 unmodified lines
14031448 cpumask_and(tmp->addmask, newmask, parent->cpus_allowed);
14041449 adding = cpumask_andnot(tmp->addmask, tmp->addmask,
14051450 parent->subparts_cpus);
1451+ /*
1452+ * Empty cpumask is not allowed
1453+ */
1454+ if (cpumask_empty(newmask)) {
1455+ part_error = PERR_CPUSEMPTY;
14061456 /*
14071457 * Make partition invalid if parent's effective_cpus could
14081458 * become empty and there are tasks in the parent.
14091459 */
1410− if (adding &&
1460+ } else if (adding &&
14111461 cpumask_subset(parent->effective_cpus, tmp->addmask) &&
14121462 !cpumask_intersects(tmp->delmask, cpu_active_mask) &&
14131463 partition_is_populated(parent, cs)) {
@@ -1480,14 +1530,13 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd, · 66 unmodified lines
14801530
14811531 /*
14821532 * Transitioning between invalid to valid or vice versa may require
1483− * changing CS_CPU_EXCLUSIVE and CS_SCHED_LOAD_BALANCE.
1533+ * changing CS_CPU_EXCLUSIVE.
14841534 */
14851535 if (old_prs != new_prs) {
1486− if (is_prs_invalid(old_prs) && !is_cpu_exclusive(cs) &&
1487− (update_flag(CS_CPU_EXCLUSIVE, cs, 1) < 0))
1488− return PERR_NOTEXCL;
1489− if (is_prs_invalid(new_prs) && is_cpu_exclusive(cs))
1490− update_flag(CS_CPU_EXCLUSIVE, cs, 0);
1536+ int err = update_partition_exclusive(cs, new_prs);
1537+
1538+ if (err)
1539+ return err;
14911540 }
14921541
14931542 /*
@@ -1520,23 +1569,33 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd, · 26 unmodified lines
15201569
15211570 spin_unlock_irq(&callback_lock);
15221571
1523− if (adding || deleting)
1572+ if (adding || deleting) {
15241573 update_tasks_cpumask(parent, tmp->addmask);
1574+ if (parent->child_ecpus_count)
1575+ update_sibling_cpumasks(parent, cs, tmp);
1576+ }
15251577
15261578 /*
1527− * Set or clear CS_SCHED_LOAD_BALANCE when partcmd_update, if necessary.
1528− * rebuild_sched_domains_locked() may be called.
1579+ * For partcmd_update without newmask, it is being called from
1580+ * cpuset_hotplug_workfn() where cpus_read_lock() wasn't taken.
1581+ * Update the load balance flag and scheduling domain if
1582+ * cpus_read_trylock() is successful.
15291583 */
1530− if (old_prs != new_prs) {
1531− if (old_prs == PRS_ISOLATED)
1532− update_flag(CS_SCHED_LOAD_BALANCE, cs, 1);
1533− else if (new_prs == PRS_ISOLATED)
1534− update_flag(CS_SCHED_LOAD_BALANCE, cs, 0);
1584+ if ((cmd == partcmd_update) && !newmask && cpus_read_trylock()) {
1585+ update_partition_sd_lb(cs, old_prs);
1586+ cpus_read_unlock();
15351587 }
1588+
15361589 notify_partition_change(cs, old_prs);
15371590 return 0;
15381591 }
15391592
1593+/*
1594+ * update_cpumasks_hier() flags
1595+ */
1596+#define HIER_CHECKALL 0x01 /* Check all cpusets with no skipping */
1597+#define HIER_NO_SD_REBUILD 0x02 /* Don't rebuild sched domains */
1598+
15401599 /*
15411600 * update_cpumasks_hier - Update effective cpumasks and tasks in the subtree
15421601 * @cs: the cpuset to consider
@@ -1551,7 +1610,7 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd, · 8 unmodified lines
15511610 * Called with cpuset_mutex held
15521611 */
15531612 static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp,
1554− bool force)
1613+ int flags)
15551614 {
15561615 struct cpuset *cp;
15571616 struct cgroup_subsys_state *pos_css;
@@ -1588,11 +1647,16 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp, · 30 unmodified lines
15881647 }
15891648
15901649 /*
1591− * Skip the whole subtree if the cpumask remains the same
1592− * and has no partition root state and force flag not set.
1650+ * Skip the whole subtree if
1651+ * 1) the cpumask remains the same,
1652+ * 2) has no partition root state,
1653+ * 3) HIER_CHECKALL flag not set, and
1654+ * 4) for v2 load balance state same as its parent.
15931655 */
1594− if (!cp->partition_root_state && !force &&
1595− cpumask_equal(tmp->new_cpus, cp->effective_cpus)) {
1656+ if (!cp->partition_root_state && !(flags & HIER_CHECKALL) &&
1657+ cpumask_equal(tmp->new_cpus, cp->effective_cpus) &&
1658+ (!cgroup_subsys_on_dfl(cpuset_cgrp_subsys) ||
1659+ (is_sched_load_balance(parent) == is_sched_load_balance(cp)))) {
15961660 pos_css = css_rightmost_descendant(pos_css);
15971661 continue;
15981662 }
@@ -1675,6 +1739,20 @@ update_parent_subparts: · 76 unmodified lines
16751739
16761740 update_tasks_cpumask(cp, tmp->new_cpus);
16771741
1742+ /*
1743+ * On default hierarchy, inherit the CS_SCHED_LOAD_BALANCE
1744+ * from parent if current cpuset isn't a valid partition root
1745+ * and their load balance states differ.
1746+ */
1747+ if (cgroup_subsys_on_dfl(cpuset_cgrp_subsys) &&
1748+ !is_partition_valid(cp) &&
1749+ (is_sched_load_balance(parent) != is_sched_load_balance(cp))) {
1750+ if (is_sched_load_balance(parent))
1751+ set_bit(CS_SCHED_LOAD_BALANCE, &cp->flags);
1752+ else
1753+ clear_bit(CS_SCHED_LOAD_BALANCE, &cp->flags);
1754+ }
1755+
16781756 /*
16791757 * On legacy hierarchy, if the effective cpumask of any non-
16801758 * empty cpuset is changed, we need to rebuild sched domains.
@@ -1692,7 +1770,7 @@ update_parent_subparts: · 11 unmodified lines
16921770 }
16931771 rcu_read_unlock();
16941772
1695− if (need_rebuild_sched_domains)
1773+ if (need_rebuild_sched_domains && !(flags & HIER_NO_SD_REBUILD))
16961774 rebuild_sched_domains_locked();
16971775 }
16981776
@@ -1716,7 +1794,9 @@ static void update_sibling_cpumasks(struct cpuset *parent, struct cpuset *cs, · 17 unmodified lines
17161794 * to use the right effective_cpus value.
17171795 *
17181796 * The update_cpumasks_hier() function may sleep. So we have to
1719− * release the RCU read lock before calling it.
1797+ * release the RCU read lock before calling it. HIER_NO_SD_REBUILD
1798+ * flag is used to suppress rebuild of sched domains as the callers
1799+ * will take care of that.
17201800 */
17211801 rcu_read_lock();
17221802 cpuset_for_each_child(sibling, pos_css, parent) {
@@ -1728,7 +1808,7 @@ static void update_sibling_cpumasks(struct cpuset *parent, struct cpuset *cs, · 5 unmodified lines
17281808 continue;
17291809
17301810 rcu_read_unlock();
1731− update_cpumasks_hier(sibling, tmp, false);
1811+ update_cpumasks_hier(sibling, tmp, HIER_NO_SD_REBUILD);
17321812 rcu_read_lock();
17331813 css_put(&sibling->css);
17341814 }
@@ -1747,6 +1827,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs, · 12 unmodified lines
17471827 int retval;
17481828 struct tmpmasks tmp;
17491829 bool invalidate = false;
1830+ int old_prs = cs->partition_root_state;
17501831
17511832 /* top_cpuset.cpus_allowed tracks cpu_online_mask; it's read-only */
17521833 if (cs == &top_cpuset)
@@ -1774,18 +1855,8 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs, · 21 unmodified lines
17741855 if (cpumask_equal(cs->cpus_allowed, trialcs->cpus_allowed))
17751856 return 0;
17761857
1777−#ifdef CONFIG_CPUMASK_OFFSTACK
1778− /*
1779− * Use the cpumasks in trialcs for tmpmasks when they are pointers
1780− * to allocated cpumasks.
1781− *
1782− * Note that update_parent_subparts_cpumask() uses only addmask &
1783− * delmask, but not new_cpus.
1784− */
1785− tmp.addmask = trialcs->subparts_cpus;
1786− tmp.delmask = trialcs->effective_cpus;
1787− tmp.new_cpus = NULL;
1788−#endif
1858+ if (alloc_cpumasks(NULL, &tmp))
1859+ return -ENOMEM;
17891860
17901861 retval = validate_change(cs, trialcs);
17911862
@@ -1814,7 +1885,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs, · 22 unmodified lines
18141885 retval = 0;
18151886 }
18161887 if (retval < 0)
1817− return retval;
1888+ goto out_free;
18181889
18191890 if (cs->partition_root_state) {
18201891 if (invalidate)
@@ -1849,13 +1920,8 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs, · 28 unmodified lines
18491920 }
18501921 spin_unlock_irq(&callback_lock);
18511922
1852−#ifdef CONFIG_CPUMASK_OFFSTACK
1853− /* Now trialcs->cpus_allowed is available */
1854− tmp.new_cpus = trialcs->cpus_allowed;
1855−#endif
1856−
18571923 /* effective_cpus will be updated here */
1858− update_cpumasks_hier(cs, &tmp, false);
1924+ update_cpumasks_hier(cs, &tmp, 0);
18591925
18601926 if (cs->partition_root_state) {
18611927 struct cpuset *parent = parent_cs(cs);
@@ -1866,7 +1932,12 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs, · 4 unmodified lines
18661932 */
18671933 if (parent->child_ecpus_count)
18681934 update_sibling_cpumasks(parent, cs, &tmp);
1935+
1936+ /* Update CS_SCHED_LOAD_BALANCE and/or sched_domains */
1937+ update_partition_sd_lb(cs, old_prs);
18691938 }
1939+out_free:
1940+ free_cpumasks(NULL, &tmp);
18701941 return 0;
18711942 }
18721943
@@ -2242,7 +2313,6 @@ out: · 369 unmodified lines
22422313 static int update_prstate(struct cpuset *cs, int new_prs)
22432314 {
22442315 int err = PERR_NONE, old_prs = cs->partition_root_state;
2245− bool sched_domain_rebuilt = false;
22462316 struct cpuset *parent = parent_cs(cs);
22472317 struct tmpmasks tmpmask;
22482318
@@ -2261,45 +2331,26 @@ static int update_prstate(struct cpuset *cs, int new_prs) · 12 unmodified lines
22612331 if (alloc_cpumasks(NULL, &tmpmask))
22622332 return -ENOMEM;
22632333
2334+ err = update_partition_exclusive(cs, new_prs);
2335+ if (err)
2336+ goto out;
2337+
22642338 if (!old_prs) {
22652339 /*
2266− * Turning on partition root requires setting the
2267− * CS_CPU_EXCLUSIVE bit implicitly as well and cpus_allowed
2268− * cannot be empty.
2340+ * cpus_allowed cannot be empty.
22692341 */
22702342 if (cpumask_empty(cs->cpus_allowed)) {
22712343 err = PERR_CPUSEMPTY;
22722344 goto out;
22732345 }
22742346
2275− err = update_flag(CS_CPU_EXCLUSIVE, cs, 1);
2276− if (err) {
2277− err = PERR_NOTEXCL;
2278− goto out;
2279− }
2280−
22812347 err = update_parent_subparts_cpumask(cs, partcmd_enable,
22822348 NULL, &tmpmask);
2283− if (err) {
2284− update_flag(CS_CPU_EXCLUSIVE, cs, 0);
2285− goto out;
2286− }
2287−
2288− if (new_prs == PRS_ISOLATED) {
2289− /*
2290− * Disable the load balance flag should not return an
2291− * error unless the system is running out of memory.
2292− */
2293− update_flag(CS_SCHED_LOAD_BALANCE, cs, 0);
2294− sched_domain_rebuilt = true;
2295− }
22962349 } else if (old_prs && new_prs) {
22972350 /*
22982351 * A change in load balance state only, no change in cpumasks.
22992352 */
2300− update_flag(CS_SCHED_LOAD_BALANCE, cs, (new_prs != PRS_ISOLATED));
2301− sched_domain_rebuilt = true;
2302− goto out; /* Sched domain is rebuilt in update_flag() */
2353+ ;
23032354 } else {
23042355 /*
23052356 * Switching back to member is always allowed even if it
@@ -2318,40 +2369,31 @@ static int update_prstate(struct cpuset *cs, int new_prs) · 12 unmodified lines
23182369 compute_effective_cpumask(cs->effective_cpus, cs, parent);
23192370 spin_unlock_irq(&callback_lock);
23202371 }
2321−
2322− /* Turning off CS_CPU_EXCLUSIVE will not return error */
2323− update_flag(CS_CPU_EXCLUSIVE, cs, 0);
2324−
2325− if (!is_sched_load_balance(cs)) {
2326− /* Make sure load balance is on */
2327− update_flag(CS_SCHED_LOAD_BALANCE, cs, 1);
2328− sched_domain_rebuilt = true;
2329− }
23302372 }
2331−
2332− update_tasks_cpumask(parent, tmpmask.new_cpus);
2333−
2334− if (parent->child_ecpus_count)
2335− update_sibling_cpumasks(parent, cs, &tmpmask);
2336−
2337− if (!sched_domain_rebuilt)
2338− rebuild_sched_domains_locked();
23392373 out:
23402374 /*
2341− * Make partition invalid if an error happen
2375+ * Make partition invalid & disable CS_CPU_EXCLUSIVE if an error
2376+ * happens.
23422377 */
2343− if (err)
2378+ if (err) {
23442379 new_prs = -new_prs;
2380+ update_partition_exclusive(cs, new_prs);
2381+ }
2382+
23452383 spin_lock_irq(&callback_lock);
23462384 cs->partition_root_state = new_prs;
23472385 WRITE_ONCE(cs->prs_err, err);
23482386 spin_unlock_irq(&callback_lock);
2387+
23492388 /*
23502389 * Update child cpusets, if present.
23512390 * Force update if switching back to member.
23522391 */
23532392 if (!list_empty(&cs->css.children))
2354− update_cpumasks_hier(cs, &tmpmask, !new_prs);
2393+ update_cpumasks_hier(cs, &tmpmask, !new_prs ? HIER_CHECKALL : 0);
2394+
2395+ /* Update sched domains and load balance flag */
2396+ update_partition_sd_lb(cs, old_prs);
23552397
23562398 notify_partition_change(cs, old_prs);
23572399 free_cpumasks(NULL, &tmpmask);
@@ -2487,6 +2529,7 @@ static int cpuset_can_attach(struct cgroup_taskset *tset) · 129 unmodified lines
24872529 struct cgroup_subsys_state *css;
24882530 struct cpuset *cs, *oldcs;
24892531 struct task_struct *task;
2532+ bool cpus_updated, mems_updated;
24902533 int ret;
24912534
24922535 /* used later by cpuset_attach() */
@@ -2501,13 +2544,25 @@ static int cpuset_can_attach(struct cgroup_taskset *tset) · 8 unmodified lines
25012544 if (ret)
25022545 goto out_unlock;
25032546
2547+ cpus_updated = !cpumask_equal(cs->effective_cpus, oldcs->effective_cpus);
2548+ mems_updated = !nodes_equal(cs->effective_mems, oldcs->effective_mems);
2549+
25042550 cgroup_taskset_for_each(task, css, tset) {
25052551 ret = task_can_attach(task);
25062552 if (ret)
25072553 goto out_unlock;
2508− ret = security_task_setscheduler(task);
2509− if (ret)
2510− goto out_unlock;
2554+
2555+ /*
2556+ * Skip rights over task check in v2 when nothing changes,
2557+ * migration permission derives from hierarchy ownership in
2558+ * cgroup_procs_write_permission()).
2559+ */
2560+ if (!cgroup_subsys_on_dfl(cpuset_cgrp_subsys) ||
2561+ (cpus_updated || mems_updated)) {
2562+ ret = security_task_setscheduler(task);
2563+ if (ret)
2564+ goto out_unlock;
2565+ }
25112566
25122567 if (dl_task(task)) {
25132568 cs->nr_migrate_dl_tasks++;
@@ -3222,6 +3277,14 @@ static int cpuset_css_online(struct cgroup_subsys_state *css) · 708 unmodified lines
32223277 cs->use_parent_ecpus = true;
32233278 parent->child_ecpus_count++;
32243279 }
3280+
3281+ /*
3282+ * For v2, clear CS_SCHED_LOAD_BALANCE if parent is isolated
3283+ */
3284+ if (cgroup_subsys_on_dfl(cpuset_cgrp_subsys) &&
3285+ !is_sched_load_balance(parent))
3286+ clear_bit(CS_SCHED_LOAD_BALANCE, &cs->flags);
3287+
32253288 spin_unlock_irq(&callback_lock);
32263289
32273290 if (!test_bit(CGRP_CPUSET_CLONE_CHILDREN, &css->cgroup->flags))
@@ -3521,17 +3584,16 @@ hotplug_update_tasks_legacy(struct cpuset *cs, · 293 unmodified lines
35213584 is_empty = cpumask_empty(cs->cpus_allowed) ||
35223585 nodes_empty(cs->mems_allowed);
35233586
3524− mutex_unlock(&cpuset_mutex);
3525−
35263587 /*
35273588 * Move tasks to the nearest ancestor with execution resources,
35283589 * This is full cgroup operation which will also call back into
35293590 * cpuset. Should be done outside any lock.
35303591 */
3531− if (is_empty)
3592+ if (is_empty) {
3593+ mutex_unlock(&cpuset_mutex);
35323594 remove_tasks_in_empty_cpuset(cs);
3533−
3534− mutex_lock(&cpuset_mutex);
3595+ mutex_lock(&cpuset_mutex);
3596+ }
35353597 }
35363598
35373599 static void
@@ -3691,6 +3753,7 @@ unlock: · 153 unmodified lines
36913753
36923754 /**
36933755 * cpuset_hotplug_workfn - handle CPU/memory hotunplug for a cpuset
3756+ * @work: unused
36943757 *
36953758 * This function is called after either CPU or memory configuration has
36963759 * changed and updates cpuset accordingly. The top_cpuset is always
@@ -4073,6 +4136,7 @@ bool cpuset_node_allowed(int node, gfp_t gfp_mask) · 376 unmodified lines
40734136
40744137 /**
40754138 * cpuset_spread_node() - On which node to begin search for a page
4139+ * @rotor: round robin rotor
40764140 *
40774141 * If a task is marked PF_SPREAD_PAGE or PF_SPREAD_SLAB (as for
40784142 * tasks in a cpuset with is_spread_page or is_spread_slab set),
kernel/cgroup/misc.c+27−28
@@ -14,7 +14,7 @@ · 13 unmodified lines
1414 #include <linux/misc_cgroup.h>
1515
1616 #define MAX_STR "max"
17−#define MAX_NUM ULONG_MAX
17+#define MAX_NUM U64_MAX
1818
1919 /* Miscellaneous res name, keep it in sync with enum misc_res_type */
2020 static const char *const misc_res_name[] = {
@@ -37,7 +37,7 @@ static struct misc_cg root_cg; · 16 unmodified lines
3737 * more than the actual capacity. We are using Limits resource distribution
3838 * model of cgroup for miscellaneous controller.
3939 */
40−static unsigned long misc_res_capacity[MISC_CG_RES_TYPES];
40+static u64 misc_res_capacity[MISC_CG_RES_TYPES];
4141
4242 /**
4343 * parent_misc() - Get the parent of the passed misc cgroup.
@@ -74,10 +74,10 @@ static inline bool valid_type(enum misc_res_type type) · 30 unmodified lines
7474 * Context: Any context.
7575 * Return: Current total usage of the resource.
7676 */
77−unsigned long misc_cg_res_total_usage(enum misc_res_type type)
77+u64 misc_cg_res_total_usage(enum misc_res_type type)
7878 {
7979 if (valid_type(type))
80− return atomic_long_read(&root_cg.res[type].usage);
80+ return atomic64_read(&root_cg.res[type].usage);
8181
8282 return 0;
8383 }
@@ -95,7 +95,7 @@ EXPORT_SYMBOL_GPL(misc_cg_res_total_usage); · 11 unmodified lines
9595 * * %0 - Successfully registered the capacity.
9696 * * %-EINVAL - If @type is invalid.
9797 */
98−int misc_cg_set_capacity(enum misc_res_type type, unsigned long capacity)
98+int misc_cg_set_capacity(enum misc_res_type type, u64 capacity)
9999 {
100100 if (!valid_type(type))
101101 return -EINVAL;
@@ -114,9 +114,9 @@ EXPORT_SYMBOL_GPL(misc_cg_set_capacity); · 12 unmodified lines
114114 * Context: Any context.
115115 */
116116 static void misc_cg_cancel_charge(enum misc_res_type type, struct misc_cg *cg,
117− unsigned long amount)
117+ u64 amount)
118118 {
119− WARN_ONCE(atomic_long_add_negative(-amount, &cg->res[type].usage),
119+ WARN_ONCE(atomic64_add_negative(-amount, &cg->res[type].usage),
120120 "misc cgroup resource %s became less than 0",
121121 misc_res_name[type]);
122122 }
@@ -137,13 +137,12 @@ static void misc_cg_cancel_charge(enum misc_res_type type, struct misc_cg *cg, · 14 unmodified lines
137137 * * -EBUSY - If max limit will be crossed or total usage will be more than the
138138 * capacity.
139139 */
140−int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg,
141− unsigned long amount)
140+int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg, u64 amount)
142141 {
143142 struct misc_cg *i, *j;
144143 int ret;
145144 struct misc_res *res;
146− int new_usage;
145+ u64 new_usage;
147146
148147 if (!(valid_type(type) && cg && READ_ONCE(misc_res_capacity[type])))
149148 return -EINVAL;
@@ -154,7 +153,7 @@ int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg, · 4 unmodified lines
154153 for (i = cg; i; i = parent_misc(i)) {
155154 res = &i->res[type];
156155
157− new_usage = atomic_long_add_return(amount, &res->usage);
156+ new_usage = atomic64_add_return(amount, &res->usage);
158157 if (new_usage > READ_ONCE(res->max) ||
159158 new_usage > READ_ONCE(misc_res_capacity[type])) {
160159 ret = -EBUSY;
@@ -165,7 +164,7 @@ int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg, · 4 unmodified lines
165164
166165 err_charge:
167166 for (j = i; j; j = parent_misc(j)) {
168− atomic_long_inc(&j->res[type].events);
167+ atomic64_inc(&j->res[type].events);
169168 cgroup_file_notify(&j->events_file);
170169 }
171170
@@ -184,8 +183,7 @@ EXPORT_SYMBOL_GPL(misc_cg_try_charge); · 12 unmodified lines
184183 *
185184 * Context: Any context.
186185 */
187−void misc_cg_uncharge(enum misc_res_type type, struct misc_cg *cg,
188− unsigned long amount)
186+void misc_cg_uncharge(enum misc_res_type type, struct misc_cg *cg, u64 amount)
189187 {
190188 struct misc_cg *i;
191189
@@ -209,7 +207,7 @@ static int misc_cg_max_show(struct seq_file *sf, void *v) · 17 unmodified lines
209207 {
210208 int i;
211209 struct misc_cg *cg = css_misc(seq_css(sf));
212− unsigned long max;
210+ u64 max;
213211
214212 for (i = 0; i < MISC_CG_RES_TYPES; i++) {
215213 if (READ_ONCE(misc_res_capacity[i])) {
@@ -217,7 +215,7 @@ static int misc_cg_max_show(struct seq_file *sf, void *v) · 1 unmodified line
217215 if (max == MAX_NUM)
218216 seq_printf(sf, "%s max\n", misc_res_name[i]);
219217 else
220− seq_printf(sf, "%s %lu\n", misc_res_name[i],
218+ seq_printf(sf, "%s %llu\n", misc_res_name[i],
221219 max);
222220 }
223221 }
@@ -241,13 +239,13 @@ static int misc_cg_max_show(struct seq_file *sf, void *v) · 17 unmodified lines
241239 * Return:
242240 * * >= 0 - Number of bytes processed in the input.
243241 * * -EINVAL - If buf is not valid.
244− * * -ERANGE - If number is bigger than the unsigned long capacity.
242+ * * -ERANGE - If number is bigger than the u64 capacity.
245243 */
246244 static ssize_t misc_cg_max_write(struct kernfs_open_file *of, char *buf,
247245 size_t nbytes, loff_t off)
248246 {
249247 struct misc_cg *cg;
250− unsigned long max;
248+ u64 max;
251249 int ret = 0, i;
252250 enum misc_res_type type = MISC_CG_RES_TYPES;
253251 char *token;
@@ -271,7 +269,7 @@ static ssize_t misc_cg_max_write(struct kernfs_open_file *of, char *buf, · 17 unmodified lines
271269 if (!strcmp(MAX_STR, buf)) {
272270 max = MAX_NUM;
273271 } else {
274− ret = kstrtoul(buf, 0, &max);
272+ ret = kstrtou64(buf, 0, &max);
275273 if (ret)
276274 return ret;
277275 }
@@ -297,13 +295,13 @@ static ssize_t misc_cg_max_write(struct kernfs_open_file *of, char *buf, · 19 unmodified lines
297295 static int misc_cg_current_show(struct seq_file *sf, void *v)
298296 {
299297 int i;
300− unsigned long usage;
298+ u64 usage;
301299 struct misc_cg *cg = css_misc(seq_css(sf));
302300
303301 for (i = 0; i < MISC_CG_RES_TYPES; i++) {
304− usage = atomic_long_read(&cg->res[i].usage);
302+ usage = atomic64_read(&cg->res[i].usage);
305303 if (READ_ONCE(misc_res_capacity[i]) || usage)
306− seq_printf(sf, "%s %lu\n", misc_res_name[i], usage);
304+ seq_printf(sf, "%s %llu\n", misc_res_name[i], usage);
307305 }
308306
309307 return 0;
@@ -322,12 +320,12 @@ static int misc_cg_current_show(struct seq_file *sf, void *v) · 12 unmodified lines
322320 static int misc_cg_capacity_show(struct seq_file *sf, void *v)
323321 {
324322 int i;
325− unsigned long cap;
323+ u64 cap;
326324
327325 for (i = 0; i < MISC_CG_RES_TYPES; i++) {
328326 cap = READ_ONCE(misc_res_capacity[i]);
329327 if (cap)
330− seq_printf(sf, "%s %lu\n", misc_res_name[i], cap);
328+ seq_printf(sf, "%s %llu\n", misc_res_name[i], cap);
331329 }
332330
333331 return 0;
@@ -336,12 +334,13 @@ static int misc_cg_capacity_show(struct seq_file *sf, void *v) · 2 unmodified lines
336334 static int misc_events_show(struct seq_file *sf, void *v)
337335 {
338336 struct misc_cg *cg = css_misc(seq_css(sf));
339− unsigned long events, i;
337+ u64 events;
338+ int i;
340339
341340 for (i = 0; i < MISC_CG_RES_TYPES; i++) {
342− events = atomic_long_read(&cg->res[i].events);
341+ events = atomic64_read(&cg->res[i].events);
343342 if (READ_ONCE(misc_res_capacity[i]) || events)
344− seq_printf(sf, "%s.max %lu\n", misc_res_name[i], events);
343+ seq_printf(sf, "%s.max %llu\n", misc_res_name[i], events);
345344 }
346345 return 0;
347346 }
@@ -397,7 +396,7 @@ misc_cg_alloc(struct cgroup_subsys_state *parent_css) · 49 unmodified lines
397396
398397 for (i = 0; i < MISC_CG_RES_TYPES; i++) {
399398 WRITE_ONCE(cg->res[i].max, MAX_NUM);
400− atomic_long_set(&cg->res[i].usage, 0);
399+ atomic64_set(&cg->res[i].usage, 0);
401400 }
402401
403402 return &cg->css;
kernel/cgroup/namespace.c+0−6
@@ -149,9 +149,3 @@ const struct proc_ns_operations cgroupns_operations = { · 148 unmodified lines
149149 .install = cgroupns_install,
150150 .owner = cgroupns_owner,
151151 };
152−
153−static __init int cgroup_namespaces_init(void)
154−{
155− return 0;
156−}
157−subsys_initcall(cgroup_namespaces_init);
kernel/cgroup/rstat.c+10−2
@@ -344,6 +344,7 @@ static void cgroup_base_stat_flush(struct cgroup *cgrp, int cpu) · 343 unmodified lines
344344 {
345345 struct cgroup_rstat_cpu *rstatc = cgroup_rstat_cpu(cgrp, cpu);
346346 struct cgroup *parent = cgroup_parent(cgrp);
347+ struct cgroup_rstat_cpu *prstatc;
347348 struct cgroup_base_stat delta;
348349 unsigned seq;
349350
@@ -357,17 +358,24 @@ static void cgroup_base_stat_flush(struct cgroup *cgrp, int cpu) · 7 unmodified lines
357358 delta = rstatc->bstat;
358359 } while (__u64_stats_fetch_retry(&rstatc->bsync, seq));
359360
360− /* propagate percpu delta to global */
361+ /* propagate per-cpu delta to cgroup and per-cpu global statistics */
361362 cgroup_base_stat_sub(&delta, &rstatc->last_bstat);
362363 cgroup_base_stat_add(&cgrp->bstat, &delta);
363364 cgroup_base_stat_add(&rstatc->last_bstat, &delta);
365+ cgroup_base_stat_add(&rstatc->subtree_bstat, &delta);
364366
365− /* propagate global delta to parent (unless that's root) */
367+ /* propagate cgroup and per-cpu global delta to parent (unless that's root) */
366368 if (cgroup_parent(parent)) {
367369 delta = cgrp->bstat;
368370 cgroup_base_stat_sub(&delta, &cgrp->last_bstat);
369371 cgroup_base_stat_add(&parent->bstat, &delta);
370372 cgroup_base_stat_add(&cgrp->last_bstat, &delta);
373+
374+ delta = rstatc->subtree_bstat;
375+ prstatc = cgroup_rstat_cpu(parent, cpu);
376+ cgroup_base_stat_sub(&delta, &rstatc->last_subtree_bstat);
377+ cgroup_base_stat_add(&prstatc->subtree_bstat, &delta);
378+ cgroup_base_stat_add(&rstatc->last_subtree_bstat, &delta);
371379 }
372380 }
373381
tools/testing/selftests/cgroup/.gitignore+1−0
@@ -5,5 +5,6 @@ test_freezer · 4 unmodified lines
55 test_kmem
66 test_kill
77 test_cpu
8+test_cpuset
89 test_zswap
910 wait_inotify
tools/testing/selftests/cgroup/Makefile+2−0
@@ -12,6 +12,7 @@ TEST_GEN_PROGS += test_core · 11 unmodified lines
1212 TEST_GEN_PROGS += test_freezer
1313 TEST_GEN_PROGS += test_kill
1414 TEST_GEN_PROGS += test_cpu
15+TEST_GEN_PROGS += test_cpuset
1516 TEST_GEN_PROGS += test_zswap
1617
1718 LOCAL_HDRS += $(selfdir)/clone3/clone3_selftests.h $(selfdir)/pidfd/pidfd.h
@@ -24,4 +25,5 @@ $(OUTPUT)/test_core: cgroup_util.c · 6 unmodified lines
2425 $(OUTPUT)/test_freezer: cgroup_util.c
2526 $(OUTPUT)/test_kill: cgroup_util.c
2627 $(OUTPUT)/test_cpu: cgroup_util.c
28+$(OUTPUT)/test_cpuset: cgroup_util.c
2729 $(OUTPUT)/test_zswap: cgroup_util.c
tools/testing/selftests/cgroup/cgroup_util.c+2−0
@@ -286,6 +286,8 @@ int cg_destroy(const char *cgroup) · 285 unmodified lines
286286 {
287287 int ret;
288288
289+ if (!cgroup)
290+ return 0;
289291 retry:
290292 ret = rmdir(cgroup);
291293 if (ret && errno == EBUSY) {
tools/testing/selftests/cgroup/cgroup_util.h+2−0
@@ -11,6 +11,8 @@ · 10 unmodified lines
1111 #define USEC_PER_SEC 1000000L
1212 #define NSEC_PER_SEC 1000000000L
1313
14+#define TEST_UID 65534 /* usually nobody, any !root is fine */
15+
1416 /*
1517 * Checks if two given values differ by less than err% of their sum.
1618 */
tools/testing/selftests/cgroup/test_core.c+1−1
@@ -683,7 +683,7 @@ cleanup: · 682 unmodified lines
683683 */
684684 static int test_cgcore_lesser_euid_open(const char *root)
685685 {
686− const uid_t test_euid = 65534; /* usually nobody, any !root is fine */
686+ const uid_t test_euid = TEST_UID;
687687 int ret = KSFT_FAIL;
688688 char *cg_test_a = NULL, *cg_test_b = NULL;
689689 char *cg_test_a_procs = NULL, *cg_test_b_procs = NULL;
tools/testing/selftests/cgroup/test_cpuset.c+275−0
@@ -0,0 +1,275 @@
1+// SPDX-License-Identifier: GPL-2.0
2+
3+#include <linux/limits.h>
4+#include <signal.h>
5+
6+#include "../kselftest.h"
7+#include "cgroup_util.h"
8+
9+static int idle_process_fn(const char *cgroup, void *arg)
10+{
11+ (void)pause();
12+ return 0;
13+}
14+
15+static int do_migration_fn(const char *cgroup, void *arg)
16+{
17+ int object_pid = (int)(size_t)arg;
18+
19+ if (setuid(TEST_UID))
20+ return EXIT_FAILURE;
21+
22+ // XXX checking /proc/$pid/cgroup would be quicker than wait
23+ if (cg_enter(cgroup, object_pid) ||
24+ cg_wait_for_proc_count(cgroup, 1))
25+ return EXIT_FAILURE;
26+
27+ return EXIT_SUCCESS;
28+}
29+
30+static int do_controller_fn(const char *cgroup, void *arg)
31+{
32+ const char *child = cgroup;
33+ const char *parent = arg;
34+
35+ if (setuid(TEST_UID))
36+ return EXIT_FAILURE;
37+
38+ if (!cg_read_strstr(child, "cgroup.controllers", "cpuset"))
39+ return EXIT_FAILURE;
40+
41+ if (cg_write(parent, "cgroup.subtree_control", "+cpuset"))
42+ return EXIT_FAILURE;
43+
44+ if (cg_read_strstr(child, "cgroup.controllers", "cpuset"))
45+ return EXIT_FAILURE;
46+
47+ if (cg_write(parent, "cgroup.subtree_control", "-cpuset"))
48+ return EXIT_FAILURE;
49+
50+ if (!cg_read_strstr(child, "cgroup.controllers", "cpuset"))
51+ return EXIT_FAILURE;
52+
53+ return EXIT_SUCCESS;
54+}
55+
56+/*
57+ * Migrate a process between two sibling cgroups.
58+ * The success should only depend on the parent cgroup permissions and not the
59+ * migrated process itself (cpuset controller is in place because it uses
60+ * security_task_setscheduler() in cgroup v1).
61+ *
62+ * Deliberately don't set cpuset.cpus in children to avoid definining migration
63+ * permissions between two different cpusets.
64+ */
65+static int test_cpuset_perms_object(const char *root, bool allow)
66+{
67+ char *parent = NULL, *child_src = NULL, *child_dst = NULL;
68+ char *parent_procs = NULL, *child_src_procs = NULL, *child_dst_procs = NULL;
69+ const uid_t test_euid = TEST_UID;
70+ int object_pid = 0;
71+ int ret = KSFT_FAIL;
72+
73+ parent = cg_name(root, "cpuset_test_0");
74+ if (!parent)
75+ goto cleanup;
76+ parent_procs = cg_name(parent, "cgroup.procs");
77+ if (!parent_procs)
78+ goto cleanup;
79+ if (cg_create(parent))
80+ goto cleanup;
81+
82+ child_src = cg_name(parent, "cpuset_test_1");
83+ if (!child_src)
84+ goto cleanup;
85+ child_src_procs = cg_name(child_src, "cgroup.procs");
86+ if (!child_src_procs)
87+ goto cleanup;
88+ if (cg_create(child_src))
89+ goto cleanup;
90+
91+ child_dst = cg_name(parent, "cpuset_test_2");
92+ if (!child_dst)
93+ goto cleanup;
94+ child_dst_procs = cg_name(child_dst, "cgroup.procs");
95+ if (!child_dst_procs)
96+ goto cleanup;
97+ if (cg_create(child_dst))
98+ goto cleanup;
99+
100+ if (cg_write(parent, "cgroup.subtree_control", "+cpuset"))
101+ goto cleanup;
102+
103+ if (cg_read_strstr(child_src, "cgroup.controllers", "cpuset") ||
104+ cg_read_strstr(child_dst, "cgroup.controllers", "cpuset"))
105+ goto cleanup;
106+
107+ /* Enable permissions along src->dst tree path */
108+ if (chown(child_src_procs, test_euid, -1) ||
109+ chown(child_dst_procs, test_euid, -1))
110+ goto cleanup;
111+
112+ if (allow && chown(parent_procs, test_euid, -1))
113+ goto cleanup;
114+
115+ /* Fork a privileged child as a test object */
116+ object_pid = cg_run_nowait(child_src, idle_process_fn, NULL);
117+ if (object_pid < 0)
118+ goto cleanup;
119+
120+ /* Carry out migration in a child process that can drop all privileges
121+ * (including capabilities), the main process must remain privileged for
122+ * cleanup.
123+ * Child process's cgroup is irrelevant but we place it into child_dst
124+ * as hacky way to pass information about migration target to the child.
125+ */
126+ if (allow ^ (cg_run(child_dst, do_migration_fn, (void *)(size_t)object_pid) == EXIT_SUCCESS))
127+ goto cleanup;
128+
129+ ret = KSFT_PASS;
130+
131+cleanup:
132+ if (object_pid > 0) {
133+ (void)kill(object_pid, SIGTERM);
134+ (void)clone_reap(object_pid, WEXITED);
135+ }
136+
137+ cg_destroy(child_dst);
138+ free(child_dst_procs);
139+ free(child_dst);
140+
141+ cg_destroy(child_src);
142+ free(child_src_procs);
143+ free(child_src);
144+
145+ cg_destroy(parent);
146+ free(parent_procs);
147+ free(parent);
148+
149+ return ret;
150+}
151+
152+static int test_cpuset_perms_object_allow(const char *root)
153+{
154+ return test_cpuset_perms_object(root, true);
155+}
156+
157+static int test_cpuset_perms_object_deny(const char *root)
158+{
159+ return test_cpuset_perms_object(root, false);
160+}
161+
162+/*
163+ * Migrate a process between parent and child implicitely
164+ * Implicit migration happens when a controller is enabled/disabled.
165+ *
166+ */
167+static int test_cpuset_perms_subtree(const char *root)
168+{
169+ char *parent = NULL, *child = NULL;
170+ char *parent_procs = NULL, *parent_subctl = NULL, *child_procs = NULL;
171+ const uid_t test_euid = TEST_UID;
172+ int object_pid = 0;
173+ int ret = KSFT_FAIL;
174+
175+ parent = cg_name(root, "cpuset_test_0");
176+ if (!parent)
177+ goto cleanup;
178+ parent_procs = cg_name(parent, "cgroup.procs");
179+ if (!parent_procs)
180+ goto cleanup;
181+ parent_subctl = cg_name(parent, "cgroup.subtree_control");
182+ if (!parent_subctl)
183+ goto cleanup;
184+ if (cg_create(parent))
185+ goto cleanup;
186+
187+ child = cg_name(parent, "cpuset_test_1");
188+ if (!child)
189+ goto cleanup;
190+ child_procs = cg_name(child, "cgroup.procs");
191+ if (!child_procs)
192+ goto cleanup;
193+ if (cg_create(child))
194+ goto cleanup;
195+
196+ /* Enable permissions as in a delegated subtree */
197+ if (chown(parent_procs, test_euid, -1) ||
198+ chown(parent_subctl, test_euid, -1) ||
199+ chown(child_procs, test_euid, -1))
200+ goto cleanup;
201+
202+ /* Put a privileged child in the subtree and modify controller state
203+ * from an unprivileged process, the main process remains privileged
204+ * for cleanup.
205+ * The unprivileged child runs in subtree too to avoid parent and
206+ * internal-node constraing violation.
207+ */
208+ object_pid = cg_run_nowait(child, idle_process_fn, NULL);
209+ if (object_pid < 0)
210+ goto cleanup;
211+
212+ if (cg_run(child, do_controller_fn, parent) != EXIT_SUCCESS)
213+ goto cleanup;
214+
215+ ret = KSFT_PASS;
216+
217+cleanup:
218+ if (object_pid > 0) {
219+ (void)kill(object_pid, SIGTERM);
220+ (void)clone_reap(object_pid, WEXITED);
221+ }
222+
223+ cg_destroy(child);
224+ free(child_procs);
225+ free(child);
226+
227+ cg_destroy(parent);
228+ free(parent_subctl);
229+ free(parent_procs);
230+ free(parent);
231+
232+ return ret;
233+}
234+
235+
236+#define T(x) { x, #x }
237+struct cpuset_test {
238+ int (*fn)(const char *root);
239+ const char *name;
240+} tests[] = {
241+ T(test_cpuset_perms_object_allow),
242+ T(test_cpuset_perms_object_deny),
243+ T(test_cpuset_perms_subtree),
244+};
245+#undef T
246+
247+int main(int argc, char *argv[])
248+{
249+ char root[PATH_MAX];
250+ int i, ret = EXIT_SUCCESS;
251+
252+ if (cg_find_unified_root(root, sizeof(root)))
253+ ksft_exit_skip("cgroup v2 isn't mounted\n");
254+
255+ if (cg_read_strstr(root, "cgroup.subtree_control", "cpuset"))
256+ if (cg_write(root, "cgroup.subtree_control", "+cpuset"))
257+ ksft_exit_skip("Failed to set cpuset controller\n");
258+
259+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
260+ switch (tests[i].fn(root)) {
261+ case KSFT_PASS:
262+ ksft_test_result_pass("%s\n", tests[i].name);
263+ break;
264+ case KSFT_SKIP:
265+ ksft_test_result_skip("%s\n", tests[i].name);
266+ break;
267+ default:
268+ ret = EXIT_FAILURE;
269+ ksft_test_result_fail("%s\n", tests[i].name);
270+ break;
271+ }
272+ }
273+
274+ return ret;
275+}
tools/testing/selftests/cgroup/test_cpuset_prs.sh+1−1
@@ -10,7 +10,7 @@ · 9 unmodified lines
1010 skip_test() {
1111 echo "$1"
1212 echo "Test SKIPPED"
13− exit 0
13+ exit 4 # ksft_skip
1414 }
1515
1616 [[ $(id -u) -eq 0 ]] || skip_test "Test must be run as root!"