diff options
Diffstat (limited to 'kernel/cpuset.c')
-rw-r--r-- | kernel/cpuset.c | 97 |
1 files changed, 77 insertions, 20 deletions
diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 00e8f2575512..984c0bf3807f 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c | |||
@@ -228,13 +228,7 @@ static struct dentry_operations cpuset_dops = { | |||
228 | 228 | ||
229 | static struct dentry *cpuset_get_dentry(struct dentry *parent, const char *name) | 229 | static struct dentry *cpuset_get_dentry(struct dentry *parent, const char *name) |
230 | { | 230 | { |
231 | struct qstr qstr; | 231 | struct dentry *d = lookup_one_len(name, parent, strlen(name)); |
232 | struct dentry *d; | ||
233 | |||
234 | qstr.name = name; | ||
235 | qstr.len = strlen(name); | ||
236 | qstr.hash = full_name_hash(name, qstr.len); | ||
237 | d = lookup_hash(&qstr, parent); | ||
238 | if (!IS_ERR(d)) | 232 | if (!IS_ERR(d)) |
239 | d->d_op = &cpuset_dops; | 233 | d->d_op = &cpuset_dops; |
240 | return d; | 234 | return d; |
@@ -601,10 +595,62 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial) | |||
601 | return 0; | 595 | return 0; |
602 | } | 596 | } |
603 | 597 | ||
598 | /* | ||
599 | * For a given cpuset cur, partition the system as follows | ||
600 | * a. All cpus in the parent cpuset's cpus_allowed that are not part of any | ||
601 | * exclusive child cpusets | ||
602 | * b. All cpus in the current cpuset's cpus_allowed that are not part of any | ||
603 | * exclusive child cpusets | ||
604 | * Build these two partitions by calling partition_sched_domains | ||
605 | * | ||
606 | * Call with cpuset_sem held. May nest a call to the | ||
607 | * lock_cpu_hotplug()/unlock_cpu_hotplug() pair. | ||
608 | */ | ||
609 | static void update_cpu_domains(struct cpuset *cur) | ||
610 | { | ||
611 | struct cpuset *c, *par = cur->parent; | ||
612 | cpumask_t pspan, cspan; | ||
613 | |||
614 | if (par == NULL || cpus_empty(cur->cpus_allowed)) | ||
615 | return; | ||
616 | |||
617 | /* | ||
618 | * Get all cpus from parent's cpus_allowed not part of exclusive | ||
619 | * children | ||
620 | */ | ||
621 | pspan = par->cpus_allowed; | ||
622 | list_for_each_entry(c, &par->children, sibling) { | ||
623 | if (is_cpu_exclusive(c)) | ||
624 | cpus_andnot(pspan, pspan, c->cpus_allowed); | ||
625 | } | ||
626 | if (is_removed(cur) || !is_cpu_exclusive(cur)) { | ||
627 | cpus_or(pspan, pspan, cur->cpus_allowed); | ||
628 | if (cpus_equal(pspan, cur->cpus_allowed)) | ||
629 | return; | ||
630 | cspan = CPU_MASK_NONE; | ||
631 | } else { | ||
632 | if (cpus_empty(pspan)) | ||
633 | return; | ||
634 | cspan = cur->cpus_allowed; | ||
635 | /* | ||
636 | * Get all cpus from current cpuset's cpus_allowed not part | ||
637 | * of exclusive children | ||
638 | */ | ||
639 | list_for_each_entry(c, &cur->children, sibling) { | ||
640 | if (is_cpu_exclusive(c)) | ||
641 | cpus_andnot(cspan, cspan, c->cpus_allowed); | ||
642 | } | ||
643 | } | ||
644 | |||
645 | lock_cpu_hotplug(); | ||
646 | partition_sched_domains(&pspan, &cspan); | ||
647 | unlock_cpu_hotplug(); | ||
648 | } | ||
649 | |||
604 | static int update_cpumask(struct cpuset *cs, char *buf) | 650 | static int update_cpumask(struct cpuset *cs, char *buf) |
605 | { | 651 | { |
606 | struct cpuset trialcs; | 652 | struct cpuset trialcs; |
607 | int retval; | 653 | int retval, cpus_unchanged; |
608 | 654 | ||
609 | trialcs = *cs; | 655 | trialcs = *cs; |
610 | retval = cpulist_parse(buf, trialcs.cpus_allowed); | 656 | retval = cpulist_parse(buf, trialcs.cpus_allowed); |
@@ -614,9 +660,13 @@ static int update_cpumask(struct cpuset *cs, char *buf) | |||
614 | if (cpus_empty(trialcs.cpus_allowed)) | 660 | if (cpus_empty(trialcs.cpus_allowed)) |
615 | return -ENOSPC; | 661 | return -ENOSPC; |
616 | retval = validate_change(cs, &trialcs); | 662 | retval = validate_change(cs, &trialcs); |
617 | if (retval == 0) | 663 | if (retval < 0) |
618 | cs->cpus_allowed = trialcs.cpus_allowed; | 664 | return retval; |
619 | return retval; | 665 | cpus_unchanged = cpus_equal(cs->cpus_allowed, trialcs.cpus_allowed); |
666 | cs->cpus_allowed = trialcs.cpus_allowed; | ||
667 | if (is_cpu_exclusive(cs) && !cpus_unchanged) | ||
668 | update_cpu_domains(cs); | ||
669 | return 0; | ||
620 | } | 670 | } |
621 | 671 | ||
622 | static int update_nodemask(struct cpuset *cs, char *buf) | 672 | static int update_nodemask(struct cpuset *cs, char *buf) |
@@ -652,7 +702,7 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, char *buf) | |||
652 | { | 702 | { |
653 | int turning_on; | 703 | int turning_on; |
654 | struct cpuset trialcs; | 704 | struct cpuset trialcs; |
655 | int err; | 705 | int err, cpu_exclusive_changed; |
656 | 706 | ||
657 | turning_on = (simple_strtoul(buf, NULL, 10) != 0); | 707 | turning_on = (simple_strtoul(buf, NULL, 10) != 0); |
658 | 708 | ||
@@ -663,13 +713,18 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, char *buf) | |||
663 | clear_bit(bit, &trialcs.flags); | 713 | clear_bit(bit, &trialcs.flags); |
664 | 714 | ||
665 | err = validate_change(cs, &trialcs); | 715 | err = validate_change(cs, &trialcs); |
666 | if (err == 0) { | 716 | if (err < 0) |
667 | if (turning_on) | 717 | return err; |
668 | set_bit(bit, &cs->flags); | 718 | cpu_exclusive_changed = |
669 | else | 719 | (is_cpu_exclusive(cs) != is_cpu_exclusive(&trialcs)); |
670 | clear_bit(bit, &cs->flags); | 720 | if (turning_on) |
671 | } | 721 | set_bit(bit, &cs->flags); |
672 | return err; | 722 | else |
723 | clear_bit(bit, &cs->flags); | ||
724 | |||
725 | if (cpu_exclusive_changed) | ||
726 | update_cpu_domains(cs); | ||
727 | return 0; | ||
673 | } | 728 | } |
674 | 729 | ||
675 | static int attach_task(struct cpuset *cs, char *buf) | 730 | static int attach_task(struct cpuset *cs, char *buf) |
@@ -1315,12 +1370,14 @@ static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry) | |||
1315 | up(&cpuset_sem); | 1370 | up(&cpuset_sem); |
1316 | return -EBUSY; | 1371 | return -EBUSY; |
1317 | } | 1372 | } |
1318 | spin_lock(&cs->dentry->d_lock); | ||
1319 | parent = cs->parent; | 1373 | parent = cs->parent; |
1320 | set_bit(CS_REMOVED, &cs->flags); | 1374 | set_bit(CS_REMOVED, &cs->flags); |
1375 | if (is_cpu_exclusive(cs)) | ||
1376 | update_cpu_domains(cs); | ||
1321 | list_del(&cs->sibling); /* delete my sibling from parent->children */ | 1377 | list_del(&cs->sibling); /* delete my sibling from parent->children */ |
1322 | if (list_empty(&parent->children)) | 1378 | if (list_empty(&parent->children)) |
1323 | check_for_release(parent); | 1379 | check_for_release(parent); |
1380 | spin_lock(&cs->dentry->d_lock); | ||
1324 | d = dget(cs->dentry); | 1381 | d = dget(cs->dentry); |
1325 | cs->dentry = NULL; | 1382 | cs->dentry = NULL; |
1326 | spin_unlock(&d->d_lock); | 1383 | spin_unlock(&d->d_lock); |