diff options
author | Dave Olson <dave.olson@qlogic.com> | 2008-12-05 14:14:38 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2008-12-05 14:14:38 -0500 |
commit | 3d0890985ac4dff781b7feba19fedda547314749 (patch) | |
tree | 4e18e4e70c32abf9450c223db97affb1d05dbeeb | |
parent | 1bf7724e093cf3071d943d53bfa4de8b8e50426b (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>
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_driver.c | 49 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_file_ops.c | 21 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_init_chip.c | 1 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_kernel.h | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_keys.c | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_mad.c | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_verbs.c | 3 |
7 files changed, 49 insertions, 31 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: | |||
661 | static void __devexit cleanup_device(struct ipath_devdata *dd) | 661 | static 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 | ||
761 | static void __devexit ipath_remove_one(struct pci_dev *pdev) | 764 | static 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 | ||
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c index ceab52c09cdb..239d4e8068ac 100644 --- a/drivers/infiniband/hw/ipath/ipath_file_ops.c +++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c | |||
@@ -2046,7 +2046,9 @@ static int ipath_close(struct inode *in, struct file *fp) | |||
2046 | struct ipath_filedata *fd; | 2046 | struct ipath_filedata *fd; |
2047 | struct ipath_portdata *pd; | 2047 | struct ipath_portdata *pd; |
2048 | struct ipath_devdata *dd; | 2048 | struct ipath_devdata *dd; |
2049 | unsigned long flags; | ||
2049 | unsigned port; | 2050 | unsigned port; |
2051 | struct pid *pid; | ||
2050 | 2052 | ||
2051 | ipath_cdbg(VERBOSE, "close on dev %lx, private data %p\n", | 2053 | ipath_cdbg(VERBOSE, "close on dev %lx, private data %p\n", |
2052 | (long)in->i_rdev, fp->private_data); | 2054 | (long)in->i_rdev, fp->private_data); |
@@ -2079,14 +2081,13 @@ static int ipath_close(struct inode *in, struct file *fp) | |||
2079 | mutex_unlock(&ipath_mutex); | 2081 | mutex_unlock(&ipath_mutex); |
2080 | goto bail; | 2082 | goto bail; |
2081 | } | 2083 | } |
2084 | /* early; no interrupt users after this */ | ||
2085 | spin_lock_irqsave(&dd->ipath_uctxt_lock, flags); | ||
2082 | port = pd->port_port; | 2086 | port = pd->port_port; |
2083 | 2087 | dd->ipath_pd[port] = NULL; | |
2084 | if (pd->port_hdrqfull) { | 2088 | pid = pd->port_pid; |
2085 | ipath_cdbg(PROC, "%s[%u] had %u rcvhdrqfull errors " | 2089 | pd->port_pid = NULL; |
2086 | "during run\n", pd->port_comm, pid_nr(pd->port_pid), | 2090 | spin_unlock_irqrestore(&dd->ipath_uctxt_lock, flags); |
2087 | pd->port_hdrqfull); | ||
2088 | pd->port_hdrqfull = 0; | ||
2089 | } | ||
2090 | 2091 | ||
2091 | if (pd->port_rcvwait_to || pd->port_piowait_to | 2092 | if (pd->port_rcvwait_to || pd->port_piowait_to |
2092 | || pd->port_rcvnowait || pd->port_pionowait) { | 2093 | || pd->port_rcvnowait || pd->port_pionowait) { |
@@ -2143,13 +2144,11 @@ static int ipath_close(struct inode *in, struct file *fp) | |||
2143 | unlock_expected_tids(pd); | 2144 | unlock_expected_tids(pd); |
2144 | ipath_stats.sps_ports--; | 2145 | ipath_stats.sps_ports--; |
2145 | ipath_cdbg(PROC, "%s[%u] closed port %u:%u\n", | 2146 | ipath_cdbg(PROC, "%s[%u] closed port %u:%u\n", |
2146 | pd->port_comm, pid_nr(pd->port_pid), | 2147 | pd->port_comm, pid_nr(pid), |
2147 | dd->ipath_unit, port); | 2148 | dd->ipath_unit, port); |
2148 | } | 2149 | } |
2149 | 2150 | ||
2150 | put_pid(pd->port_pid); | 2151 | put_pid(pid); |
2151 | pd->port_pid = NULL; | ||
2152 | dd->ipath_pd[pd->port_port] = NULL; /* before releasing mutex */ | ||
2153 | mutex_unlock(&ipath_mutex); | 2152 | mutex_unlock(&ipath_mutex); |
2154 | ipath_free_pddata(dd, pd); /* after releasing the mutex */ | 2153 | ipath_free_pddata(dd, pd); /* after releasing the mutex */ |
2155 | 2154 | ||
diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c index 3e5baa43fc82..64aeefbd2a5d 100644 --- a/drivers/infiniband/hw/ipath/ipath_init_chip.c +++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c | |||
@@ -229,6 +229,7 @@ static int init_chip_first(struct ipath_devdata *dd) | |||
229 | spin_lock_init(&dd->ipath_kernel_tid_lock); | 229 | spin_lock_init(&dd->ipath_kernel_tid_lock); |
230 | spin_lock_init(&dd->ipath_user_tid_lock); | 230 | spin_lock_init(&dd->ipath_user_tid_lock); |
231 | spin_lock_init(&dd->ipath_sendctrl_lock); | 231 | spin_lock_init(&dd->ipath_sendctrl_lock); |
232 | spin_lock_init(&dd->ipath_uctxt_lock); | ||
232 | spin_lock_init(&dd->ipath_sdma_lock); | 233 | spin_lock_init(&dd->ipath_sdma_lock); |
233 | spin_lock_init(&dd->ipath_gpio_lock); | 234 | spin_lock_init(&dd->ipath_gpio_lock); |
234 | spin_lock_init(&dd->ipath_eep_st_lock); | 235 | spin_lock_init(&dd->ipath_eep_st_lock); |
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index aa84153b731b..6ba4861dd6ac 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h | |||
@@ -477,6 +477,8 @@ struct ipath_devdata { | |||
477 | spinlock_t ipath_kernel_tid_lock; | 477 | spinlock_t ipath_kernel_tid_lock; |
478 | spinlock_t ipath_user_tid_lock; | 478 | spinlock_t ipath_user_tid_lock; |
479 | spinlock_t ipath_sendctrl_lock; | 479 | spinlock_t ipath_sendctrl_lock; |
480 | /* around ipath_pd and (user ports) port_cnt use (intr vs free) */ | ||
481 | spinlock_t ipath_uctxt_lock; | ||
480 | 482 | ||
481 | /* | 483 | /* |
482 | * IPATH_STATUS_*, | 484 | * IPATH_STATUS_*, |
diff --git a/drivers/infiniband/hw/ipath/ipath_keys.c b/drivers/infiniband/hw/ipath/ipath_keys.c index 8f32b17a5eed..c0e933fec218 100644 --- a/drivers/infiniband/hw/ipath/ipath_keys.c +++ b/drivers/infiniband/hw/ipath/ipath_keys.c | |||
@@ -132,6 +132,7 @@ int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge, | |||
132 | * (see ipath_get_dma_mr and ipath_dma.c). | 132 | * (see ipath_get_dma_mr and ipath_dma.c). |
133 | */ | 133 | */ |
134 | if (sge->lkey == 0) { | 134 | if (sge->lkey == 0) { |
135 | /* always a kernel port, no locking needed */ | ||
135 | struct ipath_pd *pd = to_ipd(qp->ibqp.pd); | 136 | struct ipath_pd *pd = to_ipd(qp->ibqp.pd); |
136 | 137 | ||
137 | if (pd->user) { | 138 | if (pd->user) { |
@@ -211,6 +212,7 @@ int ipath_rkey_ok(struct ipath_qp *qp, struct ipath_sge_state *ss, | |||
211 | * (see ipath_get_dma_mr and ipath_dma.c). | 212 | * (see ipath_get_dma_mr and ipath_dma.c). |
212 | */ | 213 | */ |
213 | if (rkey == 0) { | 214 | if (rkey == 0) { |
215 | /* always a kernel port, no locking needed */ | ||
214 | struct ipath_pd *pd = to_ipd(qp->ibqp.pd); | 216 | struct ipath_pd *pd = to_ipd(qp->ibqp.pd); |
215 | 217 | ||
216 | if (pd->user) { | 218 | if (pd->user) { |
diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c index be4fc9ada8e7..17a123197477 100644 --- a/drivers/infiniband/hw/ipath/ipath_mad.c +++ b/drivers/infiniband/hw/ipath/ipath_mad.c | |||
@@ -348,6 +348,7 @@ bail: | |||
348 | */ | 348 | */ |
349 | static int get_pkeys(struct ipath_devdata *dd, u16 * pkeys) | 349 | static int get_pkeys(struct ipath_devdata *dd, u16 * pkeys) |
350 | { | 350 | { |
351 | /* always a kernel port, no locking needed */ | ||
351 | struct ipath_portdata *pd = dd->ipath_pd[0]; | 352 | struct ipath_portdata *pd = dd->ipath_pd[0]; |
352 | 353 | ||
353 | memcpy(pkeys, pd->port_pkeys, sizeof(pd->port_pkeys)); | 354 | memcpy(pkeys, pd->port_pkeys, sizeof(pd->port_pkeys)); |
@@ -730,6 +731,7 @@ static int set_pkeys(struct ipath_devdata *dd, u16 *pkeys) | |||
730 | int i; | 731 | int i; |
731 | int changed = 0; | 732 | int changed = 0; |
732 | 733 | ||
734 | /* always a kernel port, no locking needed */ | ||
733 | pd = dd->ipath_pd[0]; | 735 | pd = dd->ipath_pd[0]; |
734 | 736 | ||
735 | for (i = 0; i < ARRAY_SIZE(pd->port_pkeys); i++) { | 737 | for (i = 0; i < ARRAY_SIZE(pd->port_pkeys); i++) { |
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index eabc4247860b..cdf0e6abd34d 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c | |||
@@ -1852,7 +1852,7 @@ unsigned ipath_get_npkeys(struct ipath_devdata *dd) | |||
1852 | } | 1852 | } |
1853 | 1853 | ||
1854 | /** | 1854 | /** |
1855 | * ipath_get_pkey - return the indexed PKEY from the port 0 PKEY table | 1855 | * ipath_get_pkey - return the indexed PKEY from the port PKEY table |
1856 | * @dd: the infinipath device | 1856 | * @dd: the infinipath device |
1857 | * @index: the PKEY index | 1857 | * @index: the PKEY index |
1858 | */ | 1858 | */ |
@@ -1860,6 +1860,7 @@ unsigned ipath_get_pkey(struct ipath_devdata *dd, unsigned index) | |||
1860 | { | 1860 | { |
1861 | unsigned ret; | 1861 | unsigned ret; |
1862 | 1862 | ||
1863 | /* always a kernel port, no locking needed */ | ||
1863 | if (index >= ARRAY_SIZE(dd->ipath_pd[0]->port_pkeys)) | 1864 | if (index >= ARRAY_SIZE(dd->ipath_pd[0]->port_pkeys)) |
1864 | ret = 0; | 1865 | ret = 0; |
1865 | else | 1866 | else |