aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c49
-rw-r--r--drivers/infiniband/hw/ipath/ipath_file_ops.c21
-rw-r--r--drivers/infiniband/hw/ipath/ipath_init_chip.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_kernel.h2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_keys.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mad.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.c3
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:
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
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 */
349static int get_pkeys(struct ipath_devdata *dd, u16 * pkeys) 349static 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