diff options
| author | Ingo Molnar <mingo@elte.hu> | 2009-04-05 19:41:22 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2009-04-05 19:41:22 -0400 |
| commit | 9efe21cb82b5dbe3b0b2ae4de4eccc64ecb94e95 (patch) | |
| tree | 7ff8833745d2f268f897f6fa4a27263b4a572245 /kernel/cpuset.c | |
| parent | de18836e447c2dc30120c0919b8db8ddc0401cc4 (diff) | |
| parent | 0221c81b1b8eb0cbb6b30a0ced52ead32d2b4e4c (diff) | |
Merge branch 'linus' into irq/threaded
Conflicts:
include/linux/irq.h
kernel/irq/handle.c
Diffstat (limited to 'kernel/cpuset.c')
| -rw-r--r-- | kernel/cpuset.c | 254 |
1 files changed, 119 insertions, 135 deletions
diff --git a/kernel/cpuset.c b/kernel/cpuset.c index f76db9dcaa0..026faccca86 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c | |||
| @@ -128,10 +128,6 @@ static inline struct cpuset *task_cs(struct task_struct *task) | |||
| 128 | return container_of(task_subsys_state(task, cpuset_subsys_id), | 128 | return container_of(task_subsys_state(task, cpuset_subsys_id), |
| 129 | struct cpuset, css); | 129 | struct cpuset, css); |
| 130 | } | 130 | } |
| 131 | struct cpuset_hotplug_scanner { | ||
| 132 | struct cgroup_scanner scan; | ||
| 133 | struct cgroup *to; | ||
| 134 | }; | ||
| 135 | 131 | ||
| 136 | /* bits in struct cpuset flags field */ | 132 | /* bits in struct cpuset flags field */ |
| 137 | typedef enum { | 133 | typedef enum { |
| @@ -521,6 +517,7 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial) | |||
| 521 | return 0; | 517 | return 0; |
| 522 | } | 518 | } |
| 523 | 519 | ||
| 520 | #ifdef CONFIG_SMP | ||
| 524 | /* | 521 | /* |
| 525 | * Helper routine for generate_sched_domains(). | 522 | * Helper routine for generate_sched_domains(). |
| 526 | * Do cpusets a, b have overlapping cpus_allowed masks? | 523 | * Do cpusets a, b have overlapping cpus_allowed masks? |
| @@ -815,6 +812,18 @@ static void do_rebuild_sched_domains(struct work_struct *unused) | |||
| 815 | 812 | ||
| 816 | put_online_cpus(); | 813 | put_online_cpus(); |
| 817 | } | 814 | } |
| 815 | #else /* !CONFIG_SMP */ | ||
| 816 | static void do_rebuild_sched_domains(struct work_struct *unused) | ||
| 817 | { | ||
| 818 | } | ||
| 819 | |||
| 820 | static int generate_sched_domains(struct cpumask **domains, | ||
| 821 | struct sched_domain_attr **attributes) | ||
| 822 | { | ||
| 823 | *domains = NULL; | ||
| 824 | return 1; | ||
| 825 | } | ||
| 826 | #endif /* CONFIG_SMP */ | ||
| 818 | 827 | ||
| 819 | static DECLARE_WORK(rebuild_sched_domains_work, do_rebuild_sched_domains); | 828 | static DECLARE_WORK(rebuild_sched_domains_work, do_rebuild_sched_domains); |
| 820 | 829 | ||
| @@ -1026,101 +1035,70 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from, | |||
| 1026 | mutex_unlock(&callback_mutex); | 1035 | mutex_unlock(&callback_mutex); |
| 1027 | } | 1036 | } |
| 1028 | 1037 | ||
| 1038 | /* | ||
| 1039 | * Rebind task's vmas to cpuset's new mems_allowed, and migrate pages to new | ||
| 1040 | * nodes if memory_migrate flag is set. Called with cgroup_mutex held. | ||
| 1041 | */ | ||
| 1042 | static void cpuset_change_nodemask(struct task_struct *p, | ||
| 1043 | struct cgroup_scanner *scan) | ||
| 1044 | { | ||
| 1045 | struct mm_struct *mm; | ||
| 1046 | struct cpuset *cs; | ||
| 1047 | int migrate; | ||
| 1048 | const nodemask_t *oldmem = scan->data; | ||
| 1049 | |||
| 1050 | mm = get_task_mm(p); | ||
| 1051 | if (!mm) | ||
| 1052 | return; | ||
| 1053 | |||
| 1054 | cs = cgroup_cs(scan->cg); | ||
| 1055 | migrate = is_memory_migrate(cs); | ||
| 1056 | |||
| 1057 | mpol_rebind_mm(mm, &cs->mems_allowed); | ||
| 1058 | if (migrate) | ||
| 1059 | cpuset_migrate_mm(mm, oldmem, &cs->mems_allowed); | ||
| 1060 | mmput(mm); | ||
| 1061 | } | ||
| 1062 | |||
| 1029 | static void *cpuset_being_rebound; | 1063 | static void *cpuset_being_rebound; |
| 1030 | 1064 | ||
| 1031 | /** | 1065 | /** |
| 1032 | * update_tasks_nodemask - Update the nodemasks of tasks in the cpuset. | 1066 | * update_tasks_nodemask - Update the nodemasks of tasks in the cpuset. |
| 1033 | * @cs: the cpuset in which each task's mems_allowed mask needs to be changed | 1067 | * @cs: the cpuset in which each task's mems_allowed mask needs to be changed |
| 1034 | * @oldmem: old mems_allowed of cpuset cs | 1068 | * @oldmem: old mems_allowed of cpuset cs |
| 1069 | * @heap: if NULL, defer allocating heap memory to cgroup_scan_tasks() | ||
| 1035 | * | 1070 | * |
| 1036 | * Called with cgroup_mutex held | 1071 | * Called with cgroup_mutex held |
| 1037 | * Return 0 if successful, -errno if not. | 1072 | * No return value. It's guaranteed that cgroup_scan_tasks() always returns 0 |
| 1073 | * if @heap != NULL. | ||
| 1038 | */ | 1074 | */ |
| 1039 | static int update_tasks_nodemask(struct cpuset *cs, const nodemask_t *oldmem) | 1075 | static void update_tasks_nodemask(struct cpuset *cs, const nodemask_t *oldmem, |
| 1076 | struct ptr_heap *heap) | ||
| 1040 | { | 1077 | { |
| 1041 | struct task_struct *p; | 1078 | struct cgroup_scanner scan; |
| 1042 | struct mm_struct **mmarray; | ||
| 1043 | int i, n, ntasks; | ||
| 1044 | int migrate; | ||
| 1045 | int fudge; | ||
| 1046 | struct cgroup_iter it; | ||
| 1047 | int retval; | ||
| 1048 | 1079 | ||
| 1049 | cpuset_being_rebound = cs; /* causes mpol_dup() rebind */ | 1080 | cpuset_being_rebound = cs; /* causes mpol_dup() rebind */ |
| 1050 | 1081 | ||
| 1051 | fudge = 10; /* spare mmarray[] slots */ | 1082 | scan.cg = cs->css.cgroup; |
| 1052 | fudge += cpumask_weight(cs->cpus_allowed);/* imagine 1 fork-bomb/cpu */ | 1083 | scan.test_task = NULL; |
| 1053 | retval = -ENOMEM; | 1084 | scan.process_task = cpuset_change_nodemask; |
| 1054 | 1085 | scan.heap = heap; | |
| 1055 | /* | 1086 | scan.data = (nodemask_t *)oldmem; |
| 1056 | * Allocate mmarray[] to hold mm reference for each task | ||
| 1057 | * in cpuset cs. Can't kmalloc GFP_KERNEL while holding | ||
| 1058 | * tasklist_lock. We could use GFP_ATOMIC, but with a | ||
| 1059 | * few more lines of code, we can retry until we get a big | ||
| 1060 | * enough mmarray[] w/o using GFP_ATOMIC. | ||
| 1061 | */ | ||
| 1062 | while (1) { | ||
| 1063 | ntasks = cgroup_task_count(cs->css.cgroup); /* guess */ | ||
| 1064 | ntasks += fudge; | ||
| 1065 | mmarray = kmalloc(ntasks * sizeof(*mmarray), GFP_KERNEL); | ||
| 1066 | if (!mmarray) | ||
| 1067 | goto done; | ||
| 1068 | read_lock(&tasklist_lock); /* block fork */ | ||
| 1069 | if (cgroup_task_count(cs->css.cgroup) <= ntasks) | ||
| 1070 | break; /* got enough */ | ||
| 1071 | read_unlock(&tasklist_lock); /* try again */ | ||
| 1072 | kfree(mmarray); | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | n = 0; | ||
| 1076 | |||
| 1077 | /* Load up mmarray[] with mm reference for each task in cpuset. */ | ||
| 1078 | cgroup_iter_start(cs->css.cgroup, &it); | ||
| 1079 | while ((p = cgroup_iter_next(cs->css.cgroup, &it))) { | ||
| 1080 | struct mm_struct *mm; | ||
| 1081 | |||
| 1082 | if (n >= ntasks) { | ||
| 1083 | printk(KERN_WARNING | ||
| 1084 | "Cpuset mempolicy rebind incomplete.\n"); | ||
| 1085 | break; | ||
| 1086 | } | ||
| 1087 | mm = get_task_mm(p); | ||
| 1088 | if (!mm) | ||
| 1089 | continue; | ||
| 1090 | mmarray[n++] = mm; | ||
| 1091 | } | ||
| 1092 | cgroup_iter_end(cs->css.cgroup, &it); | ||
| 1093 | read_unlock(&tasklist_lock); | ||
| 1094 | 1087 | ||
| 1095 | /* | 1088 | /* |
| 1096 | * Now that we've dropped the tasklist spinlock, we can | 1089 | * The mpol_rebind_mm() call takes mmap_sem, which we couldn't |
| 1097 | * rebind the vma mempolicies of each mm in mmarray[] to their | 1090 | * take while holding tasklist_lock. Forks can happen - the |
| 1098 | * new cpuset, and release that mm. The mpol_rebind_mm() | 1091 | * mpol_dup() cpuset_being_rebound check will catch such forks, |
| 1099 | * call takes mmap_sem, which we couldn't take while holding | 1092 | * and rebind their vma mempolicies too. Because we still hold |
| 1100 | * tasklist_lock. Forks can happen again now - the mpol_dup() | 1093 | * the global cgroup_mutex, we know that no other rebind effort |
| 1101 | * cpuset_being_rebound check will catch such forks, and rebind | 1094 | * will be contending for the global variable cpuset_being_rebound. |
| 1102 | * their vma mempolicies too. Because we still hold the global | ||
| 1103 | * cgroup_mutex, we know that no other rebind effort will | ||
| 1104 | * be contending for the global variable cpuset_being_rebound. | ||
| 1105 | * It's ok if we rebind the same mm twice; mpol_rebind_mm() | 1095 | * It's ok if we rebind the same mm twice; mpol_rebind_mm() |
| 1106 | * is idempotent. Also migrate pages in each mm to new nodes. | 1096 | * is idempotent. Also migrate pages in each mm to new nodes. |
| 1107 | */ | 1097 | */ |
| 1108 | migrate = is_memory_migrate(cs); | 1098 | cgroup_scan_tasks(&scan); |
| 1109 | for (i = 0; i < n; i++) { | ||
| 1110 | struct mm_struct *mm = mmarray[i]; | ||
| 1111 | |||
| 1112 | mpol_rebind_mm(mm, &cs->mems_allowed); | ||
| 1113 | if (migrate) | ||
| 1114 | cpuset_migrate_mm(mm, oldmem, &cs->mems_allowed); | ||
| 1115 | mmput(mm); | ||
| 1116 | } | ||
| 1117 | 1099 | ||
| 1118 | /* We're done rebinding vmas to this cpuset's new mems_allowed. */ | 1100 | /* We're done rebinding vmas to this cpuset's new mems_allowed. */ |
| 1119 | kfree(mmarray); | ||
| 1120 | cpuset_being_rebound = NULL; | 1101 | cpuset_being_rebound = NULL; |
| 1121 | retval = 0; | ||
| 1122 | done: | ||
| 1123 | return retval; | ||
| 1124 | } | 1102 | } |
| 1125 | 1103 | ||
| 1126 | /* | 1104 | /* |
| @@ -1141,6 +1119,7 @@ static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs, | |||
| 1141 | { | 1119 | { |
| 1142 | nodemask_t oldmem; | 1120 | nodemask_t oldmem; |
| 1143 | int retval; | 1121 | int retval; |
| 1122 | struct ptr_heap heap; | ||
| 1144 | 1123 | ||
| 1145 | /* | 1124 | /* |
| 1146 | * top_cpuset.mems_allowed tracks node_stats[N_HIGH_MEMORY]; | 1125 | * top_cpuset.mems_allowed tracks node_stats[N_HIGH_MEMORY]; |
| @@ -1175,12 +1154,18 @@ static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs, | |||
| 1175 | |||
