From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: linux-kernel@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
stable@vger.kernel.org, linux-raid@vger.kernel.org,
Oleg Nesterov <oleg@redhat.com>,
"Srivatsa S. Bhat" <srivatsa.bhat@linux.vnet.ibm.com>,
NeilBrown <neilb@suse.de>
Subject: [PATCH 3.4 21/25] md/raid5: Fix CPU hotplug callback registration
Date: Thu, 20 Feb 2014 15:51:37 -0800 [thread overview]
Message-ID: <20140220234843.077747471@linuxfoundation.org> (raw)
In-Reply-To: <20140220234842.483343851@linuxfoundation.org>
3.4-stable review patch. If anyone has any objections, please let me know.
------------------
From: Oleg Nesterov <oleg@redhat.com>
commit 789b5e0315284463617e106baad360cb9e8db3ac upstream.
Subsystems that want to register CPU hotplug callbacks, as well as perform
initialization for the CPUs that are already online, often do it as shown
below:
get_online_cpus();
for_each_online_cpu(cpu)
init_cpu(cpu);
register_cpu_notifier(&foobar_cpu_notifier);
put_online_cpus();
This is wrong, since it is prone to ABBA deadlocks involving the
cpu_add_remove_lock and the cpu_hotplug.lock (when running concurrently
with CPU hotplug operations).
Interestingly, the raid5 code can actually prevent double initialization and
hence can use the following simplified form of callback registration:
register_cpu_notifier(&foobar_cpu_notifier);
get_online_cpus();
for_each_online_cpu(cpu)
init_cpu(cpu);
put_online_cpus();
A hotplug operation that occurs between registering the notifier and calling
get_online_cpus(), won't disrupt anything, because the code takes care to
perform the memory allocations only once.
So reorganize the code in raid5 this way to fix the deadlock with callback
registration.
Cc: linux-raid@vger.kernel.org
Fixes: 36d1c6476be51101778882897b315bd928c8c7b5
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
[Srivatsa: Fixed the unregister_cpu_notifier() deadlock, added the
free_scratch_buffer() helper to condense code further and wrote the changelog.]
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/md/raid5.c | 90 +++++++++++++++++++++++++----------------------------
1 file changed, 44 insertions(+), 46 deletions(-)
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -4678,23 +4678,43 @@ raid5_size(struct mddev *mddev, sector_t
return sectors * (raid_disks - conf->max_degraded);
}
+static void free_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu)
+{
+ safe_put_page(percpu->spare_page);
+ kfree(percpu->scribble);
+ percpu->spare_page = NULL;
+ percpu->scribble = NULL;
+}
+
+static int alloc_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu)
+{
+ 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)) {
+ free_scratch_buffer(conf, percpu);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
static void raid5_free_percpu(struct r5conf *conf)
{
- struct raid5_percpu *percpu;
unsigned long cpu;
if (!conf->percpu)
return;
- get_online_cpus();
- for_each_possible_cpu(cpu) {
- percpu = per_cpu_ptr(conf->percpu, cpu);
- safe_put_page(percpu->spare_page);
- kfree(percpu->scribble);
- }
#ifdef CONFIG_HOTPLUG_CPU
unregister_cpu_notifier(&conf->cpu_notify);
#endif
+
+ get_online_cpus();
+ for_each_possible_cpu(cpu)
+ free_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu));
put_online_cpus();
free_percpu(conf->percpu);
@@ -4720,15 +4740,7 @@ static int raid456_cpu_notify(struct not
switch (action) {
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
- 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);
+ if (alloc_scratch_buffer(conf, percpu)) {
pr_err("%s: failed memory allocation for cpu%ld\n",
__func__, cpu);
return notifier_from_errno(-ENOMEM);
@@ -4736,10 +4748,7 @@ static int raid456_cpu_notify(struct not
break;
case CPU_DEAD:
case CPU_DEAD_FROZEN:
- safe_put_page(percpu->spare_page);
- kfree(percpu->scribble);
- percpu->spare_page = NULL;
- percpu->scribble = NULL;
+ free_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu));
break;
default:
break;
@@ -4751,40 +4760,29 @@ static int raid456_cpu_notify(struct not
static int raid5_alloc_percpu(struct r5conf *conf)
{
unsigned long cpu;
- struct page *spare_page;
- struct raid5_percpu __percpu *allcpus;
- void *scribble;
- int err;
+ int err = 0;
- allcpus = alloc_percpu(struct raid5_percpu);
- if (!allcpus)
+ conf->percpu = alloc_percpu(struct raid5_percpu);
+ if (!conf->percpu)
return -ENOMEM;
- conf->percpu = allcpus;
+
+#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
get_online_cpus();
- err = 0;
for_each_present_cpu(cpu) {
- 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;
+ err = alloc_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu));
+ if (err) {
+ pr_err("%s: failed memory allocation for cpu%ld\n",
+ __func__, cpu);
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;
next prev parent reply other threads:[~2014-02-21 1:08 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-02-20 23:51 [PATCH 3.4 00/25] 3.4.82-stable review Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 01/25] xen-blkfront: handle backend CLOSED without CLOSING Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 02/25] fs/file.c:fdtable: avoid triggering OOMs from alloc_fdmem Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 03/25] mac80211: fix fragmentation code, particularly for encryption Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 04/25] s390/dump: Fix dump memory detection Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 05/25] s390: fix kernel crash due to linkage stack instructions Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 06/25] spi: Fix crash with double message finalisation on error handling Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 07/25] raw: test against runtime value of max_raw_minors Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 08/25] lockd: send correct lock when granting a delayed lock Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 09/25] tty: n_gsm: Fix for modems with brk in modem status control Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 10/25] staging:iio:ad799x fix error_free_irq which was freeing an irq that may not have been requested Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 12/25] USB: ftdi_sio: add Tagsys RFID Reader IDs Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 13/25] usb-storage: add unusual-devs entry for BlackBerry 9000 Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 14/25] usb-storage: restrict bcdDevice range for Super Top in Cypress ATACB Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 15/25] usb-storage: enable multi-LUN scanning when needed Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 16/25] usb: option: blacklist ZTE MF667 net interface Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 17/25] Modpost: fixed USB alias generation for ranges including 0x9 and 0xA Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 18/25] block: add cond_resched() to potentially long running ioctl discard loop Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 19/25] IB/qib: Add missing serdes init sequence Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 20/25] KVM: return an error code in kvm_vm_ioctl_register_coalesced_mmio() Greg Kroah-Hartman
2014-02-20 23:51 ` Greg Kroah-Hartman [this message]
2014-02-20 23:51 ` [PATCH 3.4 22/25] time: Fix overflow when HZ is smaller than 60 Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 23/25] power: max17040: Fix NULL pointer dereference when there is no platform_data Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 24/25] ring-buffer: Fix first commit on sub-buffer having non-zero delta Greg Kroah-Hartman
2014-02-20 23:51 ` [PATCH 3.4 25/25] genirq: Add missing irq_to_desc export for CONFIG_SPARSE_IRQ=n Greg Kroah-Hartman
2014-02-21 5:05 ` [PATCH 3.4 00/25] 3.4.82-stable review Guenter Roeck
2014-02-21 23:40 ` Shuah Khan
2014-02-22 20:45 ` Greg KH
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20140220234843.077747471@linuxfoundation.org \
--to=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-raid@vger.kernel.org \
--cc=neilb@suse.de \
--cc=oleg@redhat.com \
--cc=srivatsa.bhat@linux.vnet.ibm.com \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox