Merge tag 'cgroup-for-6.15-rc1-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
Pull cgroup fixes from Tejun Heo: - A number of cpuset remote partition related fixes and cleanups along with selftest updates. - A change from this merge window made cgroup_rstat_updated_list() called outside cgroup_rstat_lock leading to list corruptions. Fix it by relocating the call inside the lock. * tag 'cgroup-for-6.15-rc1-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup: cgroup/cpuset: Fix race between newly created partition and dying one cgroup: rstat: call cgroup_rstat_updated_list with cgroup_rstat_lock selftest/cgroup: Add a remote partition transition test to test_cpuset_prs.sh selftest/cgroup: Clean up and restructure test_cpuset_prs.sh selftest/cgroup: Update test_cpuset_prs.sh to use | as effective CPUs and state separator cgroup/cpuset: Remove unneeded goto in sched_partition_write() and rename it cgroup/cpuset: Code cleanup and comment update cgroup/cpuset: Don't allow creation of local partition over a remote one cgroup/cpuset: Remove remote_partition_check() & make update_cpumasks_hier() handle remote partition cgroup/cpuset: Fix error handling in remote_partition_disable() cgroup/cpuset: Fix incorrect isolated_cpus update in update_parent_effective_cpumask()
This commit is contained in:
@@ -710,6 +710,7 @@ struct cgroup_subsys {
|
||||
void (*css_released)(struct cgroup_subsys_state *css);
|
||||
void (*css_free)(struct cgroup_subsys_state *css);
|
||||
void (*css_reset)(struct cgroup_subsys_state *css);
|
||||
void (*css_killed)(struct cgroup_subsys_state *css);
|
||||
void (*css_rstat_flush)(struct cgroup_subsys_state *css, int cpu);
|
||||
int (*css_extra_stat_show)(struct seq_file *seq,
|
||||
struct cgroup_subsys_state *css);
|
||||
|
||||
@@ -344,7 +344,7 @@ static inline u64 cgroup_id(const struct cgroup *cgrp)
|
||||
*/
|
||||
static inline bool css_is_dying(struct cgroup_subsys_state *css)
|
||||
{
|
||||
return !(css->flags & CSS_NO_REF) && percpu_ref_is_dying(&css->refcnt);
|
||||
return css->flags & CSS_DYING;
|
||||
}
|
||||
|
||||
static inline void cgroup_get(struct cgroup *cgrp)
|
||||
|
||||
@@ -5923,6 +5923,12 @@ static void kill_css(struct cgroup_subsys_state *css)
|
||||
if (css->flags & CSS_DYING)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Call css_killed(), if defined, before setting the CSS_DYING flag
|
||||
*/
|
||||
if (css->ss->css_killed)
|
||||
css->ss->css_killed(css);
|
||||
|
||||
css->flags |= CSS_DYING;
|
||||
|
||||
/*
|
||||
|
||||
@@ -33,6 +33,7 @@ enum prs_errcode {
|
||||
PERR_CPUSEMPTY,
|
||||
PERR_HKEEPING,
|
||||
PERR_ACCESS,
|
||||
PERR_REMOTE,
|
||||
};
|
||||
|
||||
/* bits in struct cpuset flags field */
|
||||
|
||||
+240
-165
@@ -61,10 +61,17 @@ static const char * const perr_strings[] = {
|
||||
[PERR_CPUSEMPTY] = "cpuset.cpus and cpuset.cpus.exclusive are empty",
|
||||
[PERR_HKEEPING] = "partition config conflicts with housekeeping setup",
|
||||
[PERR_ACCESS] = "Enable partition not permitted",
|
||||
[PERR_REMOTE] = "Have remote partition underneath",
|
||||
};
|
||||
|
||||
/*
|
||||
* Exclusive CPUs distributed out to sub-partitions of top_cpuset
|
||||
* For local partitions, update to subpartitions_cpus & isolated_cpus is done
|
||||
* in update_parent_effective_cpumask(). For remote partitions, it is done in
|
||||
* the remote_partition_*() and remote_cpus_update() helpers.
|
||||
*/
|
||||
/*
|
||||
* Exclusive CPUs distributed out to local or remote sub-partitions of
|
||||
* top_cpuset
|
||||
*/
|
||||
static cpumask_var_t subpartitions_cpus;
|
||||
|
||||
@@ -86,7 +93,6 @@ static struct list_head remote_children;
|
||||
* A flag to force sched domain rebuild at the end of an operation.
|
||||
* It can be set in
|
||||
* - update_partition_sd_lb()
|
||||
* - remote_partition_check()
|
||||
* - update_cpumasks_hier()
|
||||
* - cpuset_update_flag()
|
||||
* - cpuset_hotplug_update_tasks()
|
||||
@@ -1089,9 +1095,14 @@ void cpuset_reset_sched_domains(void)
|
||||
*
|
||||
* Iterate through each task of @cs updating its cpus_allowed to the
|
||||
* effective cpuset's. As this function is called with cpuset_mutex held,
|
||||
* cpuset membership stays stable. For top_cpuset, task_cpu_possible_mask()
|
||||
* is used instead of effective_cpus to make sure all offline CPUs are also
|
||||
* included as hotplug code won't update cpumasks for tasks in top_cpuset.
|
||||
* cpuset membership stays stable.
|
||||
*
|
||||
* For top_cpuset, task_cpu_possible_mask() is used instead of effective_cpus
|
||||
* to make sure all offline CPUs are also included as hotplug code won't
|
||||
* update cpumasks for tasks in top_cpuset.
|
||||
*
|
||||
* As task_cpu_possible_mask() can be task dependent in arm64, we have to
|
||||
* do cpu masking per task instead of doing it once for all.
|
||||
*/
|
||||
void cpuset_update_tasks_cpumask(struct cpuset *cs, struct cpumask *new_cpus)
|
||||
{
|
||||
@@ -1151,7 +1162,7 @@ static void update_sibling_cpumasks(struct cpuset *parent, struct cpuset *cs,
|
||||
*
|
||||
* Return: 0 if successful, an error code otherwise
|
||||
*/
|
||||
static int update_partition_exclusive(struct cpuset *cs, int new_prs)
|
||||
static int update_partition_exclusive_flag(struct cpuset *cs, int new_prs)
|
||||
{
|
||||
bool exclusive = (new_prs > PRS_MEMBER);
|
||||
|
||||
@@ -1234,12 +1245,12 @@ static void reset_partition_data(struct cpuset *cs)
|
||||
}
|
||||
|
||||
/*
|
||||
* partition_xcpus_newstate - Exclusive CPUs state change
|
||||
* isolated_cpus_update - Update the isolated_cpus mask
|
||||
* @old_prs: old partition_root_state
|
||||
* @new_prs: new partition_root_state
|
||||
* @xcpus: exclusive CPUs with state change
|
||||
*/
|
||||
static void partition_xcpus_newstate(int old_prs, int new_prs, struct cpumask *xcpus)
|
||||
static void isolated_cpus_update(int old_prs, int new_prs, struct cpumask *xcpus)
|
||||
{
|
||||
WARN_ON_ONCE(old_prs == new_prs);
|
||||
if (new_prs == PRS_ISOLATED)
|
||||
@@ -1273,8 +1284,8 @@ static bool partition_xcpus_add(int new_prs, struct cpuset *parent,
|
||||
|
||||
isolcpus_updated = (new_prs != parent->partition_root_state);
|
||||
if (isolcpus_updated)
|
||||
partition_xcpus_newstate(parent->partition_root_state, new_prs,
|
||||
xcpus);
|
||||
isolated_cpus_update(parent->partition_root_state, new_prs,
|
||||
xcpus);
|
||||
|
||||
cpumask_andnot(parent->effective_cpus, parent->effective_cpus, xcpus);
|
||||
return isolcpus_updated;
|
||||
@@ -1304,8 +1315,8 @@ static bool partition_xcpus_del(int old_prs, struct cpuset *parent,
|
||||
|
||||
isolcpus_updated = (old_prs != parent->partition_root_state);
|
||||
if (isolcpus_updated)
|
||||
partition_xcpus_newstate(old_prs, parent->partition_root_state,
|
||||
xcpus);
|
||||
isolated_cpus_update(old_prs, parent->partition_root_state,
|
||||
xcpus);
|
||||
|
||||
cpumask_and(xcpus, xcpus, cpu_active_mask);
|
||||
cpumask_or(parent->effective_cpus, parent->effective_cpus, xcpus);
|
||||
@@ -1340,20 +1351,57 @@ EXPORT_SYMBOL_GPL(cpuset_cpu_is_isolated);
|
||||
* compute_effective_exclusive_cpumask - compute effective exclusive CPUs
|
||||
* @cs: cpuset
|
||||
* @xcpus: effective exclusive CPUs value to be set
|
||||
* Return: true if xcpus is not empty, false otherwise.
|
||||
* @real_cs: the real cpuset (can be NULL)
|
||||
* Return: 0 if there is no sibling conflict, > 0 otherwise
|
||||
*
|
||||
* Starting with exclusive_cpus (cpus_allowed if exclusive_cpus is not set),
|
||||
* it must be a subset of parent's effective_xcpus.
|
||||
* If exclusive_cpus isn't explicitly set or a real_cs is provided, we have to
|
||||
* scan the sibling cpusets and exclude their exclusive_cpus or effective_xcpus
|
||||
* as well. The provision of real_cs means that a cpumask is being changed and
|
||||
* the given cs is a trial one.
|
||||
*/
|
||||
static bool compute_effective_exclusive_cpumask(struct cpuset *cs,
|
||||
struct cpumask *xcpus)
|
||||
static int compute_effective_exclusive_cpumask(struct cpuset *cs,
|
||||
struct cpumask *xcpus,
|
||||
struct cpuset *real_cs)
|
||||
{
|
||||
struct cgroup_subsys_state *css;
|
||||
struct cpuset *parent = parent_cs(cs);
|
||||
struct cpuset *sibling;
|
||||
int retval = 0;
|
||||
|
||||
if (!xcpus)
|
||||
xcpus = cs->effective_xcpus;
|
||||
|
||||
return cpumask_and(xcpus, user_xcpus(cs), parent->effective_xcpus);
|
||||
cpumask_and(xcpus, user_xcpus(cs), parent->effective_xcpus);
|
||||
|
||||
if (!real_cs) {
|
||||
if (!cpumask_empty(cs->exclusive_cpus))
|
||||
return 0;
|
||||
} else {
|
||||
cs = real_cs;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exclude exclusive CPUs from siblings
|
||||
*/
|
||||
rcu_read_lock();
|
||||
cpuset_for_each_child(sibling, css, parent) {
|
||||
if (sibling == cs)
|
||||
continue;
|
||||
|
||||
if (!cpumask_empty(sibling->exclusive_cpus) &&
|
||||
cpumask_intersects(xcpus, sibling->exclusive_cpus)) {
|
||||
cpumask_andnot(xcpus, xcpus, sibling->exclusive_cpus);
|
||||
retval++;
|
||||
continue;
|
||||
}
|
||||
if (!cpumask_empty(sibling->effective_xcpus) &&
|
||||
cpumask_intersects(xcpus, sibling->effective_xcpus)) {
|
||||
cpumask_andnot(xcpus, xcpus, sibling->effective_xcpus);
|
||||
retval++;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return retval;
|
||||
}
|
||||
|
||||
static inline bool is_remote_partition(struct cpuset *cs)
|
||||
@@ -1395,7 +1443,7 @@ static int remote_partition_enable(struct cpuset *cs, int new_prs,
|
||||
* remote partition root underneath it, its exclusive_cpus must
|
||||
* have overlapped with subpartitions_cpus.
|
||||
*/
|
||||
compute_effective_exclusive_cpumask(cs, tmp->new_cpus);
|
||||
compute_effective_exclusive_cpumask(cs, tmp->new_cpus, NULL);
|
||||
if (cpumask_empty(tmp->new_cpus) ||
|
||||
cpumask_intersects(tmp->new_cpus, subpartitions_cpus) ||
|
||||
cpumask_subset(top_cpuset.effective_cpus, tmp->new_cpus))
|
||||
@@ -1404,8 +1452,11 @@ static int remote_partition_enable(struct cpuset *cs, int new_prs,
|
||||
spin_lock_irq(&callback_lock);
|
||||
isolcpus_updated = partition_xcpus_add(new_prs, NULL, tmp->new_cpus);
|
||||
list_add(&cs->remote_sibling, &remote_children);
|
||||
cpumask_copy(cs->effective_xcpus, tmp->new_cpus);
|
||||
spin_unlock_irq(&callback_lock);
|
||||
update_unbound_workqueue_cpumask(isolcpus_updated);
|
||||
cpuset_force_rebuild();
|
||||
cs->prs_err = 0;
|
||||
|
||||
/*
|
||||
* Propagate changes in top_cpuset's effective_cpus down the hierarchy.
|
||||
@@ -1428,20 +1479,24 @@ static void remote_partition_disable(struct cpuset *cs, struct tmpmasks *tmp)
|
||||
{
|
||||
bool isolcpus_updated;
|
||||
|
||||
compute_effective_exclusive_cpumask(cs, tmp->new_cpus);
|
||||
WARN_ON_ONCE(!is_remote_partition(cs));
|
||||
WARN_ON_ONCE(!cpumask_subset(tmp->new_cpus, subpartitions_cpus));
|
||||
WARN_ON_ONCE(!cpumask_subset(cs->effective_xcpus, subpartitions_cpus));
|
||||
|
||||
spin_lock_irq(&callback_lock);
|
||||
list_del_init(&cs->remote_sibling);
|
||||
isolcpus_updated = partition_xcpus_del(cs->partition_root_state,
|
||||
NULL, tmp->new_cpus);
|
||||
cs->partition_root_state = -cs->partition_root_state;
|
||||
if (!cs->prs_err)
|
||||
cs->prs_err = PERR_INVCPUS;
|
||||
NULL, cs->effective_xcpus);
|
||||
if (cs->prs_err)
|
||||
cs->partition_root_state = -cs->partition_root_state;
|
||||
else
|
||||
cs->partition_root_state = PRS_MEMBER;
|
||||
|
||||
/* effective_xcpus may need to be changed */
|
||||
compute_effective_exclusive_cpumask(cs, NULL, NULL);
|
||||
reset_partition_data(cs);
|
||||
spin_unlock_irq(&callback_lock);
|
||||
update_unbound_workqueue_cpumask(isolcpus_updated);
|
||||
cpuset_force_rebuild();
|
||||
|
||||
/*
|
||||
* Propagate changes in top_cpuset's effective_cpus down the hierarchy.
|
||||
@@ -1453,14 +1508,15 @@ static void remote_partition_disable(struct cpuset *cs, struct tmpmasks *tmp)
|
||||
/*
|
||||
* remote_cpus_update - cpus_exclusive change of remote partition
|
||||
* @cs: the cpuset to be updated
|
||||
* @newmask: the new effective_xcpus mask
|
||||
* @xcpus: the new exclusive_cpus mask, if non-NULL
|
||||
* @excpus: the new effective_xcpus mask
|
||||
* @tmp: temporary masks
|
||||
*
|
||||
* top_cpuset and subpartitions_cpus will be updated or partition can be
|
||||
* invalidated.
|
||||
*/
|
||||
static void remote_cpus_update(struct cpuset *cs, struct cpumask *newmask,
|
||||
struct tmpmasks *tmp)
|
||||
static void remote_cpus_update(struct cpuset *cs, struct cpumask *xcpus,
|
||||
struct cpumask *excpus, struct tmpmasks *tmp)
|
||||
{
|
||||
bool adding, deleting;
|
||||
int prs = cs->partition_root_state;
|
||||
@@ -1471,29 +1527,45 @@ static void remote_cpus_update(struct cpuset *cs, struct cpumask *newmask,
|
||||
|
||||
WARN_ON_ONCE(!cpumask_subset(cs->effective_xcpus, subpartitions_cpus));
|
||||
|
||||
if (cpumask_empty(newmask))
|
||||
if (cpumask_empty(excpus)) {
|
||||
cs->prs_err = PERR_CPUSEMPTY;
|
||||
goto invalidate;
|
||||
}
|
||||
|
||||
adding = cpumask_andnot(tmp->addmask, newmask, cs->effective_xcpus);
|
||||
deleting = cpumask_andnot(tmp->delmask, cs->effective_xcpus, newmask);
|
||||
adding = cpumask_andnot(tmp->addmask, excpus, cs->effective_xcpus);
|
||||
deleting = cpumask_andnot(tmp->delmask, cs->effective_xcpus, excpus);
|
||||
|
||||
/*
|
||||
* Additions of remote CPUs is only allowed if those CPUs are
|
||||
* not allocated to other partitions and there are effective_cpus
|
||||
* left in the top cpuset.
|
||||
*/
|
||||
if (adding && (!capable(CAP_SYS_ADMIN) ||
|
||||
cpumask_intersects(tmp->addmask, subpartitions_cpus) ||
|
||||
cpumask_subset(top_cpuset.effective_cpus, tmp->addmask)))
|
||||
goto invalidate;
|
||||
if (adding) {
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
cs->prs_err = PERR_ACCESS;
|
||||
else if (cpumask_intersects(tmp->addmask, subpartitions_cpus) ||
|
||||
cpumask_subset(top_cpuset.effective_cpus, tmp->addmask))
|
||||
cs->prs_err = PERR_NOCPUS;
|
||||
if (cs->prs_err)
|
||||
goto invalidate;
|
||||
}
|
||||
|
||||
spin_lock_irq(&callback_lock);
|
||||
if (adding)
|
||||
isolcpus_updated += partition_xcpus_add(prs, NULL, tmp->addmask);
|
||||
if (deleting)
|
||||
isolcpus_updated += partition_xcpus_del(prs, NULL, tmp->delmask);
|
||||
/*
|
||||
* Need to update effective_xcpus and exclusive_cpus now as
|
||||
* update_sibling_cpumasks() below may iterate back to the same cs.
|
||||
*/
|
||||
cpumask_copy(cs->effective_xcpus, excpus);
|
||||
if (xcpus)
|
||||
cpumask_copy(cs->exclusive_cpus, xcpus);
|
||||
spin_unlock_irq(&callback_lock);
|
||||
update_unbound_workqueue_cpumask(isolcpus_updated);
|
||||
if (adding || deleting)
|
||||
cpuset_force_rebuild();
|
||||
|
||||
/*
|
||||
* Propagate changes in top_cpuset's effective_cpus down the hierarchy.
|
||||
@@ -1506,47 +1578,6 @@ invalidate:
|
||||
remote_partition_disable(cs, tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* remote_partition_check - check if a child remote partition needs update
|
||||
* @cs: the cpuset to be updated
|
||||
* @newmask: the new effective_xcpus mask
|
||||
* @delmask: temporary mask for deletion (not in tmp)
|
||||
* @tmp: temporary masks
|
||||
*
|
||||
* This should be called before the given cs has updated its cpus_allowed
|
||||
* and/or effective_xcpus.
|
||||
*/
|
||||
static void remote_partition_check(struct cpuset *cs, struct cpumask *newmask,
|
||||
struct cpumask *delmask, struct tmpmasks *tmp)
|
||||
{
|
||||
struct cpuset *child, *next;
|
||||
int disable_cnt = 0;
|
||||
|
||||
/*
|
||||
* Compute the effective exclusive CPUs that will be deleted.
|
||||
*/
|
||||
if (!cpumask_andnot(delmask, cs->effective_xcpus, newmask) ||
|
||||
!cpumask_intersects(delmask, subpartitions_cpus))
|
||||
return; /* No deletion of exclusive CPUs in partitions */
|
||||
|
||||
/*
|
||||
* Searching the remote children list to look for those that will
|
||||
* be impacted by the deletion of exclusive CPUs.
|
||||
*
|
||||
* Since a cpuset must be removed from the remote children list
|
||||
* before it can go offline and holding cpuset_mutex will prevent
|
||||
* any change in cpuset status. RCU read lock isn't needed.
|
||||
*/
|
||||
lockdep_assert_held(&cpuset_mutex);
|
||||
list_for_each_entry_safe(child, next, &remote_children, remote_sibling)
|
||||
if (cpumask_intersects(child->effective_cpus, delmask)) {
|
||||
remote_partition_disable(child, tmp);
|
||||
disable_cnt++;
|
||||
}
|
||||
if (disable_cnt)
|
||||
cpuset_force_rebuild();
|
||||
}
|
||||
|
||||
/*
|
||||
* prstate_housekeeping_conflict - check for partition & housekeeping conflicts
|
||||
* @prstate: partition root state to be checked
|
||||
@@ -1601,7 +1632,7 @@ static bool prstate_housekeeping_conflict(int prstate, struct cpumask *new_cpus)
|
||||
* The partcmd_update command is used by update_cpumasks_hier() with newmask
|
||||
* NULL and update_cpumask() with newmask set. The partcmd_invalidate is used
|
||||
* by update_cpumask() with NULL newmask. In both cases, the callers won't
|
||||
* check for error and so partition_root_state and prs_error will be updated
|
||||
* check for error and so partition_root_state and prs_err will be updated
|
||||
* directly.
|
||||
*/
|
||||
static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
|
||||
@@ -1614,11 +1645,12 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
|
||||
int old_prs, new_prs;
|
||||
int part_error = PERR_NONE; /* Partition error? */
|
||||
int subparts_delta = 0;
|
||||
struct cpumask *xcpus; /* cs effective_xcpus */
|
||||
int isolcpus_updated = 0;
|
||||
struct cpumask *xcpus = user_xcpus(cs);
|
||||
bool nocpu;
|
||||
|
||||
lockdep_assert_held(&cpuset_mutex);
|
||||
WARN_ON_ONCE(is_remote_partition(cs));
|
||||
|
||||
/*
|
||||
* new_prs will only be changed for the partcmd_update and
|
||||
@@ -1626,7 +1658,6 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
|
||||
*/
|
||||
adding = deleting = false;
|
||||
old_prs = new_prs = cs->partition_root_state;
|
||||
xcpus = user_xcpus(cs);
|
||||
|
||||
if (cmd == partcmd_invalidate) {
|
||||
if (is_prs_invalid(old_prs))
|
||||
@@ -1661,12 +1692,19 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
|
||||
|
||||
if ((cmd == partcmd_enable) || (cmd == partcmd_enablei)) {
|
||||
/*
|
||||
* Enabling partition root is not allowed if its
|
||||
* effective_xcpus is empty or doesn't overlap with
|
||||
* parent's effective_xcpus.
|
||||
* Need to call compute_effective_exclusive_cpumask() in case
|
||||
* exclusive_cpus not set. Sibling conflict should only happen
|
||||
* if exclusive_cpus isn't set.
|
||||
*/
|
||||
if (cpumask_empty(xcpus) ||
|
||||
!cpumask_intersects(xcpus, parent->effective_xcpus))
|
||||
xcpus = tmp->new_cpus;
|
||||
if (compute_effective_exclusive_cpumask(cs, xcpus, NULL))
|
||||
WARN_ON_ONCE(!cpumask_empty(cs->exclusive_cpus));
|
||||
|
||||
/*
|
||||
* Enabling partition root is not allowed if its
|
||||
* effective_xcpus is empty.
|
||||
*/
|
||||
if (cpumask_empty(xcpus))
|
||||
return PERR_INVCPUS;
|
||||
|
||||
if (prstate_housekeeping_conflict(new_prs, xcpus))
|
||||
@@ -1679,19 +1717,22 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
|
||||
if (nocpu)
|
||||
return PERR_NOCPUS;
|
||||
|
||||
cpumask_copy(tmp->delmask, xcpus);
|
||||
deleting = true;
|
||||
subparts_delta++;
|
||||
deleting = cpumask_and(tmp->delmask, xcpus, parent->effective_xcpus);
|
||||
if (deleting)
|
||||
subparts_delta++;
|
||||
new_prs = (cmd == partcmd_enable) ? PRS_ROOT : PRS_ISOLATED;
|
||||
} else if (cmd == partcmd_disable) {
|
||||
/*
|
||||
* May need to add cpus to parent's effective_cpus for
|
||||
* valid partition root.
|
||||
* May need to add cpus back to parent's effective_cpus
|
||||
* (and maybe removed from subpartitions_cpus/isolated_cpus)
|
||||
* for valid partition root. xcpus may contain CPUs that
|
||||
* shouldn't be removed from the two global cpumasks.
|
||||
*/
|
||||
adding = !is_prs_invalid(old_prs) &&
|
||||
cpumask_and(tmp->addmask, xcpus, parent->effective_xcpus);
|
||||
if (adding)
|
||||
if (is_partition_valid(cs)) {
|
||||
cpumask_copy(tmp->addmask, cs->effective_xcpus);
|
||||
adding = true;
|
||||
subparts_delta--;
|
||||
}
|
||||
new_prs = PRS_MEMBER;
|
||||
} else if (newmask) {
|
||||
/*
|
||||
@@ -1701,6 +1742,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
|
||||
part_error = PERR_CPUSEMPTY;
|
||||
goto write_error;
|
||||
}
|
||||
|
||||
/* Check newmask again, whether cpus are available for parent/cs */
|
||||
nocpu |= tasks_nocpu_error(parent, cs, newmask);
|
||||
|
||||
@@ -1829,7 +1871,7 @@ write_error:
|
||||
* CPU lists in cs haven't been updated yet. So defer it to later.
|
||||
*/
|
||||
if ((old_prs != new_prs) && (cmd != partcmd_update)) {
|
||||
int err = update_partition_exclusive(cs, new_prs);
|
||||
int err = update_partition_exclusive_flag(cs, new_prs);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
@@ -1867,7 +1909,7 @@ write_error:
|
||||
update_unbound_workqueue_cpumask(isolcpus_updated);
|
||||
|
||||
if ((old_prs != new_prs) && (cmd == partcmd_update))
|
||||
update_partition_exclusive(cs, new_prs);
|
||||
update_partition_exclusive_flag(cs, new_prs);
|
||||
|
||||
if (adding || deleting) {
|
||||
cpuset_update_tasks_cpumask(parent, tmp->addmask);
|
||||
@@ -1917,7 +1959,7 @@ static void compute_partition_effective_cpumask(struct cpuset *cs,
|
||||
* 2) All the effective_cpus will be used up and cp
|
||||
* has tasks
|
||||
*/
|
||||
compute_effective_exclusive_cpumask(cs, new_ecpus);
|
||||
compute_effective_exclusive_cpumask(cs, new_ecpus, NULL);
|
||||
cpumask_and(new_ecpus, new_ecpus, cpu_active_mask);
|
||||
|
||||
rcu_read_lock();
|
||||
@@ -1925,6 +1967,11 @@ static void compute_partition_effective_cpumask(struct cpuset *cs,
|
||||
if (!is_partition_valid(child))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* There shouldn't be a remote partition underneath another
|
||||
* partition root.
|
||||
*/
|
||||
WARN_ON_ONCE(is_remote_partition(child));
|
||||
child->prs_err = 0;
|
||||
if (!cpumask_subset(child->effective_xcpus,
|
||||
cs->effective_xcpus))
|
||||
@@ -1980,32 +2027,39 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp,
|
||||
bool remote = is_remote_partition(cp);
|
||||
bool update_parent = false;
|
||||
|
||||
old_prs = new_prs = cp->partition_root_state;
|
||||
|
||||
/*
|
||||
* Skip descendent remote partition that acquires CPUs
|
||||
* directly from top cpuset unless it is cs.
|
||||
* For child remote partition root (!= cs), we need to call
|
||||
* remote_cpus_update() if effective_xcpus will be changed.
|
||||
* Otherwise, we can skip the whole subtree.
|
||||
*
|
||||
* remote_cpus_update() will reuse tmp->new_cpus only after
|
||||
* its value is being processed.
|
||||
*/
|
||||
if (remote && (cp != cs)) {
|
||||
pos_css = css_rightmost_descendant(pos_css);
|
||||
continue;
|
||||
compute_effective_exclusive_cpumask(cp, tmp->new_cpus, NULL);
|
||||
if (cpumask_equal(cp->effective_xcpus, tmp->new_cpus)) {
|
||||
pos_css = css_rightmost_descendant(pos_css);
|
||||
continue;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
remote_cpus_update(cp, NULL, tmp->new_cpus, tmp);
|
||||
rcu_read_lock();
|
||||
|
||||
/* Remote partition may be invalidated */
|
||||
new_prs = cp->partition_root_state;
|
||||
remote = (new_prs == old_prs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update effective_xcpus if exclusive_cpus set.
|
||||
* The case when exclusive_cpus isn't set is handled later.
|
||||
*/
|
||||
if (!cpumask_empty(cp->exclusive_cpus) && (cp != cs)) {
|
||||
spin_lock_irq(&callback_lock);
|
||||
compute_effective_exclusive_cpumask(cp, NULL);
|
||||
spin_unlock_irq(&callback_lock);
|
||||
}
|
||||
|
||||
old_prs = new_prs = cp->partition_root_state;
|
||||
if (remote || (is_partition_valid(parent) &&
|
||||
is_partition_valid(cp)))
|
||||
if (remote || (is_partition_valid(parent) && is_partition_valid(cp)))
|
||||
compute_partition_effective_cpumask(cp, tmp->new_cpus);
|
||||
else
|
||||
compute_effective_cpumask(tmp->new_cpus, cp, parent);
|
||||
|
||||
if (remote)
|
||||
goto get_css; /* Ready to update cpuset data */
|
||||
|
||||
/*
|
||||
* A partition with no effective_cpus is allowed as long as
|
||||
* there is no task associated with it. Call
|
||||
@@ -2025,9 +2079,6 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp,
|
||||
if (is_in_v2_mode() && !remote && cpumask_empty(tmp->new_cpus))
|
||||
cpumask_copy(tmp->new_cpus, parent->effective_cpus);
|
||||
|
||||
if (remote)
|
||||
goto get_css;
|
||||
|
||||
/*
|
||||
* Skip the whole subtree if
|
||||
* 1) the cpumask remains the same,
|
||||
@@ -2088,6 +2139,9 @@ get_css:
|
||||
spin_lock_irq(&callback_lock);
|
||||
cpumask_copy(cp->effective_cpus, tmp->new_cpus);
|
||||
cp->partition_root_state = new_prs;
|
||||
if (!cpumask_empty(cp->exclusive_cpus) && (cp != cs))
|
||||
compute_effective_exclusive_cpumask(cp, NULL, NULL);
|
||||
|
||||
/*
|
||||
* Make sure effective_xcpus is properly set for a valid
|
||||
* partition root.
|
||||
@@ -2174,7 +2228,14 @@ static void update_sibling_cpumasks(struct cpuset *parent, struct cpuset *cs,
|
||||
parent);
|
||||
if (cpumask_equal(tmp->new_cpus, sibling->effective_cpus))
|
||||
continue;
|
||||
} else if (is_remote_partition(sibling)) {
|
||||
/*
|
||||
* Change in a sibling cpuset won't affect a remote
|
||||
* partition root.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!css_tryget_online(&sibling->css))
|
||||
continue;
|
||||
|
||||
@@ -2231,8 +2292,9 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
|
||||
* trialcs->effective_xcpus is used as a temporary cpumask
|
||||
* for checking validity of the partition root.
|
||||
*/
|
||||
trialcs->partition_root_state = PRS_MEMBER;
|
||||
if (!cpumask_empty(trialcs->exclusive_cpus) || is_partition_valid(cs))
|
||||
compute_effective_exclusive_cpumask(trialcs, NULL);
|
||||
compute_effective_exclusive_cpumask(trialcs, NULL, cs);
|
||||
}
|
||||
|
||||
/* Nothing to do if the cpus didn't change */
|
||||
@@ -2305,19 +2367,13 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
|
||||
* Call remote_cpus_update() to handle valid remote partition
|
||||
*/
|
||||
if (is_remote_partition(cs))
|
||||
remote_cpus_update(cs, xcpus, &tmp);
|
||||
remote_cpus_update(cs, NULL, xcpus, &tmp);
|
||||
else if (invalidate)
|
||||
update_parent_effective_cpumask(cs, partcmd_invalidate,
|
||||
NULL, &tmp);
|
||||
else
|
||||
update_parent_effective_cpumask(cs, partcmd_update,
|
||||
xcpus, &tmp);
|
||||
} else if (!cpumask_empty(cs->exclusive_cpus)) {
|
||||
/*
|
||||
* Use trialcs->effective_cpus as a temp cpumask
|
||||
*/
|
||||
remote_partition_check(cs, trialcs->effective_xcpus,
|
||||
trialcs->effective_cpus, &tmp);
|
||||
}
|
||||
|
||||
spin_lock_irq(&callback_lock);
|
||||
@@ -2369,8 +2425,15 @@ static int update_exclusive_cpumask(struct cpuset *cs, struct cpuset *trialcs,
|
||||
if (cpumask_equal(cs->exclusive_cpus, trialcs->exclusive_cpus))
|
||||
return 0;
|
||||
|
||||
if (*buf)
|
||||
compute_effective_exclusive_cpumask(trialcs, NULL);
|
||||
if (*buf) {
|
||||
trialcs->partition_root_state = PRS_MEMBER;
|
||||
/*
|
||||
* Reject the change if there is exclusive CPUs conflict with
|
||||
* the siblings.
|
||||
*/
|
||||
if (compute_effective_exclusive_cpumask(trialcs, NULL, cs))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check all the descendants in update_cpumasks_hier() if
|
||||
@@ -2401,8 +2464,8 @@ static int update_exclusive_cpumask(struct cpuset *cs, struct cpuset *trialcs,
|
||||
if (invalidate)
|
||||
remote_partition_disable(cs, &tmp);
|
||||
else
|
||||
remote_cpus_update(cs, trialcs->effective_xcpus,
|
||||
&tmp);
|
||||
remote_cpus_update(cs, trialcs->exclusive_cpus,
|
||||
trialcs->effective_xcpus, &tmp);
|
||||
} else if (invalidate) {
|
||||
update_parent_effective_cpumask(cs, partcmd_invalidate,
|
||||
NULL, &tmp);
|
||||
@@ -2410,12 +2473,6 @@ static int update_exclusive_cpumask(struct cpuset *cs, struct cpuset *trialcs,
|
||||
update_parent_effective_cpumask(cs, partcmd_update,
|
||||
trialcs->effective_xcpus, &tmp);
|
||||
}
|
||||
} else if (!cpumask_empty(trialcs->exclusive_cpus)) {
|
||||
/*
|
||||
* Use trialcs->effective_cpus as a temp cpumask
|
||||
*/
|
||||
remote_partition_check(cs, trialcs->effective_xcpus,
|
||||
trialcs->effective_cpus, &tmp);
|
||||
}
|
||||
spin_lock_irq(&callback_lock);
|
||||
cpumask_copy(cs->exclusive_cpus, trialcs->exclusive_cpus);
|
||||
@@ -2782,7 +2839,7 @@ static int update_prstate(struct cpuset *cs, int new_prs)
|
||||
int err = PERR_NONE, old_prs = cs->partition_root_state;
|
||||
struct cpuset *parent = parent_cs(cs);
|
||||
struct tmpmasks tmpmask;
|
||||
bool new_xcpus_state = false;
|
||||
bool isolcpus_updated = false;
|
||||
|
||||
if (old_prs == new_prs)
|
||||
return 0;
|
||||
@@ -2796,18 +2853,7 @@ static int update_prstate(struct cpuset *cs, int new_prs)
|
||||
if (alloc_cpumasks(NULL, &tmpmask))
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Setup effective_xcpus if not properly set yet, it will be cleared
|
||||
* later if partition becomes invalid.
|
||||
*/
|
||||
if ((new_prs > 0) && cpumask_empty(cs->exclusive_cpus)) {
|
||||
spin_lock_irq(&callback_lock);
|
||||
cpumask_and(cs->effective_xcpus,
|
||||
cs->cpus_allowed, parent->effective_xcpus);
|
||||
spin_unlock_irq(&callback_lock);
|
||||
}
|
||||
|
||||
err = update_partition_exclusive(cs, new_prs);
|
||||
err = update_partition_exclusive_flag(cs, new_prs);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@@ -2820,6 +2866,19 @@ static int update_prstate(struct cpuset *cs, int new_prs)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't support the creation of a new local partition with
|
||||
* a remote partition underneath it. This unsupported
|
||||
* setting can happen only if parent is the top_cpuset because
|
||||
* a remote partition cannot be created underneath an existing
|
||||
* local or remote partition.
|
||||
*/
|
||||
if ((parent == &top_cpuset) &&
|
||||
cpumask_intersects(cs->exclusive_cpus, subpartitions_cpus)) {
|
||||
err = PERR_REMOTE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* If parent is valid partition, enable local partiion.
|
||||
* Otherwise, enable a remote partition.
|
||||
@@ -2835,8 +2894,9 @@ static int update_prstate(struct cpuset *cs, int new_prs)
|
||||
} else if (old_prs && new_prs) {
|
||||
/*
|
||||
* A change in load balance state only, no change in cpumasks.
|
||||
* Need to update isolated_cpus.
|
||||
*/
|
||||
new_xcpus_state = true;
|
||||
isolcpus_updated = true;
|
||||
} else {
|
||||
/*
|
||||
* Switching back to member is always allowed even if it
|
||||
@@ -2860,7 +2920,7 @@ out:
|
||||
*/
|
||||
if (err) {
|
||||
new_prs = -new_prs;
|
||||
update_partition_exclusive(cs, new_prs);
|
||||
update_partition_exclusive_flag(cs, new_prs);
|
||||
}
|
||||
|
||||
spin_lock_irq(&callback_lock);
|
||||
@@ -2868,14 +2928,18 @@ out:
|
||||
WRITE_ONCE(cs->prs_err, err);
|
||||
if (!is_partition_valid(cs))
|
||||
reset_partition_data(cs);
|
||||
else if (new_xcpus_state)
|
||||
partition_xcpus_newstate(old_prs, new_prs, cs->effective_xcpus);
|
||||
else if (isolcpus_updated)
|
||||
isolated_cpus_update(old_prs, new_prs, cs->effective_xcpus);
|
||||
spin_unlock_irq(&callback_lock);
|
||||
update_unbound_workqueue_cpumask(new_xcpus_state);
|
||||
update_unbound_workqueue_cpumask(isolcpus_updated);
|
||||
|
||||
/* Force update if switching back to member */
|
||||
/* Force update if switching back to member & update effective_xcpus */
|
||||
update_cpumasks_hier(cs, &tmpmask, !new_prs);
|
||||
|
||||
/* A newly created partition must have effective_xcpus set */
|
||||
WARN_ON_ONCE(!old_prs && (new_prs > 0)
|
||||
&& cpumask_empty(cs->effective_xcpus));
|
||||
|
||||
/* Update sched domains and load balance flag */
|
||||
update_partition_sd_lb(cs, old_prs);
|
||||
|
||||
@@ -3208,7 +3272,7 @@ int cpuset_common_seq_show(struct seq_file *sf, void *v)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sched_partition_show(struct seq_file *seq, void *v)
|
||||
static int cpuset_partition_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
struct cpuset *cs = css_cs(seq_css(seq));
|
||||
const char *err, *type = NULL;
|
||||
@@ -3239,7 +3303,7 @@ static int sched_partition_show(struct seq_file *seq, void *v)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t sched_partition_write(struct kernfs_open_file *of, char *buf,
|
||||
static ssize_t cpuset_partition_write(struct kernfs_open_file *of, char *buf,
|
||||
size_t nbytes, loff_t off)
|
||||
{
|
||||
struct cpuset *cs = css_cs(of_css(of));
|
||||
@@ -3260,11 +3324,8 @@ static ssize_t sched_partition_write(struct kernfs_open_file *of, char *buf,
|
||||
css_get(&cs->css);
|
||||
cpus_read_lock();
|
||||
mutex_lock(&cpuset_mutex);
|
||||
if (!is_cpuset_online(cs))
|
||||
goto out_unlock;
|
||||
|
||||
retval = update_prstate(cs, val);
|
||||
out_unlock:
|
||||
if (is_cpuset_online(cs))
|
||||
retval = update_prstate(cs, val);
|
||||
mutex_unlock(&cpuset_mutex);
|
||||
cpus_read_unlock();
|
||||
css_put(&cs->css);
|
||||
@@ -3308,8 +3369,8 @@ static struct cftype dfl_files[] = {
|
||||
|
||||
{
|
||||
.name = "cpus.partition",
|
||||
.seq_show = sched_partition_show,
|
||||
.write = sched_partition_write,
|
||||
.seq_show = cpuset_partition_show,
|
||||
.write = cpuset_partition_write,
|
||||
.private = FILE_PARTITION_ROOT,
|
||||
.flags = CFTYPE_NOT_ON_ROOT,
|
||||
.file_offset = offsetof(struct cpuset, partition_file),
|
||||
@@ -3475,9 +3536,6 @@ static void cpuset_css_offline(struct cgroup_subsys_state *css)
|
||||
cpus_read_lock();
|
||||
mutex_lock(&cpuset_mutex);
|
||||
|
||||
if (is_partition_valid(cs))
|
||||
update_prstate(cs, 0);
|
||||
|
||||
if (!cpuset_v2() && is_sched_load_balance(cs))
|
||||
cpuset_update_flag(CS_SCHED_LOAD_BALANCE, cs, 0);
|
||||
|
||||
@@ -3488,6 +3546,22 @@ static void cpuset_css_offline(struct cgroup_subsys_state *css)
|
||||
cpus_read_unlock();
|
||||
}
|
||||
|
||||
static void cpuset_css_killed(struct cgroup_subsys_state *css)
|
||||
{
|
||||
struct cpuset *cs = css_cs(css);
|
||||
|
||||
cpus_read_lock();
|
||||
mutex_lock(&cpuset_mutex);
|
||||
|
||||
/* Reset valid partition back to member */
|
||||
if (is_partition_valid(cs))
|
||||
update_prstate(cs, PRS_MEMBER);
|
||||
|
||||
mutex_unlock(&cpuset_mutex);
|
||||
cpus_read_unlock();
|
||||
|
||||
}
|
||||
|
||||
static void cpuset_css_free(struct cgroup_subsys_state *css)
|
||||
{
|
||||
struct cpuset *cs = css_cs(css);
|
||||
@@ -3609,6 +3683,7 @@ struct cgroup_subsys cpuset_cgrp_subsys = {
|
||||
.css_alloc = cpuset_css_alloc,
|
||||
.css_online = cpuset_css_online,
|
||||
.css_offline = cpuset_css_offline,
|
||||
.css_killed = cpuset_css_killed,
|
||||
.css_free = cpuset_css_free,
|
||||
.can_attach = cpuset_can_attach,
|
||||
.cancel_attach = cpuset_cancel_attach,
|
||||
@@ -3739,10 +3814,10 @@ retry:
|
||||
|
||||
if (remote && cpumask_empty(&new_cpus) &&
|
||||
partition_is_populated(cs, NULL)) {
|
||||
cs->prs_err = PERR_HOTPLUG;
|
||||
remote_partition_disable(cs, tmp);
|
||||
compute_effective_cpumask(&new_cpus, cs, parent);
|
||||
remote = false;
|
||||
cpuset_force_rebuild();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -318,10 +318,11 @@ __bpf_kfunc void cgroup_rstat_flush(struct cgroup *cgrp)
|
||||
|
||||
might_sleep();
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct cgroup *pos = cgroup_rstat_updated_list(cgrp, cpu);
|
||||
struct cgroup *pos;
|
||||
|
||||
/* Reacquire for each CPU to avoid disabling IRQs too long */
|
||||
__cgroup_rstat_lock(cgrp, cpu);
|
||||
pos = cgroup_rstat_updated_list(cgrp, cpu);
|
||||
for (; pos; pos = pos->rstat_flush_next) {
|
||||
struct cgroup_subsys_state *css;
|
||||
|
||||
|
||||
@@ -88,22 +88,32 @@ echo "" > test/cpuset.cpus
|
||||
# If isolated CPUs have been reserved at boot time (as shown in
|
||||
# cpuset.cpus.isolated), these isolated CPUs should be outside of CPUs 0-8
|
||||
# that will be used by this script for testing purpose. If not, some of
|
||||
# the tests may fail incorrectly. These pre-isolated CPUs should stay in
|
||||
# an isolated state throughout the testing process for now.
|
||||
# the tests may fail incorrectly. Wait a bit and retry again just in case
|
||||
# these isolated CPUs are leftover from previous run and have just been
|
||||
# cleaned up earlier in this script.
|
||||
#
|
||||
# These pre-isolated CPUs should stay in an isolated state throughout the
|
||||
# testing process for now.
|
||||
#
|
||||
BOOT_ISOLCPUS=$(cat $CGROUP2/cpuset.cpus.isolated)
|
||||
[[ -n "$BOOT_ISOLCPUS" ]] && {
|
||||
sleep 0.5
|
||||
BOOT_ISOLCPUS=$(cat $CGROUP2/cpuset.cpus.isolated)
|
||||
}
|
||||
if [[ -n "$BOOT_ISOLCPUS" ]]
|
||||
then
|
||||
[[ $(echo $BOOT_ISOLCPUS | sed -e "s/[,-].*//") -le 8 ]] &&
|
||||
skip_test "Pre-isolated CPUs ($BOOT_ISOLCPUS) overlap CPUs to be tested"
|
||||
echo "Pre-isolated CPUs: $BOOT_ISOLCPUS"
|
||||
fi
|
||||
|
||||
cleanup()
|
||||
{
|
||||
online_cpus
|
||||
cd $CGROUP2
|
||||
rmdir A1/A2/A3 A1/A2 A1 B1 > /dev/null 2>&1
|
||||
rmdir test > /dev/null 2>&1
|
||||
rmdir A1/A2/A3 A1/A2 A1 B1 test/A1 test/B1 test > /dev/null 2>&1
|
||||
rmdir rtest/p1/c11 rtest/p1/c12 rtest/p2/c21 \
|
||||
rtest/p2/c22 rtest/p1 rtest/p2 rtest > /dev/null 2>&1
|
||||
[[ -n "$SCHED_DEBUG" ]] &&
|
||||
echo "$SCHED_DEBUG" > /sys/kernel/debug/sched/verbose
|
||||
}
|
||||
@@ -173,14 +183,22 @@ test_add_proc()
|
||||
#
|
||||
# Cgroup test hierarchy
|
||||
#
|
||||
# root -- A1 -- A2 -- A3
|
||||
# +- B1
|
||||
# root
|
||||
# |
|
||||
# +------+------+
|
||||
# | |
|
||||
# A1 B1
|
||||
# |
|
||||
# A2
|
||||
# |
|
||||
# A3
|
||||
#
|
||||
# P<v> = set cpus.partition (0:member, 1:root, 2:isolated)
|
||||
# C<l> = add cpu-list to cpuset.cpus
|
||||
# X<l> = add cpu-list to cpuset.cpus.exclusive
|
||||
# S<p> = use prefix in subtree_control
|
||||
# T = put a task into cgroup
|
||||
# CX<l> = add cpu-list to both cpuset.cpus and cpuset.cpus.exclusive
|
||||
# O<c>=<v> = Write <v> to CPU online file of <c>
|
||||
#
|
||||
# ECPUs - effective CPUs of cpusets
|
||||
@@ -207,130 +225,129 @@ TEST_MATRIX=(
|
||||
" C0-1:P1 . . C2-3 S+:C4-5 . . . 0 A1:4-5"
|
||||
" C0-1 . . C2-3:P1 . . . C2 0 "
|
||||
" C0-1 . . C2-3:P1 . . . C4-5 0 B1:4-5"
|
||||
"C0-3:P1:S+ C2-3:P1 . . . . . . 0 A1:0-1,A2:2-3"
|
||||
"C0-3:P1:S+ C2-3:P1 . . C1-3 . . . 0 A1:1,A2:2-3"
|
||||
"C2-3:P1:S+ C3:P1 . . C3 . . . 0 A1:,A2:3 A1:P1,A2:P1"
|
||||
"C2-3:P1:S+ C3:P1 . . C3 P0 . . 0 A1:3,A2:3 A1:P1,A2:P0"
|
||||
"C2-3:P1:S+ C2:P1 . . C2-4 . . . 0 A1:3-4,A2:2"
|
||||
"C2-3:P1:S+ C3:P1 . . C3 . . C0-2 0 A1:,B1:0-2 A1:P1,A2:P1"
|
||||
"$SETUP_A123_PARTITIONS . C2-3 . . . 0 A1:,A2:2,A3:3 A1:P1,A2:P1,A3:P1"
|
||||
"C0-3:P1:S+ C2-3:P1 . . . . . . 0 A1:0-1|A2:2-3|XA2:2-3"
|
||||
"C0-3:P1:S+ C2-3:P1 . . C1-3 . . . 0 A1:1|A2:2-3|XA2:2-3"
|
||||
"C2-3:P1:S+ C3:P1 . . C3 . . . 0 A1:|A2:3|XA2:3 A1:P1|A2:P1"
|
||||
"C2-3:P1:S+ C3:P1 . . C3 P0 . . 0 A1:3|A2:3 A1:P1|A2:P0"
|
||||
"C2-3:P1:S+ C2:P1 . . C2-4 . . . 0 A1:3-4|A2:2"
|
||||
"C2-3:P1:S+ C3:P1 . . C3 . . C0-2 0 A1:|B1:0-2 A1:P1|A2:P1"
|
||||
"$SETUP_A123_PARTITIONS . C2-3 . . . 0 A1:|A2:2|A3:3 A1:P1|A2:P1|A3:P1"
|
||||
|
||||
# CPU offlining cases:
|
||||
" C0-1 . . C2-3 S+ C4-5 . O2=0 0 A1:0-1,B1:3"
|
||||
"C0-3:P1:S+ C2-3:P1 . . O2=0 . . . 0 A1:0-1,A2:3"
|
||||
"C0-3:P1:S+ C2-3:P1 . . O2=0 O2=1 . . 0 A1:0-1,A2:2-3"
|
||||
"C0-3:P1:S+ C2-3:P1 . . O1=0 . . . 0 A1:0,A2:2-3"
|
||||
"C0-3:P1:S+ C2-3:P1 . . O1=0 O1=1 . . 0 A1:0-1,A2:2-3"
|
||||
"C2-3:P1:S+ C3:P1 . . O3=0 O3=1 . . 0 A1:2,A2:3 A1:P1,A2:P1"
|
||||
"C2-3:P1:S+ C3:P2 . . O3=0 O3=1 . . 0 A1:2,A2:3 A1:P1,A2:P2"
|
||||
"C2-3:P1:S+ C3:P1 . . O2=0 O2=1 . . 0 A1:2,A2:3 A1:P1,A2:P1"
|
||||
"C2-3:P1:S+ C3:P2 . . O2=0 O2=1 . . 0 A1:2,A2:3 A1:P1,A2:P2"
|
||||
"C2-3:P1:S+ C3:P1 . . O2=0 . . . 0 A1:,A2:3 A1:P1,A2:P1"
|
||||
"C2-3:P1:S+ C3:P1 . . O3=0 . . . 0 A1:2,A2: A1:P1,A2:P1"
|
||||
"C2-3:P1:S+ C3:P1 . . T:O2=0 . . . 0 A1:3,A2:3 A1:P1,A2:P-1"
|
||||
"C2-3:P1:S+ C3:P1 . . . T:O3=0 . . 0 A1:2,A2:2 A1:P1,A2:P-1"
|
||||
"$SETUP_A123_PARTITIONS . O1=0 . . . 0 A1:,A2:2,A3:3 A1:P1,A2:P1,A3:P1"
|
||||
"$SETUP_A123_PARTITIONS . O2=0 . . . 0 A1:1,A2:,A3:3 A1:P1,A2:P1,A3:P1"
|
||||
"$SETUP_A123_PARTITIONS . O3=0 . . . 0 A1:1,A2:2,A3: A1:P1,A2:P1,A3:P1"
|
||||
"$SETUP_A123_PARTITIONS . T:O1=0 . . . 0 A1:2-3,A2:2-3,A3:3 A1:P1,A2:P-1,A3:P-1"
|
||||
"$SETUP_A123_PARTITIONS . . T:O2=0 . . 0 A1:1,A2:3,A3:3 A1:P1,A2:P1,A3:P-1"
|
||||
"$SETUP_A123_PARTITIONS . . . T:O3=0 . 0 A1:1,A2:2,A3:2 A1:P1,A2:P1,A3:P-1"
|
||||
"$SETUP_A123_PARTITIONS . T:O1=0 O1=1 . . 0 A1:1,A2:2,A3:3 A1:P1,A2:P1,A3:P1"
|
||||
"$SETUP_A123_PARTITIONS . . T:O2=0 O2=1 . 0 A1:1,A2:2,A3:3 A1:P1,A2:P1,A3:P1"
|
||||
"$SETUP_A123_PARTITIONS . . . T:O3=0 O3=1 0 A1:1,A2:2,A3:3 A1:P1,A2:P1,A3:P1"
|
||||
"$SETUP_A123_PARTITIONS . T:O1=0 O2=0 O1=1 . 0 A1:1,A2:,A3:3 A1:P1,A2:P1,A3:P1"
|
||||
"$SETUP_A123_PARTITIONS . T:O1=0 O2=0 O2=1 . 0 A1:2-3,A2:2-3,A3:3 A1:P1,A2:P-1,A3:P-1"
|
||||
" C0-1 . . C2-3 S+ C4-5 . O2=0 0 A1:0-1|B1:3"
|
||||
"C0-3:P1:S+ C2-3:P1 . . O2=0 . . . 0 A1:0-1|A2:3"
|
||||
"C0-3:P1:S+ C2-3:P1 . . O2=0 O2=1 . . 0 A1:0-1|A2:2-3"
|
||||
"C0-3:P1:S+ C2-3:P1 . . O1=0 . . . 0 A1:0|A2:2-3"
|
||||
"C0-3:P1:S+ C2-3:P1 . . O1=0 O1=1 . . 0 A1:0-1|A2:2-3"
|
||||
"C2-3:P1:S+ C3:P1 . . O3=0 O3=1 . . 0 A1:2|A2:3 A1:P1|A2:P1"
|
||||
"C2-3:P1:S+ C3:P2 . . O3=0 O3=1 . . 0 A1:2|A2:3 A1:P1|A2:P2"
|
||||
"C2-3:P1:S+ C3:P1 . . O2=0 O2=1 . . 0 A1:2|A2:3 A1:P1|A2:P1"
|
||||
"C2-3:P1:S+ C3:P2 . . O2=0 O2=1 . . 0 A1:2|A2:3 A1:P1|A2:P2"
|
||||
"C2-3:P1:S+ C3:P1 . . O2=0 . . . 0 A1:|A2:3 A1:P1|A2:P1"
|
||||
"C2-3:P1:S+ C3:P1 . . O3=0 . . . 0 A1:2|A2: A1:P1|A2:P1"
|
||||
"C2-3:P1:S+ C3:P1 . . T:O2=0 . . . 0 A1:3|A2:3 A1:P1|A2:P-1"
|
||||
"C2-3:P1:S+ C3:P1 . . . T:O3=0 . . 0 A1:2|A2:2 A1:P1|A2:P-1"
|
||||
"$SETUP_A123_PARTITIONS . O1=0 . . . 0 A1:|A2:2|A3:3 A1:P1|A2:P1|A3:P1"
|
||||
"$SETUP_A123_PARTITIONS . O2=0 . . . 0 A1:1|A2:|A3:3 A1:P1|A2:P1|A3:P1"
|
||||
"$SETUP_A123_PARTITIONS . O3=0 . . . 0 A1:1|A2:2|A3: A1:P1|A2:P1|A3:P1"
|
||||
"$SETUP_A123_PARTITIONS . T:O1=0 . . . 0 A1:2-3|A2:2-3|A3:3 A1:P1|A2:P-1|A3:P-1"
|
||||
"$SETUP_A123_PARTITIONS . . T:O2=0 . . 0 A1:1|A2:3|A3:3 A1:P1|A2:P1|A3:P-1"
|
||||
"$SETUP_A123_PARTITIONS . . . T:O3=0 . 0 A1:1|A2:2|A3:2 A1:P1|A2:P1|A3:P-1"
|
||||
"$SETUP_A123_PARTITIONS . T:O1=0 O1=1 . . 0 A1:1|A2:2|A3:3 A1:P1|A2:P1|A3:P1"
|
||||
"$SETUP_A123_PARTITIONS . . T:O2=0 O2=1 . 0 A1:1|A2:2|A3:3 A1:P1|A2:P1|A3:P1"
|
||||
"$SETUP_A123_PARTITIONS . . . T:O3=0 O3=1 0 A1:1|A2:2|A3:3 A1:P1|A2:P1|A3:P1"
|
||||
"$SETUP_A123_PARTITIONS . T:O1=0 O2=0 O1=1 . 0 A1:1|A2:|A3:3 A1:P1|A2:P1|A3:P1"
|
||||
"$SETUP_A123_PARTITIONS . T:O1=0 O2=0 O2=1 . 0 A1:2-3|A2:2-3|A3:3 A1:P1|A2:P-1|A3:P-1"
|
||||
|
||||
# old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS
|
||||
# ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ --------
|
||||
#
|
||||
# Remote partition and cpuset.cpus.exclusive tests
|
||||
#
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 . . . 0 A1:0-3,A2:1-3,A3:2-3,XA1:2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3:P2 . . 0 A1:0-1,A2:2-3,A3:2-3 A1:P0,A2:P2 2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 X3:P2 . . 0 A1:0-2,A2:3,A3:3 A1:P0,A2:P2 3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3 X2-3:P2 . 0 A1:0-1,A2:1,A3:2-3 A1:P0,A3:P2 2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3 X2-3:P2:C3 . 0 A1:0-1,A2:1,A3:2-3 A1:P0,A3:P2 2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C2-3 . . . P2 0 A1:0-3,A2:1-3,A3:2-3,B1:2-3 A1:P0,A3:P0,B1:P-2"
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 . . . 0 A1:0-3|A2:1-3|A3:2-3|XA1:2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3:P2 . . 0 A1:0-1|A2:2-3|A3:2-3 A1:P0|A2:P2 2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 X3:P2 . . 0 A1:0-2|A2:3|A3:3 A1:P0|A2:P2 3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3 X2-3:P2 . 0 A1:0-1|A2:1|A3:2-3 A1:P0|A3:P2 2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3 X2-3:P2:C3 . 0 A1:0-1|A2:1|A3:2-3 A1:P0|A3:P2 2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C2-3 . . . P2 0 A1:0-3|A2:1-3|A3:2-3|B1:2-3 A1:P0|A3:P0|B1:P-2"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4-5 . . . P2 0 B1:4-5 B1:P2 4-5"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3 X2-3:P2 P2 0 A3:2-3,B1:4 A3:P2,B1:P2 2-4"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3 X2-3:P2:C1-3 P2 0 A3:2-3,B1:4 A3:P2,B1:P2 2-4"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4 X1-3 X1-3:P2 P2 . 0 A2:1,A3:2-3 A2:P2,A3:P2 1-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3 X2-3:P2 P2:C4-5 0 A3:2-3,B1:4-5 A3:P2,B1:P2 2-5"
|
||||
" C4:X0-3:S+ X1-3:S+ X2-3 . . P2 . . 0 A1:4,A2:1-3,A3:1-3 A2:P2 1-3"
|
||||
" C4:X0-3:S+ X1-3:S+ X2-3 . . . P2 . 0 A1:4,A2:4,A3:2-3 A3:P2 2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3 X2-3:P2 P2 0 A3:2-3|B1:4 A3:P2|B1:P2 2-4"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3 X2-3:P2:C1-3 P2 0 A3:2-3|B1:4 A3:P2|B1:P2 2-4"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4 X1-3 X1-3:P2 P2 . 0 A2:1|A3:2-3 A2:P2|A3:P2 1-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3 X2-3:P2 P2:C4-5 0 A3:2-3|B1:4-5 A3:P2|B1:P2 2-5"
|
||||
" C4:X0-3:S+ X1-3:S+ X2-3 . . P2 . . 0 A1:4|A2:1-3|A3:1-3 A2:P2 1-3"
|
||||
" C4:X0-3:S+ X1-3:S+ X2-3 . . . P2 . 0 A1:4|A2:4|A3:2-3 A3:P2 2-3"
|
||||
|
||||
# Nested remote/local partition tests
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4-5 X2-3 X2-3:P1 P2 P1 0 A1:0-1,A2:,A3:2-3,B1:4-5 \
|
||||
A1:P0,A2:P1,A3:P2,B1:P1 2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3:P1 P2 P1 0 A1:0-1,A2:,A3:2-3,B1:4 \
|
||||
A1:P0,A2:P1,A3:P2,B1:P1 2-4,2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3:P1 . P1 0 A1:0-1,A2:2-3,A3:2-3,B1:4 \
|
||||
A1:P0,A2:P1,A3:P0,B1:P1"
|
||||
" C0-3:S+ C1-3:S+ C3 C4 X2-3 X2-3:P1 P2 P1 0 A1:0-1,A2:2,A3:3,B1:4 \
|
||||
A1:P0,A2:P1,A3:P2,B1:P1 2-4,3"
|
||||
" C0-4:S+ C1-4:S+ C2-4 . X2-4 X2-4:P2 X4:P1 . 0 A1:0-1,A2:2-3,A3:4 \
|
||||
A1:P0,A2:P2,A3:P1 2-4,2-3"
|
||||
" C0-4:S+ C1-4:S+ C2-4 . X2-4 X2-4:P2 X3-4:P1 . 0 A1:0-1,A2:2,A3:3-4 \
|
||||
A1:P0,A2:P2,A3:P1 2"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4-5 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:|A3:2-3|B1:4-5 \
|
||||
A1:P0|A2:P1|A3:P2|B1:P1 2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:|A3:2-3|B1:4 \
|
||||
A1:P0|A2:P1|A3:P2|B1:P1 2-4|2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3:P1 . P1 0 A1:0-1|A2:2-3|A3:2-3|B1:4 \
|
||||
A1:P0|A2:P1|A3:P0|B1:P1"
|
||||
" C0-3:S+ C1-3:S+ C3 C4 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:2|A3:3|B1:4 \
|
||||
A1:P0|A2:P1|A3:P2|B1:P1 2-4|3"
|
||||
" C0-4:S+ C1-4:S+ C2-4 . X2-4 X2-4:P2 X4:P1 . 0 A1:0-1|A2:2-3|A3:4 \
|
||||
A1:P0|A2:P2|A3:P1 2-4|2-3"
|
||||
" C0-4:S+ C1-4:S+ C2-4 . X2-4 X2-4:P2 X3-4:P1 . 0 A1:0-1|A2:2|A3:3-4 \
|
||||
A1:P0|A2:P2|A3:P1 2"
|
||||
" C0-4:X2-4:S+ C1-4:X2-4:S+:P2 C2-4:X4:P1 \
|
||||
. . X5 . . 0 A1:0-4,A2:1-4,A3:2-4 \
|
||||
A1:P0,A2:P-2,A3:P-1"
|
||||
. . X5 . . 0 A1:0-4|A2:1-4|A3:2-4 \
|
||||
A1:P0|A2:P-2|A3:P-1 ."
|
||||
" C0-4:X2-4:S+ C1-4:X2-4:S+:P2 C2-4:X4:P1 \
|
||||
. . . X1 . 0 A1:0-1,A2:2-4,A3:2-4 \
|
||||
A1:P0,A2:P2,A3:P-1 2-4"
|
||||
. . . X1 . 0 A1:0-1|A2:2-4|A3:2-4 \
|
||||
A1:P0|A2:P2|A3:P-1 2-4"
|
||||
|
||||
# Remote partition offline tests
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3 X2-3:P2:O2=0 . 0 A1:0-1,A2:1,A3:3 A1:P0,A3:P2 2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3 X2-3:P2:O2=0 O2=1 0 A1:0-1,A2:1,A3:2-3 A1:P0,A3:P2 2-3"
|
||||
" C0-3:S+ C1-3:S+ C3 . X2-3 X2-3 P2:O3=0 . 0 A1:0-2,A2:1-2,A3: A1:P0,A3:P2 3"
|
||||
" C0-3:S+ C1-3:S+ C3 . X2-3 X2-3 T:P2:O3=0 . 0 A1:0-2,A2:1-2,A3:1-2 A1:P0,A3:P-2 3,"
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3 X2-3:P2:O2=0 . 0 A1:0-1|A2:1|A3:3 A1:P0|A3:P2 2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3 X2-3:P2:O2=0 O2=1 0 A1:0-1|A2:1|A3:2-3 A1:P0|A3:P2 2-3"
|
||||
" C0-3:S+ C1-3:S+ C3 . X2-3 X2-3 P2:O3=0 . 0 A1:0-2|A2:1-2|A3: A1:P0|A3:P2 3"
|
||||
" C0-3:S+ C1-3:S+ C3 . X2-3 X2-3 T:P2:O3=0 . 0 A1:0-2|A2:1-2|A3:1-2 A1:P0|A3:P-2 3|"
|
||||
|
||||
# An invalidated remote partition cannot self-recover from hotplug
|
||||
" C0-3:S+ C1-3:S+ C2 . X2-3 X2-3 T:P2:O2=0 O2=1 0 A1:0-3,A2:1-3,A3:2 A1:P0,A3:P-2"
|
||||
" C0-3:S+ C1-3:S+ C2 . X2-3 X2-3 T:P2:O2=0 O2=1 0 A1:0-3|A2:1-3|A3:2 A1:P0|A3:P-2 ."
|
||||
|
||||
# cpus.exclusive.effective clearing test
|
||||
" C0-3:S+ C1-3:S+ C2 . X2-3:X . . . 0 A1:0-3,A2:1-3,A3:2,XA1:"
|
||||
" C0-3:S+ C1-3:S+ C2 . X2-3:X . . . 0 A1:0-3|A2:1-3|A3:2|XA1:"
|
||||
|
||||
# Invalid to valid remote partition transition test
|
||||
" C0-3:S+ C1-3 . . . X3:P2 . . 0 A1:0-3,A2:1-3,XA2: A2:P-2"
|
||||
" C0-3:S+ C1-3 . . . X3:P2 . . 0 A1:0-3|A2:1-3|XA2: A2:P-2 ."
|
||||
" C0-3:S+ C1-3:X3:P2
|
||||
. . X2-3 P2 . . 0 A1:0-2,A2:3,XA2:3 A2:P2 3"
|
||||
. . X2-3 P2 . . 0 A1:0-2|A2:3|XA2:3 A2:P2 3"
|
||||
|
||||
# Invalid to valid local partition direct transition tests
|
||||
" C1-3:S+:P2 X4:P2 . . . . . . 0 A1:1-3,XA1:1-3,A2:1-3:XA2: A1:P2,A2:P-2 1-3"
|
||||
" C1-3:S+:P2 X4:P2 . . . X3:P2 . . 0 A1:1-2,XA1:1-3,A2:3:XA2:3 A1:P2,A2:P2 1-3"
|
||||
" C0-3:P2 . . C4-6 C0-4 . . . 0 A1:0-4,B1:4-6 A1:P-2,B1:P0"
|
||||
" C0-3:P2 . . C4-6 C0-4:C0-3 . . . 0 A1:0-3,B1:4-6 A1:P2,B1:P0 0-3"
|
||||
" C0-3:P2 . . C3-5:C4-5 . . . . 0 A1:0-3,B1:4-5 A1:P2,B1:P0 0-3"
|
||||
" C1-3:S+:P2 X4:P2 . . . . . . 0 A1:1-3|XA1:1-3|A2:1-3:XA2: A1:P2|A2:P-2 1-3"
|
||||
" C1-3:S+:P2 X4:P2 . . . X3:P2 . . 0 A1:1-2|XA1:1-3|A2:3:XA2:3 A1:P2|A2:P2 1-3"
|
||||
" C0-3:P2 . . C4-6 C0-4 . . . 0 A1:0-4|B1:4-6 A1:P-2|B1:P0"
|
||||
" C0-3:P2 . . C4-6 C0-4:C0-3 . . . 0 A1:0-3|B1:4-6 A1:P2|B1:P0 0-3"
|
||||
|
||||
# Local partition invalidation tests
|
||||
" C0-3:X1-3:S+:P2 C1-3:X2-3:S+:P2 C2-3:X3:P2 \
|
||||
. . . . . 0 A1:1,A2:2,A3:3 A1:P2,A2:P2,A3:P2 1-3"
|
||||
. . . . . 0 A1:1|A2:2|A3:3 A1:P2|A2:P2|A3:P2 1-3"
|
||||
" C0-3:X1-3:S+:P2 C1-3:X2-3:S+:P2 C2-3:X3:P2 \
|
||||
. . X4 . . 0 A1:1-3,A2:1-3,A3:2-3,XA2:,XA3: A1:P2,A2:P-2,A3:P-2 1-3"
|
||||
. . X4 . . 0 A1:1-3|A2:1-3|A3:2-3|XA2:|XA3: A1:P2|A2:P-2|A3:P-2 1-3"
|
||||
" C0-3:X1-3:S+:P2 C1-3:X2-3:S+:P2 C2-3:X3:P2 \
|
||||
. . C4:X . . 0 A1:1-3,A2:1-3,A3:2-3,XA2:,XA3: A1:P2,A2:P-2,A3:P-2 1-3"
|
||||
. . C4:X . . 0 A1:1-3|A2:1-3|A3:2-3|XA2:|XA3: A1:P2|A2:P-2|A3:P-2 1-3"
|
||||
# Local partition CPU change tests
|
||||
" C0-5:S+:P2 C4-5:S+:P1 . . . C3-5 . . 0 A1:0-2,A2:3-5 A1:P2,A2:P1 0-2"
|
||||
" C0-5:S+:P2 C4-5:S+:P1 . . C1-5 . . . 0 A1:1-3,A2:4-5 A1:P2,A2:P1 1-3"
|
||||
" C0-5:S+:P2 C4-5:S+:P1 . . . C3-5 . . 0 A1:0-2|A2:3-5 A1:P2|A2:P1 0-2"
|
||||
" C0-5:S+:P2 C4-5:S+:P1 . . C1-5 . . . 0 A1:1-3|A2:4-5 A1:P2|A2:P1 1-3"
|
||||
|
||||
# cpus_allowed/exclusive_cpus update tests
|
||||
" C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3 \
|
||||
. X:C4 . P2 . 0 A1:4,A2:4,XA2:,XA3:,A3:4 \
|
||||
A1:P0,A3:P-2"
|
||||
. X:C4 . P2 . 0 A1:4|A2:4|XA2:|XA3:|A3:4 \
|
||||
A1:P0|A3:P-2 ."
|
||||
" C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3 \
|
||||
. X1 . P2 . 0 A1:0-3,A2:1-3,XA1:1,XA2:,XA3:,A3:2-3 \
|
||||
A1:P0,A3:P-2"
|
||||
. X1 . P2 . 0 A1:0-3|A2:1-3|XA1:1|XA2:|XA3:|A3:2-3 \
|
||||
A1:P0|A3:P-2 ."
|
||||
" C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3 \
|
||||
. . X3 P2 . 0 A1:0-2,A2:1-2,XA2:3,XA3:3,A3:3 \
|
||||
A1:P0,A3:P2 3"
|
||||
. . X3 P2 . 0 A1:0-2|A2:1-2|XA2:3|XA3:3|A3:3 \
|
||||
A1:P0|A3:P2 3"
|
||||
" C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3:P2 \
|
||||
. . X3 . . 0 A1:0-3,A2:1-3,XA2:3,XA3:3,A3:2-3 \
|
||||
A1:P0,A3:P-2"
|
||||
. . X3 . . 0 A1:0-2|A2:1-2|XA2:3|XA3:3|A3:3|XA3:3 \
|
||||
A1:P0|A3:P2 3"
|
||||
" C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3:P2 \
|
||||
. X4 . . . 0 A1:0-3,A2:1-3,A3:2-3,XA1:4,XA2:,XA3 \
|
||||
A1:P0,A3:P-2"
|
||||
. X4 . . . 0 A1:0-3|A2:1-3|A3:2-3|XA1:4|XA2:|XA3 \
|
||||
A1:P0|A3:P-2"
|
||||
|
||||
# old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS
|
||||
# ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ --------
|
||||
@@ -339,68 +356,127 @@ TEST_MATRIX=(
|
||||
#
|
||||
# Adding CPUs to partition root that are not in parent's
|
||||
# cpuset.cpus is allowed, but those extra CPUs are ignored.
|
||||
"C2-3:P1:S+ C3:P1 . . . C2-4 . . 0 A1:,A2:2-3 A1:P1,A2:P1"
|
||||
"C2-3:P1:S+ C3:P1 . . . C2-4 . . 0 A1:|A2:2-3 A1:P1|A2:P1"
|
||||
|
||||
# Taking away all CPUs from parent or itself if there are tasks
|
||||
# will make the partition invalid.
|
||||
"C2-3:P1:S+ C3:P1 . . T C2-3 . . 0 A1:2-3,A2:2-3 A1:P1,A2:P-1"
|
||||
" C3:P1:S+ C3 . . T P1 . . 0 A1:3,A2:3 A1:P1,A2:P-1"
|
||||
"$SETUP_A123_PARTITIONS . T:C2-3 . . . 0 A1:2-3,A2:2-3,A3:3 A1:P1,A2:P-1,A3:P-1"
|
||||
"$SETUP_A123_PARTITIONS . T:C2-3:C1-3 . . . 0 A1:1,A2:2,A3:3 A1:P1,A2:P1,A3:P1"
|
||||
"C2-3:P1:S+ C3:P1 . . T C2-3 . . 0 A1:2-3|A2:2-3 A1:P1|A2:P-1"
|
||||
" C3:P1:S+ C3 . . T P1 . . 0 A1:3|A2:3 A1:P1|A2:P-1"
|
||||
"$SETUP_A123_PARTITIONS . T:C2-3 . . . 0 A1:2-3|A2:2-3|A3:3 A1:P1|A2:P-1|A3:P-1"
|
||||
"$SETUP_A123_PARTITIONS . T:C2-3:C1-3 . . . 0 A1:1|A2:2|A3:3 A1:P1|A2:P1|A3:P1"
|
||||
|
||||
# Changing a partition root to member makes child partitions invalid
|
||||
"C2-3:P1:S+ C3:P1 . . P0 . . . 0 A1:2-3,A2:3 A1:P0,A2:P-1"
|
||||
"$SETUP_A123_PARTITIONS . C2-3 P0 . . 0 A1:2-3,A2:2-3,A3:3 A1:P1,A2:P0,A3:P-1"
|
||||
"C2-3:P1:S+ C3:P1 . . P0 . . . 0 A1:2-3|A2:3 A1:P0|A2:P-1"
|
||||
"$SETUP_A123_PARTITIONS . C2-3 P0 . . 0 A1:2-3|A2:2-3|A3:3 A1:P1|A2:P0|A3:P-1"
|
||||
|
||||
# cpuset.cpus can contains cpus not in parent's cpuset.cpus as long
|
||||
# as they overlap.
|
||||
"C2-3:P1:S+ . . . . C3-4:P1 . . 0 A1:2,A2:3 A1:P1,A2:P1"
|
||||
"C2-3:P1:S+ . . . . C3-4:P1 . . 0 A1:2|A2:3 A1:P1|A2:P1"
|
||||
|
||||
# Deletion of CPUs distributed to child cgroup is allowed.
|
||||
"C0-1:P1:S+ C1 . C2-3 C4-5 . . . 0 A1:4-5,A2:4-5"
|
||||
"C0-1:P1:S+ C1 . C2-3 C4-5 . . . 0 A1:4-5|A2:4-5"
|
||||
|
||||
# To become a valid partition root, cpuset.cpus must overlap parent's
|
||||
# cpuset.cpus.
|
||||
" C0-1:P1 . . C2-3 S+ C4-5:P1 . . 0 A1:0-1,A2:0-1 A1:P1,A2:P-1"
|
||||
" C0-1:P1 . . C2-3 S+ C4-5:P1 . . 0 A1:0-1|A2:0-1 A1:P1|A2:P-1"
|
||||
|
||||
# Enabling partition with child cpusets is allowed
|
||||
" C0-1:S+ C1 . C2-3 P1 . . . 0 A1:0-1,A2:1 A1:P1"
|
||||
" C0-1:S+ C1 . C2-3 P1 . . . 0 A1:0-1|A2:1 A1:P1"
|
||||
|
||||
# A partition root with non-partition root parent is invalid, but it
|
||||
# A partition root with non-partition root parent is invalid| but it
|
||||
# can be made valid if its parent becomes a partition root too.
|
||||
" C0-1:S+ C1 . C2-3 . P2 . . 0 A1:0-1,A2:1 A1:P0,A2:P-2"
|
||||
" C0-1:S+ C1:P2 . C2-3 P1 . . . 0 A1:0,A2:1 A1:P1,A2:P2"
|
||||
" C0-1:S+ C1 . C2-3 . P2 . . 0 A1:0-1|A2:1 A1:P0|A2:P-2"
|
||||
" C0-1:S+ C1:P2 . C2-3 P1 . . . 0 A1:0|A2:1 A1:P1|A2:P2 0-1|1"
|
||||
|
||||
# A non-exclusive cpuset.cpus change will invalidate partition and its siblings
|
||||
" C0-1:P1 . . C2-3 C0-2 . . . 0 A1:0-2,B1:2-3 A1:P-1,B1:P0"
|
||||
" C0-1:P1 . . P1:C2-3 C0-2 . . . 0 A1:0-2,B1:2-3 A1:P-1,B1:P-1"
|
||||
" C0-1 . . P1:C2-3 C0-2 . . . 0 A1:0-2,B1:2-3 A1:P0,B1:P-1"
|
||||
" C0-1:P1 . . C2-3 C0-2 . . . 0 A1:0-2|B1:2-3 A1:P-1|B1:P0"
|
||||
" C0-1:P1 . . P1:C2-3 C0-2 . . . 0 A1:0-2|B1:2-3 A1:P-1|B1:P-1"
|
||||
" C0-1 . . P1:C2-3 C0-2 . . . 0 A1:0-2|B1:2-3 A1:P0|B1:P-1"
|
||||
|
||||
# cpuset.cpus can overlap with sibling cpuset.cpus.exclusive but not subsumed by it
|
||||
" C0-3 . . C4-5 X5 . . . 0 A1:0-3,B1:4-5"
|
||||
" C0-3 . . C4-5 X5 . . . 0 A1:0-3|B1:4-5"
|
||||
|
||||
# Child partition root that try to take all CPUs from parent partition
|
||||
# with tasks will remain invalid.
|
||||
" C1-4:P1:S+ P1 . . . . . . 0 A1:1-4,A2:1-4 A1:P1,A2:P-1"
|
||||
" C1-4:P1:S+ P1 . . . C1-4 . . 0 A1,A2:1-4 A1:P1,A2:P1"
|
||||
" C1-4:P1:S+ P1 . . T C1-4 . . 0 A1:1-4,A2:1-4 A1:P1,A2:P-1"
|
||||
" C1-4:P1:S+ P1 . . . . . . 0 A1:1-4|A2:1-4 A1:P1|A2:P-1"
|
||||
" C1-4:P1:S+ P1 . . . C1-4 . . 0 A1|A2:1-4 A1:P1|A2:P1"
|
||||
" C1-4:P1:S+ P1 . . T C1-4 . . 0 A1:1-4|A2:1-4 A1:P1|A2:P-1"
|
||||
|
||||
# Clearing of cpuset.cpus with a preset cpuset.cpus.exclusive shouldn't
|
||||
# affect cpuset.cpus.exclusive.effective.
|
||||
" C1-4:X3:S+ C1:X3 . . . C . . 0 A2:1-4,XA2:3"
|
||||
" C1-4:X3:S+ C1:X3 . . . C . . 0 A2:1-4|XA2:3"
|
||||
|
||||
# cpuset.cpus can contain CPUs that overlap a sibling cpuset with cpus.exclusive
|
||||
# but creating a local partition out of it is not allowed. Similarly and change
|
||||
# in cpuset.cpus of a local partition that overlaps sibling exclusive CPUs will
|
||||
# invalidate it.
|
||||
" CX1-4:S+ CX2-4:P2 . C5-6 . . . P1 0 A1:1|A2:2-4|B1:5-6|XB1:5-6 \
|
||||
A1:P0|A2:P2:B1:P1 2-4"
|
||||
" CX1-4:S+ CX2-4:P2 . C3-6 . . . P1 0 A1:1|A2:2-4|B1:5-6 \
|
||||
A1:P0|A2:P2:B1:P-1 2-4"
|
||||
" CX1-4:S+ CX2-4:P2 . C5-6 . . . P1:C3-6 0 A1:1|A2:2-4|B1:5-6 \
|
||||
A1:P0|A2:P2:B1:P-1 2-4"
|
||||
|
||||
# old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS
|
||||
# ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ --------
|
||||
# Failure cases:
|
||||
|
||||
# A task cannot be added to a partition with no cpu
|
||||
"C2-3:P1:S+ C3:P1 . . O2=0:T . . . 1 A1:,A2:3 A1:P1,A2:P1"
|
||||
"C2-3:P1:S+ C3:P1 . . O2=0:T . . . 1 A1:|A2:3 A1:P1|A2:P1"
|
||||
|
||||
# Changes to cpuset.cpus.exclusive that violate exclusivity rule is rejected
|
||||
" C0-3 . . C4-5 X0-3 . . X3-5 1 A1:0-3,B1:4-5"
|
||||
" C0-3 . . C4-5 X0-3 . . X3-5 1 A1:0-3|B1:4-5"
|
||||
|
||||
# cpuset.cpus cannot be a subset of sibling cpuset.cpus.exclusive
|
||||
" C0-3 . . C4-5 X3-5 . . . 1 A1:0-3,B1:4-5"
|
||||
" C0-3 . . C4-5 X3-5 . . . 1 A1:0-3|B1:4-5"
|
||||
)
|
||||
|
||||
#
|
||||
# Cpuset controller remote partition test matrix.
|
||||
#
|
||||
# Cgroup test hierarchy
|
||||
#
|
||||
# root
|
||||
# |
|
||||
# rtest (cpuset.cpus.exclusive=1-7)
|
||||
# |
|
||||
# +------+------+
|
||||
# | |
|
||||
# p1 p2
|
||||
# +--+--+ +--+--+
|
||||
# | | | |
|
||||
# c11 c12 c21 c22
|
||||
#
|
||||
# REMOTE_TEST_MATRIX uses the same notational convention as TEST_MATRIX.
|
||||
# Only CPUs 1-7 should be used.
|
||||
#
|
||||
REMOTE_TEST_MATRIX=(
|
||||
# old-p1 old-p2 old-c11 old-c12 old-c21 old-c22
|
||||
# new-p1 new-p2 new-c11 new-c12 new-c21 new-c22 ECPUs Pstate ISOLCPUS
|
||||
# ------ ------ ------- ------- ------- ------- ----- ------ --------
|
||||
" X1-3:S+ X4-6:S+ X1-2 X3 X4-5 X6 \
|
||||
. . P2 P2 P2 P2 c11:1-2|c12:3|c21:4-5|c22:6 \
|
||||
c11:P2|c12:P2|c21:P2|c22:P2 1-6"
|
||||
" CX1-4:S+ . X1-2:P2 C3 . . \
|
||||
. . . C3-4 . . p1:3-4|c11:1-2|c12:3-4 \
|
||||
p1:P0|c11:P2|c12:P0 1-2"
|
||||
" CX1-4:S+ . X1-2:P2 . . . \
|
||||
X2-4 . . . . . p1:1,3-4|c11:2 \
|
||||
p1:P0|c11:P2 2"
|
||||
" CX1-5:S+ . X1-2:P2 X3-5:P1 . . \
|
||||
X2-4 . . . . . p1:1,5|c11:2|c12:3-4 \
|
||||
p1:P0|c11:P2|c12:P1 2"
|
||||
" CX1-4:S+ . X1-2:P2 X3-4:P1 . . \
|
||||
. . X2 . . . p1:1|c11:2|c12:3-4 \
|
||||
p1:P0|c11:P2|c12:P1 2"
|
||||
# p1 as member, will get its effective CPUs from its parent rtest
|
||||
" CX1-4:S+ . X1-2:P2 X3-4:P1 . . \
|
||||
. . X1 CX2-4 . . p1:5-7|c11:1|c12:2-4 \
|
||||
p1:P0|c11:P2|c12:P1 1"
|
||||
" CX1-4:S+ X5-6:P1:S+ . . . . \
|
||||
. . X1-2:P2 X4-5:P1 . X1-7:P2 p1:3|c11:1-2|c12:4:c22:5-6 \
|
||||
p1:P0|p2:P1|c11:P2|c12:P1|c22:P2 \
|
||||
1-2,4-6|1-2,5-6"
|
||||
)
|
||||
|
||||
#
|
||||
@@ -453,25 +529,26 @@ set_ctrl_state()
|
||||
PFILE=$CGRP/cpuset.cpus.partition
|
||||
CFILE=$CGRP/cpuset.cpus
|
||||
XFILE=$CGRP/cpuset.cpus.exclusive
|
||||
S=$(expr substr $CMD 1 1)
|
||||
if [[ $S = S ]]
|
||||
then
|
||||
PREFIX=${CMD#?}
|
||||
case $CMD in
|
||||
S*) PREFIX=${CMD#?}
|
||||
COMM="echo ${PREFIX}${CTRL} > $SFILE"
|
||||
eval $COMM $REDIRECT
|
||||
elif [[ $S = X ]]
|
||||
then
|
||||
;;
|
||||
X*)
|
||||
CPUS=${CMD#?}
|
||||
COMM="echo $CPUS > $XFILE"
|
||||
eval $COMM $REDIRECT
|
||||
elif [[ $S = C ]]
|
||||
then
|
||||
CPUS=${CMD#?}
|
||||
;;
|
||||
CX*)
|
||||
CPUS=${CMD#??}
|
||||
COMM="echo $CPUS > $CFILE; echo $CPUS > $XFILE"
|
||||
eval $COMM $REDIRECT
|
||||
;;
|
||||
C*) CPUS=${CMD#?}
|
||||
COMM="echo $CPUS > $CFILE"
|
||||
eval $COMM $REDIRECT
|
||||
elif [[ $S = P ]]
|
||||
then
|
||||
VAL=${CMD#?}
|
||||
;;
|
||||
P*) VAL=${CMD#?}
|
||||
case $VAL in
|
||||
0) VAL=member
|
||||
;;
|
||||
@@ -486,15 +563,17 @@ set_ctrl_state()
|
||||
esac
|
||||
COMM="echo $VAL > $PFILE"
|
||||
eval $COMM $REDIRECT
|
||||
elif [[ $S = O ]]
|
||||
then
|
||||
VAL=${CMD#?}
|
||||
;;
|
||||
O*) VAL=${CMD#?}
|
||||
write_cpu_online $VAL
|
||||
elif [[ $S = T ]]
|
||||
then
|
||||
COMM="echo 0 > $TFILE"
|
||||
;;
|
||||
T*) COMM="echo 0 > $TFILE"
|
||||
eval $COMM $REDIRECT
|
||||
fi
|
||||
;;
|
||||
*) echo "Unknown command: $CMD"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
RET=$?
|
||||
[[ $RET -ne 0 ]] && {
|
||||
[[ -n "$SHOWERR" ]] && {
|
||||
@@ -532,21 +611,18 @@ online_cpus()
|
||||
}
|
||||
|
||||
#
|
||||
# Return 1 if the list of effective cpus isn't the same as the initial list.
|
||||
# Remove all the test cgroup directories
|
||||
#
|
||||
reset_cgroup_states()
|
||||
{
|
||||
echo 0 > $CGROUP2/cgroup.procs
|
||||
online_cpus
|
||||
rmdir A1/A2/A3 A1/A2 A1 B1 > /dev/null 2>&1
|
||||
pause 0.02
|
||||
set_ctrl_state . R-
|
||||
pause 0.01
|
||||
rmdir $RESET_LIST > /dev/null 2>&1
|
||||
}
|
||||
|
||||
dump_states()
|
||||
{
|
||||
for DIR in . A1 A1/A2 A1/A2/A3 B1
|
||||
for DIR in $CGROUP_LIST
|
||||
do
|
||||
CPUS=$DIR/cpuset.cpus
|
||||
ECPUS=$DIR/cpuset.cpus.effective
|
||||
@@ -565,18 +641,34 @@ dump_states()
|
||||
done
|
||||
}
|
||||
|
||||
#
|
||||
# Set the actual cgroup directory into $CGRP_DIR
|
||||
# $1 - cgroup name
|
||||
#
|
||||
set_cgroup_dir()
|
||||
{
|
||||
CGRP_DIR=$1
|
||||
[[ $CGRP_DIR = A2 ]] && CGRP_DIR=A1/A2
|
||||
[[ $CGRP_DIR = A3 ]] && CGRP_DIR=A1/A2/A3
|
||||
[[ $CGRP_DIR = c11 ]] && CGRP_DIR=p1/c11
|
||||
[[ $CGRP_DIR = c12 ]] && CGRP_DIR=p1/c12
|
||||
[[ $CGRP_DIR = c21 ]] && CGRP_DIR=p2/c21
|
||||
[[ $CGRP_DIR = c22 ]] && CGRP_DIR=p2/c22
|
||||
}
|
||||
|
||||
#
|
||||
# Check effective cpus
|
||||
# $1 - check string, format: <cgroup>:<cpu-list>[,<cgroup>:<cpu-list>]*
|
||||
# $1 - check string, format: <cgroup>:<cpu-list>[|<cgroup>:<cpu-list>]*
|
||||
#
|
||||
check_effective_cpus()
|
||||
{
|
||||
CHK_STR=$1
|
||||
for CHK in $(echo $CHK_STR | sed -e "s/,/ /g")
|
||||
for CHK in $(echo $CHK_STR | sed -e "s/|/ /g")
|
||||
do
|
||||
set -- $(echo $CHK | sed -e "s/:/ /g")
|
||||
CGRP=$1
|
||||
CPUS=$2
|
||||
EXPECTED_CPUS=$2
|
||||
ACTUAL_CPUS=
|
||||
if [[ $CGRP = X* ]]
|
||||
then
|
||||
CGRP=${CGRP#X}
|
||||
@@ -584,41 +676,39 @@ check_effective_cpus()
|
||||
else
|
||||
FILE=cpuset.cpus.effective
|
||||
fi
|
||||
[[ $CGRP = A2 ]] && CGRP=A1/A2
|
||||
[[ $CGRP = A3 ]] && CGRP=A1/A2/A3
|
||||
[[ -e $CGRP/$FILE ]] || return 1
|
||||
[[ $CPUS = $(cat $CGRP/$FILE) ]] || return 1
|
||||
set_cgroup_dir $CGRP
|
||||
[[ -e $CGRP_DIR/$FILE ]] || return 1
|
||||
ACTUAL_CPUS=$(cat $CGRP_DIR/$FILE)
|
||||
[[ $EXPECTED_CPUS = $ACTUAL_CPUS ]] || return 1
|
||||
done
|
||||
}
|
||||
|
||||
#
|
||||
# Check cgroup states
|
||||
# $1 - check string, format: <cgroup>:<state>[,<cgroup>:<state>]*
|
||||
# $1 - check string, format: <cgroup>:<state>[|<cgroup>:<state>]*
|
||||
#
|
||||
check_cgroup_states()
|
||||
{
|
||||
CHK_STR=$1
|
||||
for CHK in $(echo $CHK_STR | sed -e "s/,/ /g")
|
||||
for CHK in $(echo $CHK_STR | sed -e "s/|/ /g")
|
||||
do
|
||||
set -- $(echo $CHK | sed -e "s/:/ /g")
|
||||
CGRP=$1
|
||||
CGRP_DIR=$CGRP
|
||||
STATE=$2
|
||||
EXPECTED_STATE=$2
|
||||
FILE=
|
||||
EVAL=$(expr substr $STATE 2 2)
|
||||
[[ $CGRP = A2 ]] && CGRP_DIR=A1/A2
|
||||
[[ $CGRP = A3 ]] && CGRP_DIR=A1/A2/A3
|
||||
EVAL=$(expr substr $EXPECTED_STATE 2 2)
|
||||
|
||||
case $STATE in
|
||||
set_cgroup_dir $CGRP
|
||||
case $EXPECTED_STATE in
|
||||
P*) FILE=$CGRP_DIR/cpuset.cpus.partition
|
||||
;;
|
||||
*) echo "Unknown state: $STATE!"
|
||||
*) echo "Unknown state: $EXPECTED_STATE!"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
VAL=$(cat $FILE)
|
||||
ACTUAL_STATE=$(cat $FILE)
|
||||
|
||||
case "$VAL" in
|
||||
case "$ACTUAL_STATE" in
|
||||
member) VAL=0
|
||||
;;
|
||||
root) VAL=1
|
||||
@@ -642,7 +732,7 @@ check_cgroup_states()
|
||||
[[ $VAL -eq 1 && $VERBOSE -gt 0 ]] && {
|
||||
DOMS=$(cat $CGRP_DIR/cpuset.cpus.effective)
|
||||
[[ -n "$DOMS" ]] &&
|
||||
echo " [$CGRP] sched-domain: $DOMS" > $CONSOLE
|
||||
echo " [$CGRP_DIR] sched-domain: $DOMS" > $CONSOLE
|
||||
}
|
||||
done
|
||||
return 0
|
||||
@@ -665,22 +755,22 @@ check_cgroup_states()
|
||||
#
|
||||
check_isolcpus()
|
||||
{
|
||||
EXPECT_VAL=$1
|
||||
ISOLCPUS=
|
||||
EXPECTED_ISOLCPUS=$1
|
||||
ISCPUS=${CGROUP2}/cpuset.cpus.isolated
|
||||
ISOLCPUS=$(cat $ISCPUS)
|
||||
LASTISOLCPU=
|
||||
SCHED_DOMAINS=/sys/kernel/debug/sched/domains
|
||||
ISCPUS=${CGROUP2}/cpuset.cpus.isolated
|
||||
if [[ $EXPECT_VAL = . ]]
|
||||
if [[ $EXPECTED_ISOLCPUS = . ]]
|
||||
then
|
||||
EXPECT_VAL=
|
||||
EXPECT_VAL2=
|
||||
elif [[ $(expr $EXPECT_VAL : ".*,.*") > 0 ]]
|
||||
EXPECTED_ISOLCPUS=
|
||||
EXPECTED_SDOMAIN=
|
||||
elif [[ $(expr $EXPECTED_ISOLCPUS : ".*|.*") > 0 ]]
|
||||
then
|
||||
set -- $(echo $EXPECT_VAL | sed -e "s/,/ /g")
|
||||
EXPECT_VAL=$1
|
||||
EXPECT_VAL2=$2
|
||||
set -- $(echo $EXPECTED_ISOLCPUS | sed -e "s/|/ /g")
|
||||
EXPECTED_ISOLCPUS=$2
|
||||
EXPECTED_SDOMAIN=$1
|
||||
else
|
||||
EXPECT_VAL2=$EXPECT_VAL
|
||||
EXPECTED_SDOMAIN=$EXPECTED_ISOLCPUS
|
||||
fi
|
||||
|
||||
#
|
||||
@@ -689,20 +779,21 @@ check_isolcpus()
|
||||
# to make appending those CPUs easier.
|
||||
#
|
||||
[[ -n "$BOOT_ISOLCPUS" ]] && {
|
||||
EXPECT_VAL=${EXPECT_VAL:+${EXPECT_VAL},}${BOOT_ISOLCPUS}
|
||||
EXPECT_VAL2=${EXPECT_VAL2:+${EXPECT_VAL2},}${BOOT_ISOLCPUS}
|
||||
EXPECTED_ISOLCPUS=${EXPECTED_ISOLCPUS:+${EXPECTED_ISOLCPUS},}${BOOT_ISOLCPUS}
|
||||
EXPECTED_SDOMAIN=${EXPECTED_SDOMAIN:+${EXPECTED_SDOMAIN},}${BOOT_ISOLCPUS}
|
||||
}
|
||||
|
||||
#
|
||||
# Check cpuset.cpus.isolated cpumask
|
||||
#
|
||||
[[ "$EXPECT_VAL2" != "$ISOLCPUS" ]] && {
|
||||
[[ "$EXPECTED_ISOLCPUS" != "$ISOLCPUS" ]] && {
|
||||
# Take a 50ms pause and try again
|
||||
pause 0.05
|
||||
ISOLCPUS=$(cat $ISCPUS)
|
||||
}
|
||||
[[ "$EXPECT_VAL2" != "$ISOLCPUS" ]] && return 1
|
||||
[[ "$EXPECTED_ISOLCPUS" != "$ISOLCPUS" ]] && return 1
|
||||
ISOLCPUS=
|
||||
EXPECTED_ISOLCPUS=$EXPECTED_SDOMAIN
|
||||
|
||||
#
|
||||
# Use the sched domain in debugfs to check isolated CPUs, if available
|
||||
@@ -736,7 +827,7 @@ check_isolcpus()
|
||||
done
|
||||
[[ "$ISOLCPUS" = *- ]] && ISOLCPUS=${ISOLCPUS}$LASTISOLCPU
|
||||
|
||||
[[ "$EXPECT_VAL" = "$ISOLCPUS" ]]
|
||||
[[ "$EXPECTED_SDOMAIN" = "$ISOLCPUS" ]]
|
||||
}
|
||||
|
||||
test_fail()
|
||||
@@ -773,6 +864,63 @@ null_isolcpus_check()
|
||||
exit 1
|
||||
}
|
||||
|
||||
#
|
||||
# Check state transition test result
|
||||
# $1 - Test number
|
||||
# $2 - Expected effective CPU values
|
||||
# $3 - Expected partition states
|
||||
# $4 - Expected isolated CPUs
|
||||
#
|
||||
check_test_results()
|
||||
{
|
||||
_NR=$1
|
||||
_ECPUS="$2"
|
||||
_PSTATES="$3"
|
||||
_ISOLCPUS="$4"
|
||||
|
||||
[[ -n "$_ECPUS" && "$_ECPUS" != . ]] && {
|
||||
check_effective_cpus $_ECPUS
|
||||
[[ $? -ne 0 ]] && test_fail $_NR "effective CPU" \
|
||||
"Cgroup $CGRP: expected $EXPECTED_CPUS, got $ACTUAL_CPUS"
|
||||
}
|
||||
|
||||
[[ -n "$_PSTATES" && "$_PSTATES" != . ]] && {
|
||||
check_cgroup_states $_PSTATES
|
||||
[[ $? -ne 0 ]] && test_fail $_NR states \
|
||||
"Cgroup $CGRP: expected $EXPECTED_STATE, got $ACTUAL_STATE"
|
||||
}
|
||||
|
||||
# Compare the expected isolated CPUs with the actual ones,
|
||||
# if available
|
||||
[[ -n "$_ISOLCPUS" ]] && {
|
||||
check_isolcpus $_ISOLCPUS
|
||||
[[ $? -ne 0 ]] && {
|
||||
[[ -n "$BOOT_ISOLCPUS" ]] && _ISOLCPUS=${_ISOLCPUS},${BOOT_ISOLCPUS}
|
||||
test_fail $_NR "isolated CPU" \
|
||||
"Expect $_ISOLCPUS, get $ISOLCPUS instead"
|
||||
}
|
||||
}
|
||||
reset_cgroup_states
|
||||
#
|
||||
# Check to see if effective cpu list changes
|
||||
#
|
||||
_NEWLIST=$(cat $CGROUP2/cpuset.cpus.effective)
|
||||
RETRY=0
|
||||
while [[ $_NEWLIST != $CPULIST && $RETRY -lt 8 ]]
|
||||
do
|
||||
# Wait a bit longer & recheck a few times
|
||||
pause 0.02
|
||||
((RETRY++))
|
||||
_NEWLIST=$(cat $CGROUP2/cpuset.cpus.effective)
|
||||
done
|
||||
[[ $_NEWLIST != $CPULIST ]] && {
|
||||
echo "Effective cpus changed to $_NEWLIST after test $_NR!"
|
||||
exit 1
|
||||
}
|
||||
null_isolcpus_check
|
||||
[[ $VERBOSE -gt 0 ]] && echo "Test $I done."
|
||||
}
|
||||
|
||||
#
|
||||
# Run cpuset state transition test
|
||||
# $1 - test matrix name
|
||||
@@ -785,6 +933,8 @@ run_state_test()
|
||||
{
|
||||
TEST=$1
|
||||
CONTROLLER=cpuset
|
||||
CGROUP_LIST=". A1 A1/A2 A1/A2/A3 B1"
|
||||
RESET_LIST="A1/A2/A3 A1/A2 A1 B1"
|
||||
I=0
|
||||
eval CNT="\${#$TEST[@]}"
|
||||
|
||||
@@ -812,10 +962,11 @@ run_state_test()
|
||||
STATES=${11}
|
||||
ICPUS=${12}
|
||||
|
||||
set_ctrl_state_noerr B1 $OLD_B1
|
||||
set_ctrl_state_noerr A1 $OLD_A1
|
||||
set_ctrl_state_noerr A1/A2 $OLD_A2
|
||||
set_ctrl_state_noerr A1/A2/A3 $OLD_A3
|
||||
set_ctrl_state_noerr B1 $OLD_B1
|
||||
|
||||
RETVAL=0
|
||||
set_ctrl_state A1 $NEW_A1; ((RETVAL += $?))
|
||||
set_ctrl_state A1/A2 $NEW_A2; ((RETVAL += $?))
|
||||
@@ -824,50 +975,82 @@ run_state_test()
|
||||
|
||||
[[ $RETVAL -ne $RESULT ]] && test_fail $I result
|
||||
|
||||
[[ -n "$ECPUS" && "$ECPUS" != . ]] && {
|
||||
check_effective_cpus $ECPUS
|
||||
[[ $? -ne 0 ]] && test_fail $I "effective CPU"
|
||||
}
|
||||
|
||||
[[ -n "$STATES" && "$STATES" != . ]] && {
|
||||
check_cgroup_states $STATES
|
||||
[[ $? -ne 0 ]] && test_fail $I states
|
||||
}
|
||||
|
||||
# Compare the expected isolated CPUs with the actual ones,
|
||||
# if available
|
||||
[[ -n "$ICPUS" ]] && {
|
||||
check_isolcpus $ICPUS
|
||||
[[ $? -ne 0 ]] && {
|
||||
[[ -n "$BOOT_ISOLCPUS" ]] && ICPUS=${ICPUS},${BOOT_ISOLCPUS}
|
||||
test_fail $I "isolated CPU" \
|
||||
"Expect $ICPUS, get $ISOLCPUS instead"
|
||||
}
|
||||
}
|
||||
reset_cgroup_states
|
||||
#
|
||||
# Check to see if effective cpu list changes
|
||||
#
|
||||
NEWLIST=$(cat cpuset.cpus.effective)
|
||||
RETRY=0
|
||||
while [[ $NEWLIST != $CPULIST && $RETRY -lt 8 ]]
|
||||
do
|
||||
# Wait a bit longer & recheck a few times
|
||||
pause 0.02
|
||||
((RETRY++))
|
||||
NEWLIST=$(cat cpuset.cpus.effective)
|
||||
done
|
||||
[[ $NEWLIST != $CPULIST ]] && {
|
||||
echo "Effective cpus changed to $NEWLIST after test $I!"
|
||||
exit 1
|
||||
}
|
||||
null_isolcpus_check
|
||||
[[ $VERBOSE -gt 0 ]] && echo "Test $I done."
|
||||
check_test_results $I "$ECPUS" "$STATES" "$ICPUS"
|
||||
((I++))
|
||||
done
|
||||
echo "All $I tests of $TEST PASSED."
|
||||
}
|
||||
|
||||
#
|
||||
# Run cpuset remote partition state transition test
|
||||
# $1 - test matrix name
|
||||
#
|
||||
run_remote_state_test()
|
||||
{
|
||||
TEST=$1
|
||||
CONTROLLER=cpuset
|
||||
[[ -d rtest ]] || mkdir rtest
|
||||
cd rtest
|
||||
echo +cpuset > cgroup.subtree_control
|
||||
echo "1-7" > cpuset.cpus
|
||||
echo "1-7" > cpuset.cpus.exclusive
|
||||
CGROUP_LIST=".. . p1 p2 p1/c11 p1/c12 p2/c21 p2/c22"
|
||||
RESET_LIST="p1/c11 p1/c12 p2/c21 p2/c22 p1 p2"
|
||||
I=0
|
||||
eval CNT="\${#$TEST[@]}"
|
||||
|
||||
reset_cgroup_states
|
||||
console_msg "Running remote partition state transition test ..."
|
||||
|
||||
while [[ $I -lt $CNT ]]
|
||||
do
|
||||
echo "Running test $I ..." > $CONSOLE
|
||||
[[ $VERBOSE -gt 1 ]] && {
|
||||
echo ""
|
||||
eval echo \${$TEST[$I]}
|
||||
}
|
||||
eval set -- "\${$TEST[$I]}"
|
||||
OLD_p1=$1
|
||||
OLD_p2=$2
|
||||
OLD_c11=$3
|
||||
OLD_c12=$4
|
||||
OLD_c21=$5
|
||||
OLD_c22=$6
|
||||
NEW_p1=$7
|
||||
NEW_p2=$8
|
||||
NEW_c11=$9
|
||||
NEW_c12=${10}
|
||||
NEW_c21=${11}
|
||||
NEW_c22=${12}
|
||||
ECPUS=${13}
|
||||
STATES=${14}
|
||||
ICPUS=${15}
|
||||
|
||||
set_ctrl_state_noerr p1 $OLD_p1
|
||||
set_ctrl_state_noerr p2 $OLD_p2
|
||||
set_ctrl_state_noerr p1/c11 $OLD_c11
|
||||
set_ctrl_state_noerr p1/c12 $OLD_c12
|
||||
set_ctrl_state_noerr p2/c21 $OLD_c21
|
||||
set_ctrl_state_noerr p2/c22 $OLD_c22
|
||||
|
||||
RETVAL=0
|
||||
set_ctrl_state p1 $NEW_p1 ; ((RETVAL += $?))
|
||||
set_ctrl_state p2 $NEW_p2 ; ((RETVAL += $?))
|
||||
set_ctrl_state p1/c11 $NEW_c11; ((RETVAL += $?))
|
||||
set_ctrl_state p1/c12 $NEW_c12; ((RETVAL += $?))
|
||||
set_ctrl_state p2/c21 $NEW_c21; ((RETVAL += $?))
|
||||
set_ctrl_state p2/c22 $NEW_c22; ((RETVAL += $?))
|
||||
|
||||
[[ $RETVAL -ne 0 ]] && test_fail $I result
|
||||
|
||||
check_test_results $I "$ECPUS" "$STATES" "$ICPUS"
|
||||
((I++))
|
||||
done
|
||||
cd ..
|
||||
rmdir rtest
|
||||
echo "All $I tests of $TEST PASSED."
|
||||
}
|
||||
|
||||
#
|
||||
# Testing the new "isolated" partition root type
|
||||
#
|
||||
@@ -932,6 +1115,7 @@ test_isolated()
|
||||
echo $$ > $CGROUP2/cgroup.procs
|
||||
[[ -d A1 ]] && rmdir A1
|
||||
null_isolcpus_check
|
||||
pause 0.05
|
||||
}
|
||||
|
||||
#
|
||||
@@ -997,10 +1181,13 @@ test_inotify()
|
||||
else
|
||||
echo "Inotify test PASSED"
|
||||
fi
|
||||
echo member > cpuset.cpus.partition
|
||||
echo "" > cpuset.cpus
|
||||
}
|
||||
|
||||
trap cleanup 0 2 3 6
|
||||
run_state_test TEST_MATRIX
|
||||
run_remote_state_test REMOTE_TEST_MATRIX
|
||||
test_isolated
|
||||
test_inotify
|
||||
echo "All tests PASSED."
|
||||
|
||||
Reference in New Issue
Block a user