aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSrivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>2014-04-08 15:34:16 +0530
committerEli Qiao <taget@linux.vnet.ibm.com>2014-04-09 10:21:51 +0800
commit1c2f35366426173c9b87b336629199de3d6293fe (patch)
treeeff16442de8e05aeaab1a2f03bea16b2c328f5b8
parent9466852d027bca067746207aca410ef4b0c0725b (diff)
downloadpowerkvm-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.c73
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;