diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/cpuset.c | 89 |
1 files changed, 76 insertions, 13 deletions
diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 79dd929f4084..984c0bf3807f 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c | |||
@@ -595,10 +595,62 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial) | |||
595 | return 0; | 595 | return 0; |
596 | } | 596 | } |
597 | 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 | |||
598 | static int update_cpumask(struct cpuset *cs, char *buf) | 650 | static int update_cpumask(struct cpuset *cs, char *buf) |
599 | { | 651 | { |
600 | struct cpuset trialcs; | 652 | struct cpuset trialcs; |
601 | int retval; | 653 | int retval, cpus_unchanged; |
602 | 654 | ||
603 | trialcs = *cs; | 655 | trialcs = *cs; |
604 | retval = cpulist_parse(buf, trialcs.cpus_allowed); | 656 | retval = cpulist_parse(buf, trialcs.cpus_allowed); |
@@ -608,9 +660,13 @@ static int update_cpumask(struct cpuset *cs, char *buf) | |||
608 | if (cpus_empty(trialcs.cpus_allowed)) | 660 | if (cpus_empty(trialcs.cpus_allowed)) |
609 | return -ENOSPC; | 661 | return -ENOSPC; |
610 | retval = validate_change(cs, &trialcs); | 662 | retval = validate_change(cs, &trialcs); |
611 | if (retval == 0) | 663 | if (retval < 0) |
612 | cs->cpus_allowed = trialcs.cpus_allowed; | 664 | return retval; |
613 | 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; | ||
614 | } | 670 | } |
615 | 671 | ||
616 | static int update_nodemask(struct cpuset *cs, char *buf) | 672 | 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) | |||
646 | { | 702 | { |
647 | int turning_on; | 703 | int turning_on; |
648 | struct cpuset trialcs; | 704 | struct cpuset trialcs; |
649 | int err; | 705 | int err, cpu_exclusive_changed; |
650 | 706 | ||
651 | turning_on = (simple_strtoul(buf, NULL, 10) != 0); | 707 | turning_on = (simple_strtoul(buf, NULL, 10) != 0); |
652 | 708 | ||
@@ -657,13 +713,18 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, char *buf) | |||
657 | clear_bit(bit, &trialcs.flags); | 713 | clear_bit(bit, &trialcs.flags); |
658 | 714 | ||
659 | err = validate_change(cs, &trialcs); | 715 | err = validate_change(cs, &trialcs); |
660 | if (err == 0) { | 716 | if (err < 0) |
661 | if (turning_on) | 717 | return err; |
662 | set_bit(bit, &cs->flags); | 718 | cpu_exclusive_changed = |
663 | else | 719 | (is_cpu_exclusive(cs) != is_cpu_exclusive(&trialcs)); |
664 | clear_bit(bit, &cs->flags); | 720 | if (turning_on) |
665 | } | 721 | set_bit(bit, &cs->flags); |
666 | return err; | 722 | else |
723 | clear_bit(bit, &cs->flags); | ||
724 | |||
725 | if (cpu_exclusive_changed) | ||
726 | update_cpu_domains(cs); | ||
727 | return 0; | ||
667 | } | 728 | } |
668 | 729 | ||
669 | static int attach_task(struct cpuset *cs, char *buf) | 730 | static int attach_task(struct cpuset *cs, char *buf) |
@@ -1309,12 +1370,14 @@ static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry) | |||
1309 | up(&cpuset_sem); | 1370 | up(&cpuset_sem); |
1310 | return -EBUSY; | 1371 | return -EBUSY; |
1311 | } | 1372 | } |
1312 | spin_lock(&cs->dentry->d_lock); | ||
1313 | parent = cs->parent; | 1373 | parent = cs->parent; |
1314 | set_bit(CS_REMOVED, &cs->flags); | 1374 | set_bit(CS_REMOVED, &cs->flags); |
1375 | if (is_cpu_exclusive(cs)) | ||
1376 | update_cpu_domains(cs); | ||
1315 | list_del(&cs->sibling); /* delete my sibling from parent->children */ | 1377 | list_del(&cs->sibling); /* delete my sibling from parent->children */ |
1316 | if (list_empty(&parent->children)) | 1378 | if (list_empty(&parent->children)) |
1317 | check_for_release(parent); | 1379 | check_for_release(parent); |
1380 | spin_lock(&cs->dentry->d_lock); | ||
1318 | d = dget(cs->dentry); | 1381 | d = dget(cs->dentry); |
1319 | cs->dentry = NULL; | 1382 | cs->dentry = NULL; |
1320 | spin_unlock(&d->d_lock); | 1383 | spin_unlock(&d->d_lock); |