aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSrivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>2014-03-10 16:42:57 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-03-20 08:43:48 -0400
commita0e247a8059223593f9c5c3d5c1fd50eedf415c0 (patch)
tree8a5dedd84f4de6e40916a6e55e1a1cd3e09d86a3
parente30a293e8ad7e6048d6d88bcc114094f964bd67b (diff)
net/iucv/iucv.c: 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). Instead, the correct and race-free way of performing the callback registration is: cpu_notifier_register_begin(); for_each_online_cpu(cpu) init_cpu(cpu); /* Note the use of the double underscored version of the API */ __register_cpu_notifier(&foobar_cpu_notifier); cpu_notifier_register_done(); Fix the code in net/iucv/iucv.c by using this latter form of callback registration. Also, provide helper functions to perform the common memory allocations and frees, to condense repetitive code. Cc: Ursula Braun <ursula.braun@de.ibm.com> Cc: Ingo Molnar <mingo@kernel.org> Acked-by: David S. Miller <davem@davemloft.net> Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--net/iucv/iucv.c121
1 files changed, 57 insertions, 64 deletions
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index cd5b8ec9be04..79a0ce95799f 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -621,6 +621,42 @@ static void iucv_disable(void)
621 put_online_cpus(); 621 put_online_cpus();
622} 622}
623 623
624static void free_iucv_data(int cpu)
625{
626 kfree(iucv_param_irq[cpu]);
627 iucv_param_irq[cpu] = NULL;
628 kfree(iucv_param[cpu]);
629 iucv_param[cpu] = NULL;
630 kfree(iucv_irq_data[cpu]);
631 iucv_irq_data[cpu] = NULL;
632}
633
634static int alloc_iucv_data(int cpu)
635{
636 /* Note: GFP_DMA used to get memory below 2G */
637 iucv_irq_data[cpu] = kmalloc_node(sizeof(struct iucv_irq_data),
638 GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
639 if (!iucv_irq_data[cpu])
640 goto out_free;
641
642 /* Allocate parameter blocks. */
643 iucv_param[cpu] = kmalloc_node(sizeof(union iucv_param),
644 GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
645 if (!iucv_param[cpu])
646 goto out_free;
647
648 iucv_param_irq[cpu] = kmalloc_node(sizeof(union iucv_param),
649 GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
650 if (!iucv_param_irq[cpu])
651 goto out_free;
652
653 return 0;
654
655out_free:
656 free_iucv_data(cpu);
657 return -ENOMEM;
658}
659
624static int iucv_cpu_notify(struct notifier_block *self, 660static int iucv_cpu_notify(struct notifier_block *self,
625 unsigned long action, void *hcpu) 661 unsigned long action, void *hcpu)
626{ 662{
@@ -630,38 +666,14 @@ static int iucv_cpu_notify(struct notifier_block *self,
630 switch (action) { 666 switch (action) {
631 case CPU_UP_PREPARE: 667 case CPU_UP_PREPARE:
632 case CPU_UP_PREPARE_FROZEN: 668 case CPU_UP_PREPARE_FROZEN:
633 iucv_irq_data[cpu] = kmalloc_node(sizeof(struct iucv_irq_data), 669 if (alloc_iucv_data(cpu))
634 GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
635 if (!iucv_irq_data[cpu])
636 return notifier_from_errno(-ENOMEM);
637
638 iucv_param[cpu] = kmalloc_node(sizeof(union iucv_param),
639 GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
640 if (!iucv_param[cpu]) {
641 kfree(iucv_irq_data[cpu]);
642 iucv_irq_data[cpu] = NULL;
643 return notifier_from_errno(-ENOMEM); 670 return notifier_from_errno(-ENOMEM);
644 }
645 iucv_param_irq[cpu] = kmalloc_node(sizeof(union iucv_param),
646 GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
647 if (!iucv_param_irq[cpu]) {
648 kfree(iucv_param[cpu]);
649 iucv_param[cpu] = NULL;
650 kfree(iucv_irq_data[cpu]);
651 iucv_irq_data[cpu] = NULL;
652 return notifier_from_errno(-ENOMEM);
653 }
654 break; 671 break;
655 case CPU_UP_CANCELED: 672 case CPU_UP_CANCELED:
656 case CPU_UP_CANCELED_FROZEN: 673 case CPU_UP_CANCELED_FROZEN:
657 case CPU_DEAD: 674 case CPU_DEAD:
658 case CPU_DEAD_FROZEN: 675 case CPU_DEAD_FROZEN:
659 kfree(iucv_param_irq[cpu]); 676 free_iucv_data(cpu);
660 iucv_param_irq[cpu] = NULL;
661 kfree(iucv_param[cpu]);
662 iucv_param[cpu] = NULL;
663 kfree(iucv_irq_data[cpu]);
664 iucv_irq_data[cpu] = NULL;
665 break; 677 break;
666 case CPU_ONLINE: 678 case CPU_ONLINE:
667 case CPU_ONLINE_FROZEN: 679 case CPU_ONLINE_FROZEN:
@@ -2025,33 +2037,20 @@ static int __init iucv_init(void)
2025 goto out_int; 2037 goto out_int;
2026 } 2038 }
2027 2039
2028 for_each_online_cpu(cpu) { 2040 cpu_notifier_register_begin();
2029 /* Note: GFP_DMA used to get memory below 2G */
2030 iucv_irq_data[cpu] = kmalloc_node(sizeof(struct iucv_irq_data),
2031 GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
2032 if (!iucv_irq_data[cpu]) {
2033 rc = -ENOMEM;
2034 goto out_free;
2035 }
2036 2041
2037 /* Allocate parameter blocks. */ 2042 for_each_online_cpu(cpu) {
2038 iucv_param[cpu] = kmalloc_node(sizeof(union iucv_param), 2043 if (alloc_iucv_data(cpu)) {
2039 GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
2040 if (!iucv_param[cpu]) {
2041 rc = -ENOMEM;
2042 goto out_free;
2043 }
2044 iucv_param_irq[cpu] = kmalloc_node(sizeof(union iucv_param),
2045 GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
2046 if (!iucv_param_irq[cpu]) {
2047 rc = -ENOMEM; 2044 rc = -ENOMEM;
2048 goto out_free; 2045 goto out_free;
2049 } 2046 }
2050
2051 } 2047 }
2052 rc = register_hotcpu_notifier(&iucv_cpu_notifier); 2048 rc = __register_hotcpu_notifier(&iucv_cpu_notifier);
2053 if (rc) 2049 if (rc)
2054 goto out_free; 2050 goto out_free;
2051
2052 cpu_notifier_register_done();
2053
2055 rc = register_reboot_notifier(&iucv_reboot_notifier); 2054 rc = register_reboot_notifier(&iucv_reboot_notifier);
2056 if (rc) 2055 if (rc)
2057 goto out_cpu; 2056 goto out_cpu;
@@ -2069,16 +2068,14 @@ static int __init iucv_init(void)
2069out_reboot: 2068out_reboot:
2070 unregister_reboot_notifier(&iucv_reboot_notifier); 2069 unregister_reboot_notifier(&iucv_reboot_notifier);
2071out_cpu: 2070out_cpu:
2072 unregister_hotcpu_notifier(&iucv_cpu_notifier); 2071 cpu_notifier_register_begin();
2072 __unregister_hotcpu_notifier(&iucv_cpu_notifier);
2073out_free: 2073out_free:
2074 for_each_possible_cpu(cpu) { 2074 for_each_possible_cpu(cpu)
2075 kfree(iucv_param_irq[cpu]); 2075 free_iucv_data(cpu);
2076 iucv_param_irq[cpu] = NULL; 2076
2077 kfree(iucv_param[cpu]); 2077 cpu_notifier_register_done();
2078 iucv_param[cpu] = NULL; 2078
2079 kfree(iucv_irq_data[cpu]);
2080 iucv_irq_data[cpu] = NULL;
2081 }
2082 root_device_unregister(iucv_root); 2079 root_device_unregister(iucv_root);
2083out_int: 2080out_int:
2084 unregister_external_interrupt(0x4000, iucv_external_interrupt); 2081 unregister_external_interrupt(0x4000, iucv_external_interrupt);
@@ -2105,15 +2102,11 @@ static void __exit iucv_exit(void)
2105 kfree(p); 2102 kfree(p);
2106 spin_unlock_irq(&iucv_queue_lock); 2103 spin_unlock_irq(&iucv_queue_lock);
2107 unregister_reboot_notifier(&iucv_reboot_notifier); 2104 unregister_reboot_notifier(&iucv_reboot_notifier);
2108 unregister_hotcpu_notifier(&iucv_cpu_notifier); 2105 cpu_notifier_register_begin();
2109 for_each_possible_cpu(cpu) { 2106 __unregister_hotcpu_notifier(&iucv_cpu_notifier);
2110 kfree(iucv_param_irq[cpu]); 2107 for_each_possible_cpu(cpu)
2111 iucv_param_irq[cpu] = NULL; 2108 free_iucv_data(cpu);
2112 kfree(iucv_param[cpu]); 2109 cpu_notifier_register_done();
2113 iucv_param[cpu] = NULL;
2114 kfree(iucv_irq_data[cpu]);
2115 iucv_irq_data[cpu] = NULL;
2116 }
2117 root_device_unregister(iucv_root); 2110 root_device_unregister(iucv_root);
2118 bus_unregister(&iucv_bus); 2111 bus_unregister(&iucv_bus);
2119 unregister_external_interrupt(0x4000, iucv_external_interrupt); 2112 unregister_external_interrupt(0x4000, iucv_external_interrupt);