aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2010-11-13 13:32:29 -0500
committerIngo Molnar <mingo@elte.hu>2010-11-18 07:27:46 -0500
commit48c5ccae88dcd989d9de507e8510313c6cbd352b (patch)
tree06fe8ce2ac28e9f5844de8bc32ecbef97e40d68b
parent92fd4d4d67b945c0766416284d4ab236b31542c4 (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.h3
-rw-r--r--kernel/cpu.c16
-rw-r--r--kernel/sched.c206
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);
1871extern void sched_clock_idle_wakeup_event(u64 delta_ns); 1871extern void sched_clock_idle_wakeup_event(u64 delta_ns);
1872 1872
1873#ifdef CONFIG_HOTPLUG_CPU 1873#ifdef CONFIG_HOTPLUG_CPU
1874extern void move_task_off_dead_cpu(int dead_cpu, struct task_struct *p);
1875extern void idle_task_exit(void); 1874extern void idle_task_exit(void);
1876#else 1875#else
1877static inline void idle_task_exit(void) {} 1876static inline void idle_task_exit(void) {}
1878#endif 1877#endif
1879 1878
1880extern void sched_idle_next(void);
1881
1882#if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP) 1879#if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP)
1883extern void wake_up_idle_cpu(int cpu); 1880extern 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
191struct take_cpu_down_param { 191struct 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 */
5718void move_task_off_dead_cpu(int dead_cpu, struct task_struct *p) 5717void 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)
5747static void migrate_nr_uninterruptible(struct rq *rq_src) 5735static 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. */
5761static 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 */
5783void sched_idle_next(void) 5746static 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 */