diff options
author | Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com> | 2014-04-08 15:34:16 +0530 |
---|---|---|
committer | Eli Qiao <taget@linux.vnet.ibm.com> | 2014-04-09 10:21:51 +0800 |
commit | 1c2f35366426173c9b87b336629199de3d6293fe (patch) | |
tree | eff16442de8e05aeaab1a2f03bea16b2c328f5b8 | |
parent | 9466852d027bca067746207aca410ef4b0c0725b (diff) | |
download | powerkvm-1c2f35366426173c9b87b336629199de3d6293fe.tar.gz |
md/raid5: Revert partial fix of CPU hotplug callback registration
Commit 2775d6230 (md: Avoid deadlock in raid5_alloc_percpu) only partially
fixed the deadlock involving CPU hotplug notifiers. In particular, it fixed
the deadlock possibility in register_cpu_notifier(), but left the deadlock
in unregister_cpu_notifier() unfixed. So revert this commit so that we can
fix both the deadlocks properly, using the solution that was accepted
upstream.
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
-rw-r--r-- | drivers/md/raid5.c | 73 |
1 files changed, 39 insertions, 34 deletions
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 2091f31ba80e93..4bed5454b8dc10 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5067,25 +5067,6 @@ static void free_conf(struct r5conf *conf) kfree(conf); } -static int alloc_percpu_areas(struct r5conf *conf, struct raid5_percpu *percpu, - int cpu) -{ - if (conf->level == 6 && !percpu->spare_page) - percpu->spare_page = alloc_page(GFP_KERNEL); - if (!percpu->scribble) - percpu->scribble = kmalloc(conf->scribble_len, GFP_KERNEL); - - if (!percpu->scribble || (conf->level == 6 && !percpu->spare_page)) { - safe_put_page(percpu->spare_page); - kfree(percpu->scribble); - pr_err("%s: failed memory allocation for cpu%d\n", - __func__, cpu); - return -ENOMEM; - } - - return 0; -} - #ifdef CONFIG_HOTPLUG_CPU static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action, void *hcpu) @@ -5097,8 +5078,19 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action, switch (action) { case CPU_UP_PREPARE: case CPU_UP_PREPARE_FROZEN: - if (alloc_percpu_areas(conf, percpu, cpu)) + if (conf->level == 6 && !percpu->spare_page) + percpu->spare_page = alloc_page(GFP_KERNEL); + if (!percpu->scribble) + percpu->scribble = kmalloc(conf->scribble_len, GFP_KERNEL); + + if (!percpu->scribble || + (conf->level == 6 && !percpu->spare_page)) { + safe_put_page(percpu->spare_page); + kfree(percpu->scribble); + pr_err("%s: failed memory allocation for cpu%ld\n", + __func__, cpu); return notifier_from_errno(-ENOMEM); + } break; case CPU_DEAD: case CPU_DEAD_FROZEN: @@ -5117,27 +5109,40 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action, static int raid5_alloc_percpu(struct r5conf *conf) { unsigned long cpu; - int err = 0; + struct page *spare_page; + struct raid5_percpu __percpu *allcpus; + void *scribble; + int err; - conf->percpu = alloc_percpu(struct raid5_percpu); - if (!conf->percpu) + allcpus = alloc_percpu(struct raid5_percpu); + if (!allcpus) return -ENOMEM; - -#ifdef CONFIG_HOTPLUG_CPU - conf->cpu_notify.notifier_call = raid456_cpu_notify; - conf->cpu_notify.priority = 0; - err = register_cpu_notifier(&conf->cpu_notify); - if (err) - return err; -#endif + conf->percpu = allcpus; get_online_cpus(); + err = 0; for_each_present_cpu(cpu) { - err = alloc_percpu_areas(conf, per_cpu_ptr(conf->percpu, cpu), - cpu); - if (err) + if (conf->level == 6) { + spare_page = alloc_page(GFP_KERNEL); + if (!spare_page) { + err = -ENOMEM; + break; + } + per_cpu_ptr(conf->percpu, cpu)->spare_page = spare_page; + } + scribble = kmalloc(conf->scribble_len, GFP_KERNEL); + if (!scribble) { + err = -ENOMEM; break; + } + per_cpu_ptr(conf->percpu, cpu)->scribble = scribble; } +#ifdef CONFIG_HOTPLUG_CPU + conf->cpu_notify.notifier_call = raid456_cpu_notify; + conf->cpu_notify.priority = 0; + if (err == 0) + err = register_cpu_notifier(&conf->cpu_notify); +#endif put_online_cpus(); return err; |