diff options
| author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2010-11-13 13:32:29 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2010-11-18 07:27:46 -0500 |
| commit | 48c5ccae88dcd989d9de507e8510313c6cbd352b (patch) | |
| tree | 06fe8ce2ac28e9f5844de8bc32ecbef97e40d68b | |
| parent | 92fd4d4d67b945c0766416284d4ab236b31542c4 (diff) | |
sched: Simplify cpu-hot-unplug task migration
While discussing the need for sched_idle_next(), Oleg remarked that
since try_to_wake_up() ensures sleeping tasks will end up running on a
sane cpu, we can do away with migrate_live_tasks().
If we then extend the existing hack of migrating current from
CPU_DYING to migrating the full rq worth of tasks from CPU_DYING, the
need for the sched_idle_next() abomination disappears as well, since
idle will be the only possible thread left after the migration thread
stops.
This greatly simplifies the hot-unplug task migration path, as can be
seen from the resulting code reduction (and about half the new lines
are comments).
Suggested-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <1289851597.2109.547.camel@laptop>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
| -rw-r--r-- | include/linux/sched.h | 3 | ||||
| -rw-r--r-- | kernel/cpu.c | 16 | ||||
| -rw-r--r-- | kernel/sched.c | 206 |
3 files changed, 67 insertions, 158 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h index 3cd70cf91fde..29d953abb5ad 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
| @@ -1871,14 +1871,11 @@ extern void sched_clock_idle_sleep_event(void); | |||
| 1871 | extern void sched_clock_idle_wakeup_event(u64 delta_ns); | 1871 | extern void sched_clock_idle_wakeup_event(u64 delta_ns); |
| 1872 | 1872 | ||
| 1873 | #ifdef CONFIG_HOTPLUG_CPU | 1873 | #ifdef CONFIG_HOTPLUG_CPU |
| 1874 | extern void move_task_off_dead_cpu(int dead_cpu, struct task_struct *p); | ||
| 1875 | extern void idle_task_exit(void); | 1874 | extern void idle_task_exit(void); |
| 1876 | #else | 1875 | #else |
| 1877 | static inline void idle_task_exit(void) {} | 1876 | static inline void idle_task_exit(void) {} |
| 1878 | #endif | 1877 | #endif |
| 1879 | 1878 | ||
| 1880 | extern void sched_idle_next(void); | ||
| 1881 | |||
| 1882 | #if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP) | 1879 | #if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP) |
| 1883 | extern void wake_up_idle_cpu(int cpu); | 1880 | extern void wake_up_idle_cpu(int cpu); |
| 1884 | #else | 1881 | #else |
diff --git a/kernel/cpu.c b/kernel/cpu.c index f6e726f18491..8615aa65d927 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
| @@ -189,7 +189,6 @@ static inline void check_for_tasks(int cpu) | |||
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | struct take_cpu_down_param { | 191 | struct take_cpu_down_param { |
| 192 | struct task_struct *caller; | ||
| 193 | unsigned long mod; | 192 | unsigned long mod; |
| 194 | void *hcpu; | 193 | void *hcpu; |
| 195 | }; | 194 | }; |
| @@ -208,11 +207,6 @@ static int __ref take_cpu_down(void *_param) | |||
| 208 | 207 | ||
| 209 | cpu_notify(CPU_DYING | param->mod, param->hcpu); | 208 | cpu_notify(CPU_DYING | param->mod, param->hcpu); |
| 210 | 209 | ||
| 211 | if (task_cpu(param->caller) == cpu) | ||
| 212 | move_task_off_dead_cpu(cpu, param->caller); | ||
| 213 | /* Force idle task to run as soon as we yield: it should | ||
| 214 | immediately notice cpu is offline and die quickly. */ | ||
| 215 | sched_idle_next(); | ||
| 216 | return 0; | 210 | return 0; |
| 217 | } | 211 | } |
| 218 | 212 | ||
| @@ -223,7 +217,6 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen) | |||
| 223 | void *hcpu = (void *)(long)cpu; | 217 | void *hcpu = (void *)(long)cpu; |
| 224 | unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0; | 218 | unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0; |
| 225 | struct take_cpu_down_param tcd_param = { | 219 | struct take_cpu_down_param tcd_param = { |
| 226 | .caller = current, | ||
| 227 | .mod = mod, | 220 | .mod = mod, |
| 228 | .hcpu = hcpu, | 221 | .hcpu = hcpu, |
| 229 | }; | 222 | }; |
| @@ -253,9 +246,12 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen) | |||
| 253 | } | 246 | } |
| 254 | BUG_ON(cpu_online(cpu)); | 247 | BUG_ON(cpu_online(cpu)); |
| 255 | 248 | ||
| 256 | /* Wait for it to sleep (leaving idle task). */ | 249 | /* |
| 257 | while (!idle_cpu(cpu)) | 250 | * The migration_call() CPU_DYING callback will have removed all |
| 258 | yield(); | 251 | * runnable tasks from the cpu, there's only the idle task left now |
| 252 | * that the migration thread is done doing the stop_machine thing. | ||
| 253 | */ | ||
| 254 | BUG_ON(!idle_cpu(cpu)); | ||
| 259 | 255 | ||
| 260 | /* This actually kills the CPU. */ | 256 | /* This actually kills the CPU. */ |
| 261 | __cpu_die(cpu); | 257 | __cpu_die(cpu); |
diff --git a/kernel/sched.c b/kernel/sched.c index 41f18695b730..b0d5f1b24a39 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
| @@ -2366,18 +2366,15 @@ static int select_fallback_rq(int cpu, struct task_struct *p) | |||
| 2366 | return dest_cpu; | 2366 | return dest_cpu; |
| 2367 | 2367 | ||
| 2368 | /* No more Mr. Nice Guy. */ | 2368 | /* No more Mr. Nice Guy. */ |
| 2369 | if (unlikely(dest_cpu >= nr_cpu_ids)) { | 2369 | dest_cpu = cpuset_cpus_allowed_fallback(p); |
| 2370 | dest_cpu = cpuset_cpus_allowed_fallback(p); | 2370 | /* |
| 2371 | /* | 2371 | * Don't tell them about moving exiting tasks or |
| 2372 | * Don't tell them about moving exiting tasks or | 2372 | * kernel threads (both mm NULL), since they never |
| 2373 | * kernel threads (both mm NULL), since they never | 2373 | * leave kernel. |
| 2374 | * leave kernel. | 2374 | */ |
| 2375 | */ | 2375 | if (p->mm && printk_ratelimit()) { |
| 2376 | if (p->mm && printk_ratelimit()) { | 2376 | printk(KERN_INFO "process %d (%s) no longer affine to cpu%d\n", |
| 2377 | printk(KERN_INFO "process %d (%s) no " | 2377 | task_pid_nr(p), p->comm, cpu); |
| 2378 | "longer affine to cpu%d\n", | ||
| 2379 | task_pid_nr(p), p->comm, cpu); | ||
| 2380 | } | ||
| 2381 | } | 2378 | } |
| 2382 | 2379 | ||
| 2383 | return dest_cpu; | 2380 | return dest_cpu; |
| @@ -5712,29 +5709,20 @@ static int migration_cpu_stop(void *data) | |||
| 5712 | } | 5709 | } |
| 5713 | 5710 | ||
| 5714 | #ifdef CONFIG_HOTPLUG_CPU | 5711 | #ifdef CONFIG_HOTPLUG_CPU |
| 5712 | |||
| 5715 | /* | 5713 | /* |
| 5716 | * Figure out where task on dead CPU should go, use force if necessary. | 5714 | * Ensures that the idle task is using init_mm right before its cpu goes |
| 5715 | * offline. | ||
| 5717 | */ | 5716 | */ |
| 5718 | void move_task_off_dead_cpu(int dead_cpu, struct task_struct *p) | 5717 | void idle_task_exit(void) |
| 5719 | { | 5718 | { |
| 5720 | struct rq *rq = cpu_rq(dead_cpu); | 5719 | struct mm_struct *mm = current->active_mm; |
| 5721 | int needs_cpu, uninitialized_var(dest_cpu); | ||
| 5722 | unsigned long flags; | ||
| 5723 | 5720 | ||
| 5724 | local_irq_save(flags); | 5721 | BUG_ON(cpu_online(smp_processor_id())); |
| 5725 | 5722 | ||
| 5726 | raw_spin_lock(&rq->lock); | 5723 | if (mm != &init_mm) |
| 5727 | needs_cpu = (task_cpu(p) == dead_cpu) && (p->state != TASK_WAKING); | 5724 | switch_mm(mm, &init_mm, current); |
| 5728 | if (needs_cpu) | 5725 | mmdrop(mm); |
| 5729 | dest_cpu = select_fallback_rq(dead_cpu, p); | ||
| 5730 | raw_spin_unlock(&rq->lock); | ||
| 5731 | /* | ||
| 5732 | * It can only fail if we race with set_cpus_allowed(), | ||
| 5733 | * in the racer should migrate the task anyway. | ||
| 5734 | */ | ||
| 5735 | if (needs_cpu) | ||
| 5736 | __migrate_task(p, dead_cpu, dest_cpu); | ||
| 5737 | local_irq_restore(flags); | ||
| 5738 | } | 5726 | } |
| 5739 | 5727 | ||
| 5740 | /* | 5728 | /* |
| @@ -5747,128 +5735,69 @@ void move_task_off_dead_cpu(int dead_cpu, struct task_struct *p) | |||
| 5747 | static void migrate_nr_uninterruptible(struct rq *rq_src) | 5735 | static void migrate_nr_uninterruptible(struct rq *rq_src) |
| 5748 | { | 5736 | { |
| 5749 | struct rq *rq_dest = cpu_rq(cpumask_any(cpu_active_mask)); | 5737 | struct rq *rq_dest = cpu_rq(cpumask_any(cpu_active_mask)); |
| 5750 | unsigned long flags; | ||
| 5751 | 5738 | ||
| 5752 | local_irq_save(flags); | ||
| 5753 | double_rq_lock(rq_src, rq_dest); | ||
| 5754 | rq_dest->nr_uninterruptible += rq_src->nr_uninterruptible; | 5739 | rq_dest->nr_uninterruptible += rq_src->nr_uninterruptible; |
| 5755 | rq_src->nr_uninterruptible = 0; | 5740 | rq_src->nr_uninterruptible = 0; |
| 5756 | double_rq_unlock(rq_src, rq_dest); | ||
| 5757 | local_irq_restore(flags); | ||
| 5758 | } | ||
| 5759 | |||
| 5760 | /* Run through task list and migrate tasks from the dead cpu. */ | ||
| 5761 | static void migrate_live_tasks(int src_cpu) | ||
| 5762 | { | ||
| 5763 | struct task_struct *p, *t; | ||
| 5764 | |||
| 5765 | read_lock(&tasklist_lock); | ||
| 5766 | |||
| 5767 | do_each_thread(t, p) { | ||
| 5768 | if (p == current) | ||
| 5769 | continue; | ||
| 5770 | |||
| 5771 | if (task_cpu(p) == src_cpu) | ||
| 5772 | move_task_off_dead_cpu(src_cpu, p); | ||
| 5773 | } while_each_thread(t, p); | ||
| 5774 | |||
| 5775 | read_unlock(&tasklist_lock); | ||
| 5776 | } | 5741 | } |
| 5777 | 5742 | ||
| 5778 | /* | 5743 | /* |
| 5779 | * Schedules idle task to be the next runnable task on current CPU. | 5744 | * remove the tasks which were accounted by rq from calc_load_tasks. |
| 5780 | * It does so by boosting its priority to highest possible. | ||
| 5781 | * Used by CPU offline code. | ||
| 5782 | */ | 5745 | */ |
| 5783 | void sched_idle_next(void) | 5746 | static void calc_global_load_remove(struct rq *rq) |
| 5784 | { | 5747 | { |
| 5785 | int this_cpu = smp_processor_id(); | 5748 | atomic_long_sub(rq->calc_load_active, &calc_load_tasks); |
| 5786 | struct rq *rq = cpu_rq(this_cpu); | 5749 | rq->calc_load_active = 0; |
| 5787 | struct task_struct *p = rq->idle; | ||
| 5788 | unsigned long flags; | ||
| 5789 | |||
| 5790 | /* cpu has to be offline */ | ||
