aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/hw/ipath/ipath_driver.c
diff options
context:
space:
mode:
authorDave Olson <dave.olson@qlogic.com>2008-12-05 14:14:38 -0500
committerRoland Dreier <rolandd@cisco.com>2008-12-05 14:14:38 -0500
commit3d0890985ac4dff781b7feba19fedda547314749 (patch)
tree4e18e4e70c32abf9450c223db97affb1d05dbeeb /drivers/infiniband/hw/ipath/ipath_driver.c
parent1bf7724e093cf3071d943d53bfa4de8b8e50426b (diff)
IB/ipath: Add locking for interrupt use of ipath_pd contexts vs free
Fixes timing race resulting in panic. Not a performance sensitive path. Signed-off-by: Dave Olson <dave.olson@qlogic.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw/ipath/ipath_driver.c')
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c49
1 files changed, 30 insertions, 19 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index ad0aab60b051..69c0ce321b4e 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -661,6 +661,8 @@ bail:
661static void __devexit cleanup_device(struct ipath_devdata *dd) 661static void __devexit cleanup_device(struct ipath_devdata *dd)
662{ 662{
663 int port; 663 int port;
664 struct ipath_portdata **tmp;
665 unsigned long flags;
664 666
665 if (*dd->ipath_statusp & IPATH_STATUS_CHIP_PRESENT) { 667 if (*dd->ipath_statusp & IPATH_STATUS_CHIP_PRESENT) {
666 /* can't do anything more with chip; needs re-init */ 668 /* can't do anything more with chip; needs re-init */
@@ -742,20 +744,21 @@ static void __devexit cleanup_device(struct ipath_devdata *dd)
742 744
743 /* 745 /*
744 * free any resources still in use (usually just kernel ports) 746 * free any resources still in use (usually just kernel ports)
745 * at unload; we do for portcnt, not cfgports, because cfgports 747 * at unload; we do for portcnt, because that's what we allocate.
746 * could have changed while we were loaded. 748 * We acquire lock to be really paranoid that ipath_pd isn't being
749 * accessed from some interrupt-related code (that should not happen,
750 * but best to be sure).
747 */ 751 */
752 spin_lock_irqsave(&dd->ipath_uctxt_lock, flags);
753 tmp = dd->ipath_pd;
754 dd->ipath_pd = NULL;
755 spin_unlock_irqrestore(&dd->ipath_uctxt_lock, flags);
748 for (port = 0; port < dd->ipath_portcnt; port++) { 756 for (port = 0; port < dd->ipath_portcnt; port++) {
749 struct ipath_portdata *pd = dd->ipath_pd[port]; 757 struct ipath_portdata *pd = tmp[port];
750 dd->ipath_pd[port] = NULL; 758 tmp[port] = NULL; /* debugging paranoia */
751 ipath_free_pddata(dd, pd); 759 ipath_free_pddata(dd, pd);
752 } 760 }
753 kfree(dd->ipath_pd); 761 kfree(tmp);
754 /*
755 * debuggability, in case some cleanup path tries to use it
756 * after this
757 */
758 dd->ipath_pd = NULL;
759} 762}
760 763
761static void __devexit ipath_remove_one(struct pci_dev *pdev) 764static void __devexit ipath_remove_one(struct pci_dev *pdev)
@@ -2586,6 +2589,7 @@ int ipath_reset_device(int unit)
2586{ 2589{
2587 int ret, i; 2590 int ret, i;
2588 struct ipath_devdata *dd = ipath_lookup(unit); 2591 struct ipath_devdata *dd = ipath_lookup(unit);
2592 unsigned long flags;
2589 2593
2590 if (!dd) { 2594 if (!dd) {
2591 ret = -ENODEV; 2595 ret = -ENODEV;
@@ -2611,18 +2615,21 @@ int ipath_reset_device(int unit)
2611 goto bail; 2615 goto bail;
2612 } 2616 }
2613 2617
2618 spin_lock_irqsave(&dd->ipath_uctxt_lock, flags);
2614 if (dd->ipath_pd) 2619 if (dd->ipath_pd)
2615 for (i = 1; i < dd->ipath_cfgports; i++) { 2620 for (i = 1; i < dd->ipath_cfgports; i++) {
2616 if (dd->ipath_pd[i] && dd->ipath_pd[i]->port_cnt) { 2621 if (!dd->ipath_pd[i] || !dd->ipath_pd[i]->port_cnt)
2617 ipath_dbg("unit %u port %d is in use " 2622 continue;
2618 "(PID %u cmd %s), can't reset\n", 2623 spin_unlock_irqrestore(&dd->ipath_uctxt_lock, flags);
2619 unit, i, 2624 ipath_dbg("unit %u port %d is in use "
2620 pid_nr(dd->ipath_pd[i]->port_pid), 2625 "(PID %u cmd %s), can't reset\n",
2621 dd->ipath_pd[i]->port_comm); 2626 unit, i,
2622 ret = -EBUSY; 2627 pid_nr(dd->ipath_pd[i]->port_pid),
2623 goto bail; 2628 dd->ipath_pd[i]->port_comm);
2624 } 2629 ret = -EBUSY;
2630 goto bail;
2625 } 2631 }
2632 spin_unlock_irqrestore(&dd->ipath_uctxt_lock, flags);
2626 2633
2627 if (dd->ipath_flags & IPATH_HAS_SEND_DMA) 2634 if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
2628 teardown_sdma(dd); 2635 teardown_sdma(dd);
@@ -2656,9 +2663,12 @@ static int ipath_signal_procs(struct ipath_devdata *dd, int sig)
2656{ 2663{
2657 int i, sub, any = 0; 2664 int i, sub, any = 0;
2658 struct pid *pid; 2665 struct pid *pid;
2666 unsigned long flags;
2659 2667
2660 if (!dd->ipath_pd) 2668 if (!dd->ipath_pd)
2661 return 0; 2669 return 0;
2670
2671 spin_lock_irqsave(&dd->ipath_uctxt_lock, flags);
2662 for (i = 1; i < dd->ipath_cfgports; i++) { 2672 for (i = 1; i < dd->ipath_cfgports; i++) {
2663 if (!dd->ipath_pd[i] || !dd->ipath_pd[i]->port_cnt) 2673 if (!dd->ipath_pd[i] || !dd->ipath_pd[i]->port_cnt)
2664 continue; 2674 continue;
@@ -2682,6 +2692,7 @@ static int ipath_signal_procs(struct ipath_devdata *dd, int sig)
2682 any++; 2692 any++;
2683 } 2693 }
2684 } 2694 }
2695 spin_unlock_irqrestore(&dd->ipath_uctxt_lock, flags);
2685 return any; 2696 return any;
2686} 2697}
2687 2698