|
@@ -595,10 +595,62 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * For a given cpuset cur, partition the system as follows
|
|
|
+ * a. All cpus in the parent cpuset's cpus_allowed that are not part of any
|
|
|
+ * exclusive child cpusets
|
|
|
+ * b. All cpus in the current cpuset's cpus_allowed that are not part of any
|
|
|
+ * exclusive child cpusets
|
|
|
+ * Build these two partitions by calling partition_sched_domains
|
|
|
+ *
|
|
|
+ * Call with cpuset_sem held. May nest a call to the
|
|
|
+ * lock_cpu_hotplug()/unlock_cpu_hotplug() pair.
|
|
|
+ */
|
|
|
+static void update_cpu_domains(struct cpuset *cur)
|
|
|
+{
|
|
|
+ struct cpuset *c, *par = cur->parent;
|
|
|
+ cpumask_t pspan, cspan;
|
|
|
+
|
|
|
+ if (par == NULL || cpus_empty(cur->cpus_allowed))
|
|
|
+ return;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Get all cpus from parent's cpus_allowed not part of exclusive
|
|
|
+ * children
|
|
|
+ */
|
|
|
+ pspan = par->cpus_allowed;
|
|
|
+ list_for_each_entry(c, &par->children, sibling) {
|
|
|
+ if (is_cpu_exclusive(c))
|
|
|
+ cpus_andnot(pspan, pspan, c->cpus_allowed);
|
|
|
+ }
|
|
|
+ if (is_removed(cur) || !is_cpu_exclusive(cur)) {
|
|
|
+ cpus_or(pspan, pspan, cur->cpus_allowed);
|
|
|
+ if (cpus_equal(pspan, cur->cpus_allowed))
|
|
|
+ return;
|
|
|
+ cspan = CPU_MASK_NONE;
|
|
|
+ } else {
|
|
|
+ if (cpus_empty(pspan))
|
|
|
+ return;
|
|
|
+ cspan = cur->cpus_allowed;
|
|
|
+ /*
|
|
|
+ * Get all cpus from current cpuset's cpus_allowed not part
|
|
|
+ * of exclusive children
|
|
|
+ */
|
|
|
+ list_for_each_entry(c, &cur->children, sibling) {
|
|
|
+ if (is_cpu_exclusive(c))
|
|
|
+ cpus_andnot(cspan, cspan, c->cpus_allowed);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ lock_cpu_hotplug();
|
|
|
+ partition_sched_domains(&pspan, &cspan);
|
|
|
+ unlock_cpu_hotplug();
|
|
|
+}
|
|
|
+
|
|
|
static int update_cpumask(struct cpuset *cs, char *buf)
|
|
|
{
|
|
|
struct cpuset trialcs;
|
|
|
- int retval;
|
|
|
+ int retval, cpus_unchanged;
|
|
|
|
|
|
trialcs = *cs;
|
|
|
retval = cpulist_parse(buf, trialcs.cpus_allowed);
|
|
@@ -608,9 +660,13 @@ static int update_cpumask(struct cpuset *cs, char *buf)
|
|
|
if (cpus_empty(trialcs.cpus_allowed))
|
|
|
return -ENOSPC;
|
|
|
retval = validate_change(cs, &trialcs);
|
|
|
- if (retval == 0)
|
|
|
- cs->cpus_allowed = trialcs.cpus_allowed;
|
|
|
- return retval;
|
|
|
+ if (retval < 0)
|
|
|
+ return retval;
|
|
|
+ cpus_unchanged = cpus_equal(cs->cpus_allowed, trialcs.cpus_allowed);
|
|
|
+ cs->cpus_allowed = trialcs.cpus_allowed;
|
|
|
+ if (is_cpu_exclusive(cs) && !cpus_unchanged)
|
|
|
+ update_cpu_domains(cs);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
static int update_nodemask(struct cpuset *cs, char *buf)
|
|
@@ -646,7 +702,7 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, char *buf)
|
|
|
{
|
|
|
int turning_on;
|
|
|
struct cpuset trialcs;
|
|
|
- int err;
|
|
|
+ int err, cpu_exclusive_changed;
|
|
|
|
|
|
turning_on = (simple_strtoul(buf, NULL, 10) != 0);
|
|
|
|
|
@@ -657,13 +713,18 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, char *buf)
|
|
|
clear_bit(bit, &trialcs.flags);
|
|
|
|
|
|
err = validate_change(cs, &trialcs);
|
|
|
- if (err == 0) {
|
|
|
- if (turning_on)
|
|
|
- set_bit(bit, &cs->flags);
|
|
|
- else
|
|
|
- clear_bit(bit, &cs->flags);
|
|
|
- }
|
|
|
- return err;
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+ cpu_exclusive_changed =
|
|
|
+ (is_cpu_exclusive(cs) != is_cpu_exclusive(&trialcs));
|
|
|
+ if (turning_on)
|
|
|
+ set_bit(bit, &cs->flags);
|
|
|
+ else
|
|
|
+ clear_bit(bit, &cs->flags);
|
|
|
+
|
|
|
+ if (cpu_exclusive_changed)
|
|
|
+ update_cpu_domains(cs);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
static int attach_task(struct cpuset *cs, char *buf)
|
|
@@ -1309,12 +1370,14 @@ static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry)
|
|
|
up(&cpuset_sem);
|
|
|
return -EBUSY;
|
|
|
}
|
|
|
- spin_lock(&cs->dentry->d_lock);
|
|
|
parent = cs->parent;
|
|
|
set_bit(CS_REMOVED, &cs->flags);
|
|
|
+ if (is_cpu_exclusive(cs))
|
|
|
+ update_cpu_domains(cs);
|
|
|
list_del(&cs->sibling); /* delete my sibling from parent->children */
|
|
|
if (list_empty(&parent->children))
|
|
|
check_for_release(parent);
|
|
|
+ spin_lock(&cs->dentry->d_lock);
|
|
|
d = dget(cs->dentry);
|
|
|
cs->dentry = NULL;
|
|
|
spin_unlock(&d->d_lock);
|