aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen/balloon.c
diff options
context:
space:
mode:
authorSrivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>2014-03-10 16:41:45 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-03-20 08:43:48 -0400
commit43ea9536499e80d858e26cecb7abcc893f86d222 (patch)
tree57e8699ca04caaa7d86009e67cdc452ba78dcf74 /drivers/xen/balloon.c
parent2480b6a3e5e80d778455f8138ae6d6efb568cd59 (diff)
xen, balloon: Fix CPU hotplug callback registration
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). The xen balloon driver doesn't take get/put_online_cpus() around this code, but that is also buggy, since it can miss CPU hotplug events in between the initialization and callback registration: for_each_online_cpu(cpu) init_cpu(cpu); ^ | Race window; Can miss CPU hotplug events here. v register_cpu_notifier(&foobar_cpu_notifier); Interestingly, the balloon code in xen can simply be reorganized as shown below, to have a race-free method to register hotplug callbacks, without even taking get/put_online_cpus(). This is because the initialization performed for already online CPUs is exactly the same as that performed for CPUs that come online later. Moreover, the code has checks in place to avoid double initialization. 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 balloon code in xen this way to fix the issues with CPU hotplug callback registration. Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: David Vrabel <david.vrabel@citrix.com> Cc: Ingo Molnar <mingo@kernel.org> Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/xen/balloon.c')
-rw-r--r--drivers/xen/balloon.c36
1 files changed, 24 insertions, 12 deletions
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index 37d06ea624aa..dd7954922942 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -592,19 +592,29 @@ static void __init balloon_add_region(unsigned long start_pfn,
592 } 592 }
593} 593}
594 594
595static int alloc_balloon_scratch_page(int cpu)
596{
597 if (per_cpu(balloon_scratch_page, cpu) != NULL)
598 return 0;
599
600 per_cpu(balloon_scratch_page, cpu) = alloc_page(GFP_KERNEL);
601 if (per_cpu(balloon_scratch_page, cpu) == NULL) {
602 pr_warn("Failed to allocate balloon_scratch_page for cpu %d\n", cpu);
603 return -ENOMEM;
604 }
605
606 return 0;
607}
608
609
595static int balloon_cpu_notify(struct notifier_block *self, 610static int balloon_cpu_notify(struct notifier_block *self,
596 unsigned long action, void *hcpu) 611 unsigned long action, void *hcpu)
597{ 612{
598 int cpu = (long)hcpu; 613 int cpu = (long)hcpu;
599 switch (action) { 614 switch (action) {
600 case CPU_UP_PREPARE: 615 case CPU_UP_PREPARE:
601 if (per_cpu(balloon_scratch_page, cpu) != NULL) 616 if (alloc_balloon_scratch_page(cpu))
602 break;
603 per_cpu(balloon_scratch_page, cpu) = alloc_page(GFP_KERNEL);
604 if (per_cpu(balloon_scratch_page, cpu) == NULL) {
605 pr_warn("Failed to allocate balloon_scratch_page for cpu %d\n", cpu);
606 return NOTIFY_BAD; 617 return NOTIFY_BAD;
607 }
608 break; 618 break;
609 default: 619 default:
610 break; 620 break;
@@ -624,15 +634,17 @@ static int __init balloon_init(void)
624 return -ENODEV; 634 return -ENODEV;
625 635
626 if (!xen_feature(XENFEAT_auto_translated_physmap)) { 636 if (!xen_feature(XENFEAT_auto_translated_physmap)) {
627 for_each_online_cpu(cpu) 637 register_cpu_notifier(&balloon_cpu_notifier);
628 { 638
629 per_cpu(balloon_scratch_page, cpu) = alloc_page(GFP_KERNEL); 639 get_online_cpus();
630 if (per_cpu(balloon_scratch_page, cpu) == NULL) { 640 for_each_online_cpu(cpu) {
631 pr_warn("Failed to allocate balloon_scratch_page for cpu %d\n", cpu); 641 if (alloc_balloon_scratch_page(cpu)) {
642 put_online_cpus();
643 unregister_cpu_notifier(&balloon_cpu_notifier);
632 return -ENOMEM; 644 return -ENOMEM;
633 } 645 }
634 } 646 }
635 register_cpu_notifier(&balloon_cpu_notifier); 647 put_online_cpus();
636 } 648 }
637 649
638 pr_info("Initialising balloon driver\n"); 650 pr_info("Initialising balloon driver\n");