Skip to content

Commit 7476a63

Browse files
Waiman-Longhtejun
authored andcommitted
cgroup/cpuset: Show invalid partition reason string
There are a number of different reasons which can cause a partition to become invalid. A user seeing an invalid partition may not know exactly why. To help user to get a better understanding of the underlying reason, The cpuset.cpus.partition control file, when read, will now report the reason why a partition become invalid. When a partition does become invalid, reading the control file will show "root invalid (<reason>)" where <reason> is a string that describes why the partition is invalid. Signed-off-by: Waiman Long <[email protected]> Signed-off-by: Tejun Heo <[email protected]>
1 parent f28e224 commit 7476a63

File tree

1 file changed

+75
-18
lines changed

1 file changed

+75
-18
lines changed

kernel/cgroup/cpuset.c

Lines changed: 75 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,30 @@ struct fmeter {
8686
spinlock_t lock; /* guards read or write of above */
8787
};
8888

89+
/*
90+
* Invalid partition error code
91+
*/
92+
enum prs_errcode {
93+
PERR_NONE = 0,
94+
PERR_INVCPUS,
95+
PERR_INVPARENT,
96+
PERR_NOTPART,
97+
PERR_NOTEXCL,
98+
PERR_NOCPUS,
99+
PERR_HOTPLUG,
100+
PERR_CPUSEMPTY,
101+
};
102+
103+
static const char * const perr_strings[] = {
104+
[PERR_INVCPUS] = "Invalid cpu list in cpuset.cpus",
105+
[PERR_INVPARENT] = "Parent is an invalid partition root",
106+
[PERR_NOTPART] = "Parent is not a partition root",
107+
[PERR_NOTEXCL] = "Cpu list in cpuset.cpus not exclusive",
108+
[PERR_NOCPUS] = "Parent unable to distribute cpu downstream",
109+
[PERR_HOTPLUG] = "No cpu available due to hotplug",
110+
[PERR_CPUSEMPTY] = "cpuset.cpus is empty",
111+
};
112+
89113
struct cpuset {
90114
struct cgroup_subsys_state css;
91115

@@ -169,6 +193,9 @@ struct cpuset {
169193
int use_parent_ecpus;
170194
int child_ecpus_count;
171195

196+
/* Invalid partition error code, not lock protected */
197+
enum prs_errcode prs_err;
198+
172199
/* Handle for cpuset.cpus.partition */
173200
struct cgroup_file partition_file;
174201
};
@@ -298,6 +325,10 @@ static inline void notify_partition_change(struct cpuset *cs, int old_prs)
298325
if (old_prs == cs->partition_root_state)
299326
return;
300327
cgroup_file_notify(&cs->partition_file);
328+
329+
/* Reset prs_err if not invalid */
330+
if (is_partition_valid(cs))
331+
WRITE_ONCE(cs->prs_err, PERR_NONE);
301332
}
302333

303334
static struct cpuset top_cpuset = {
@@ -1235,7 +1266,7 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs,
12351266
* @cmd: Partition root state change command
12361267
* @newmask: Optional new cpumask for partcmd_update
12371268
* @tmp: Temporary addmask and delmask
1238-
* Return: 0 or -1 (error)
1269+
* Return: 0 or a partition root state error code
12391270
*
12401271
* For partcmd_enable, the cpuset is being transformed from a non-partition
12411272
* root to a partition root. The cpus_allowed mask of the given cpuset will
@@ -1261,7 +1292,7 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs,
12611292
*
12621293
* The partcmd_update command is used by update_cpumasks_hier() with newmask
12631294
* NULL and update_cpumask() with newmask set. The callers won't check for
1264-
* error and so partition_root_state will be updated directly.
1295+
* error and so partition_root_state and prs_error will be updated directly.
12651296
*/
12661297
static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd,
12671298
struct cpumask *newmask,
@@ -1271,7 +1302,7 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd,
12711302
int adding; /* Moving cpus from effective_cpus to subparts_cpus */
12721303
int deleting; /* Moving cpus from subparts_cpus to effective_cpus */
12731304
int old_prs, new_prs;
1274-
bool part_error = false; /* Partition error? */
1305+
int part_error = PERR_NONE; /* Partition error? */
12751306

12761307
percpu_rwsem_assert_held(&cpuset_rwsem);
12771308

@@ -1280,10 +1311,13 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd,
12801311
* The new cpumask, if present, or the current cpus_allowed must
12811312
* not be empty.
12821313
*/
1283-
if (!is_partition_valid(parent) ||
1284-
(newmask && cpumask_empty(newmask)) ||
1314+
if (!is_partition_valid(parent)) {
1315+
return is_partition_invalid(parent)
1316+
? PERR_INVPARENT : PERR_NOTPART;
1317+
}
1318+
if ((newmask && cpumask_empty(newmask)) ||
12851319
(!newmask && cpumask_empty(cs->cpus_allowed)))
1286-
return -1;
1320+
return PERR_CPUSEMPTY;
12871321

12881322
/*
12891323
* new_prs will only be changed for the partcmd_update command.
@@ -1296,15 +1330,15 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd,
12961330
* doesn't overlap parent's cpus_allowed.
12971331
*/
12981332
if (!cpumask_intersects(cs->cpus_allowed, parent->cpus_allowed))
1299-
return -1;
1333+
return PERR_INVCPUS;
13001334

13011335
/*
13021336
* A parent can be left with no CPU as long as there is no
13031337
* task directly associated with the parent partition.
13041338
*/
13051339
if (!cpumask_intersects(cs->cpus_allowed, parent->effective_cpus) &&
13061340
partition_is_populated(parent, cs))
1307-
return -1;
1341+
return PERR_NOCPUS;
13081342

13091343
cpumask_copy(tmp->addmask, cs->cpus_allowed);
13101344
adding = true;
@@ -1341,7 +1375,7 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd,
13411375
cpumask_subset(parent->effective_cpus, tmp->addmask) &&
13421376
!cpumask_intersects(tmp->delmask, cpu_active_mask) &&
13431377
partition_is_populated(parent, cs)) {
1344-
part_error = true;
1378+
part_error = PERR_NOCPUS;
13451379
adding = false;
13461380
deleting = cpumask_and(tmp->delmask, cs->cpus_allowed,
13471381
parent->subparts_cpus);
@@ -1373,7 +1407,7 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd,
13731407
(adding &&
13741408
cpumask_subset(parent->effective_cpus, tmp->addmask) &&
13751409
partition_is_populated(parent, cs))) {
1376-
part_error = true;
1410+
part_error = PERR_NOCPUS;
13771411
adding = false;
13781412
}
13791413

@@ -1382,6 +1416,8 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd,
13821416
deleting = cpumask_and(tmp->delmask, cs->cpus_allowed,
13831417
parent->subparts_cpus);
13841418
}
1419+
if (part_error)
1420+
WRITE_ONCE(cs->prs_err, part_error);
13851421

13861422
if (cmd == partcmd_update) {
13871423
/*
@@ -1412,7 +1448,7 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd,
14121448
if (old_prs != new_prs) {
14131449
if (is_prs_invalid(old_prs) && !is_cpu_exclusive(cs) &&
14141450
(update_flag(CS_CPU_EXCLUSIVE, cs, 1) < 0))
1415-
return -1;
1451+
return PERR_NOTEXCL;
14161452
if (is_prs_invalid(new_prs) && is_cpu_exclusive(cs))
14171453
update_flag(CS_CPU_EXCLUSIVE, cs, 0);
14181454
}
@@ -1547,6 +1583,9 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp,
15471583
*/
15481584
if (is_partition_valid(cp))
15491585
new_prs = -cp->partition_root_state;
1586+
WRITE_ONCE(cp->prs_err,
1587+
is_partition_invalid(parent)
1588+
? PERR_INVPARENT : PERR_NOTPART);
15501589
break;
15511590
}
15521591
}
@@ -2121,13 +2160,13 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs,
21212160
* update_prstate - update partition_root_state
21222161
* @cs: the cpuset to update
21232162
* @new_prs: new partition root state
2124-
* Return: 0 if successful, < 0 if error
2163+
* Return: 0 if successful, != 0 if error
21252164
*
21262165
* Call with cpuset_rwsem held.
21272166
*/
21282167
static int update_prstate(struct cpuset *cs, int new_prs)
21292168
{
2130-
int err = 0, old_prs = cs->partition_root_state;
2169+
int err = PERR_NONE, old_prs = cs->partition_root_state;
21312170
bool sched_domain_rebuilt = false;
21322171
struct cpuset *parent = parent_cs(cs);
21332172
struct tmpmasks tmpmask;
@@ -2154,13 +2193,15 @@ static int update_prstate(struct cpuset *cs, int new_prs)
21542193
* cannot be empty.
21552194
*/
21562195
if (cpumask_empty(cs->cpus_allowed)) {
2157-
err = 1;
2196+
err = PERR_CPUSEMPTY;
21582197
goto out;
21592198
}
21602199

21612200
err = update_flag(CS_CPU_EXCLUSIVE, cs, 1);
2162-
if (err)
2201+
if (err) {
2202+
err = PERR_NOTEXCL;
21632203
goto out;
2204+
}
21642205

21652206
err = update_parent_subparts_cpumask(cs, partcmd_enable,
21662207
NULL, &tmpmask);
@@ -2730,6 +2771,7 @@ static s64 cpuset_read_s64(struct cgroup_subsys_state *css, struct cftype *cft)
27302771
static int sched_partition_show(struct seq_file *seq, void *v)
27312772
{
27322773
struct cpuset *cs = css_cs(seq_css(seq));
2774+
const char *err, *type = NULL;
27332775

27342776
switch (cs->partition_root_state) {
27352777
case PRS_ROOT:
@@ -2742,9 +2784,17 @@ static int sched_partition_show(struct seq_file *seq, void *v)
27422784
seq_puts(seq, "member\n");
27432785
break;
27442786
case PRS_INVALID_ROOT:
2745-
seq_puts(seq, "root invalid\n");
2746-
break;
2787+
type = "root";
2788+
fallthrough;
27472789
case PRS_INVALID_ISOLATED:
2790+
if (!type)
2791+
type = "isolated";
2792+
err = perr_strings[READ_ONCE(cs->prs_err)];
2793+
if (err)
2794+
seq_printf(seq, "%s invalid (%s)\n", type, err);
2795+
else
2796+
seq_printf(seq, "%s invalid\n", type);
2797+
break;
27482798
seq_puts(seq, "isolated invalid\n");
27492799
break;
27502800
}
@@ -3335,7 +3385,7 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp)
33353385
*/
33363386
if (is_partition_valid(cs) && (!parent->nr_subparts_cpus ||
33373387
(cpumask_empty(&new_cpus) && partition_is_populated(cs, NULL)))) {
3338-
int old_prs;
3388+
int old_prs, parent_prs;
33393389

33403390
update_parent_subparts_cpumask(cs, partcmd_disable, NULL, tmp);
33413391
if (cs->nr_subparts_cpus) {
@@ -3347,10 +3397,17 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp)
33473397
}
33483398

33493399
old_prs = cs->partition_root_state;
3400+
parent_prs = parent->partition_root_state;
33503401
if (is_partition_valid(cs)) {
33513402
spin_lock_irq(&callback_lock);
33523403
make_partition_invalid(cs);
33533404
spin_unlock_irq(&callback_lock);
3405+
if (is_prs_invalid(parent_prs))
3406+
WRITE_ONCE(cs->prs_err, PERR_INVPARENT);
3407+
else if (!parent_prs)
3408+
WRITE_ONCE(cs->prs_err, PERR_NOTPART);
3409+
else
3410+
WRITE_ONCE(cs->prs_err, PERR_HOTPLUG);
33543411
notify_partition_change(cs, old_prs);
33553412
}
33563413
cpuset_force_rebuild();

0 commit comments

Comments
 (0)