diff options
author | Tejun Heo <tj@kernel.org> | 2010-06-08 15:40:36 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2010-06-08 15:40:36 -0400 |
commit | 3a101d0548e925ab16ca6aaa8cf4f767d322ddb0 (patch) | |
tree | b90d8c5f2efe30fcfa49a00fdea037567c6cd46f /kernel/sched.c | |
parent | 50a323b73069b169385a8ac65633dee837a7d13f (diff) |
sched: adjust when cpu_active and cpuset configurations are updated during cpu on/offlining
Currently, when a cpu goes down, cpu_active is cleared before
CPU_DOWN_PREPARE starts and cpuset configuration is updated from a
default priority cpu notifier. When a cpu is coming up, it's set
before CPU_ONLINE but cpuset configuration again is updated from the
same cpu notifier.
For cpu notifiers, this presents an inconsistent state. Threads which
a CPU_DOWN_PREPARE notifier expects to be bound to the CPU can be
migrated to other cpus because the cpu is no more inactive.
Fix it by updating cpu_active in the highest priority cpu notifier and
cpuset configuration in the second highest when a cpu is coming up.
Down path is updated similarly. This guarantees that all other cpu
notifiers see consistent cpu_active and cpuset configuration.
cpuset_track_online_cpus() notifier is converted to
cpuset_update_active_cpus() which just updates the configuration and
now called from cpuset_cpu_[in]active() notifiers registered from
sched_init_smp(). If cpuset is disabled, cpuset_update_active_cpus()
degenerates into partition_sched_domains() making separate notifier
for !CONFIG_CPUSETS unnecessary.
This problem is triggered by cmwq. During CPU_DOWN_PREPARE, hotplug
callback creates a kthread and kthread_bind()s it to the target cpu,
and the thread is expected to run on that cpu.
* Ingo's test discovered __cpuinit/exit markups were incorrect.
Fixed.
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Paul Menage <menage@google.com>
Diffstat (limited to 'kernel/sched.c')
-rw-r--r-- | kernel/sched.c | 67 |
1 files changed, 50 insertions, 17 deletions
diff --git a/kernel/sched.c b/kernel/sched.c index 552faf8d358c..2b942e49d0fa 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -5804,17 +5804,46 @@ static struct notifier_block __cpuinitdata migration_notifier = { | |||
5804 | .priority = CPU_PRI_MIGRATION, | 5804 | .priority = CPU_PRI_MIGRATION, |
5805 | }; | 5805 | }; |
5806 | 5806 | ||
5807 | static int __cpuinit sched_cpu_active(struct notifier_block *nfb, | ||
5808 | unsigned long action, void *hcpu) | ||
5809 | { | ||
5810 | switch (action & ~CPU_TASKS_FROZEN) { | ||
5811 | case CPU_ONLINE: | ||
5812 | case CPU_DOWN_FAILED: | ||
5813 | set_cpu_active((long)hcpu, true); | ||
5814 | return NOTIFY_OK; | ||
5815 | default: | ||
5816 | return NOTIFY_DONE; | ||
5817 | } | ||
5818 | } | ||
5819 | |||
5820 | static int __cpuinit sched_cpu_inactive(struct notifier_block *nfb, | ||
5821 | unsigned long action, void *hcpu) | ||
5822 | { | ||
5823 | switch (action & ~CPU_TASKS_FROZEN) { | ||
5824 | case CPU_DOWN_PREPARE: | ||
5825 | set_cpu_active((long)hcpu, false); | ||
5826 | return NOTIFY_OK; | ||
5827 | default: | ||
5828 | return NOTIFY_DONE; | ||
5829 | } | ||
5830 | } | ||
5831 | |||
5807 | static int __init migration_init(void) | 5832 | static int __init migration_init(void) |
5808 | { | 5833 | { |
5809 | void *cpu = (void *)(long)smp_processor_id(); | 5834 | void *cpu = (void *)(long)smp_processor_id(); |
5810 | int err; | 5835 | int err; |
5811 | 5836 | ||
5812 | /* Start one for the boot CPU: */ | 5837 | /* Initialize migration for the boot CPU */ |
5813 | err = migration_call(&migration_notifier, CPU_UP_PREPARE, cpu); | 5838 | err = migration_call(&migration_notifier, CPU_UP_PREPARE, cpu); |
5814 | BUG_ON(err == NOTIFY_BAD); | 5839 | BUG_ON(err == NOTIFY_BAD); |
5815 | migration_call(&migration_notifier, CPU_ONLINE, cpu); | 5840 | migration_call(&migration_notifier, CPU_ONLINE, cpu); |
5816 | register_cpu_notifier(&migration_notifier); | 5841 | register_cpu_notifier(&migration_notifier); |
5817 | 5842 | ||
5843 | /* Register cpu active notifiers */ | ||
5844 | cpu_notifier(sched_cpu_active, CPU_PRI_SCHED_ACTIVE); | ||
5845 | cpu_notifier(sched_cpu_inactive, CPU_PRI_SCHED_INACTIVE); | ||
5846 | |||
5818 | return 0; | 5847 | return 0; |
5819 | } | 5848 | } |
5820 | early_initcall(migration_init); | 5849 | early_initcall(migration_init); |
@@ -7273,29 +7302,35 @@ int __init sched_create_sysfs_power_savings_entries(struct sysdev_class *cls) | |||
7273 | } | 7302 | } |
7274 | #endif /* CONFIG_SCHED_MC || CONFIG_SCHED_SMT */ | 7303 | #endif /* CONFIG_SCHED_MC || CONFIG_SCHED_SMT */ |
7275 | 7304 | ||
7276 | #ifndef CONFIG_CPUSETS | ||
7277 | /* | 7305 | /* |
7278 | * Add online and remove offline CPUs from the scheduler domains. | 7306 | * Update cpusets according to cpu_active mask. If cpusets are |
7279 | * When cpusets are enabled they take over this function. | 7307 | * disabled, cpuset_update_active_cpus() becomes a simple wrapper |
7308 | * around partition_sched_domains(). | ||
7280 | */ | 7309 | */ |
7281 | static int update_sched_domains(struct notifier_block *nfb, | 7310 | static int __cpuexit cpuset_cpu_active(struct notifier_block *nfb, |
7282 | unsigned long action, void *hcpu) | 7311 | unsigned long action, void *hcpu) |
7283 | { | 7312 | { |
7284 | switch (action) { | 7313 | switch (action & ~CPU_TASKS_FROZEN) { |
7285 | case CPU_ONLINE: | 7314 | case CPU_ONLINE: |
7286 | case CPU_ONLINE_FROZEN: | ||
7287 | case CPU_DOWN_PREPARE: | ||
7288 | case CPU_DOWN_PREPARE_FROZEN: | ||
7289 | case CPU_DOWN_FAILED: | 7315 | case CPU_DOWN_FAILED: |
7290 | case CPU_DOWN_FAILED_FROZEN: | 7316 | cpuset_update_active_cpus(); |
7291 | partition_sched_domains(1, NULL, NULL); | ||
7292 | return NOTIFY_OK; | 7317 | return NOTIFY_OK; |
7318 | default: | ||
7319 | return NOTIFY_DONE; | ||
7320 | } | ||
7321 | } | ||
7293 | 7322 | ||
7323 | static int __cpuexit cpuset_cpu_inactive(struct notifier_block *nfb, | ||
7324 | unsigned long action, void *hcpu) | ||
7325 | { | ||
7326 | switch (action & ~CPU_TASKS_FROZEN) { | ||
7327 | case CPU_DOWN_PREPARE: | ||
7328 | cpuset_update_active_cpus(); | ||
7329 | return NOTIFY_OK; | ||
7294 | default: | 7330 | default: |
7295 | return NOTIFY_DONE; | 7331 | return NOTIFY_DONE; |
7296 | } | 7332 | } |
7297 | } | 7333 | } |
7298 | #endif | ||
7299 | 7334 | ||
7300 | static int update_runtime(struct notifier_block *nfb, | 7335 | static int update_runtime(struct notifier_block *nfb, |
7301 | unsigned long action, void *hcpu) | 7336 | unsigned long action, void *hcpu) |
@@ -7341,10 +7376,8 @@ void __init sched_init_smp(void) | |||
7341 | mutex_unlock(&sched_domains_mutex); | 7376 | mutex_unlock(&sched_domains_mutex); |
7342 | put_online_cpus(); | 7377 | put_online_cpus(); |
7343 | 7378 | ||
7344 | #ifndef CONFIG_CPUSETS | 7379 | hotcpu_notifier(cpuset_cpu_active, CPU_PRI_CPUSET_ACTIVE); |
7345 | /* XXX: Theoretical race here - CPU may be hotplugged now */ | 7380 | hotcpu_notifier(cpuset_cpu_inactive, CPU_PRI_CPUSET_INACTIVE); |
7346 | hotcpu_notifier(update_sched_domains, 0); | ||
7347 | #endif | ||
7348 | 7381 | ||
7349 | /* RT runtime code needs to handle some hotplug events */ | 7382 | /* RT runtime code needs to handle some hotplug events */ |
7350 | hotcpu_notifier(update_runtime, 0); | 7383 | hotcpu_notifier(update_runtime, 0); |