From 4356d0b64b9be53c507f66c572c1e275b4529239 Mon Sep 17 00:00:00 2001
From: Ram Vepa <ram.vepa@qlogic.com>
Date: Fri, 27 May 2011 13:41:55 +0000
Subject: IB/qib: Fix potential deadlock with link down interrupt
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Git-commit: 4356d0b64b9be53c507f66c572c1e275b4529239
Patch-mainline: Queued in subsystem maintainer repo
References: bnc#780244,FATE#314303

There is a possibility of a deadlock due to the way locks are
acquired and released in qib_set_uevent_bits(). The function
qib_set_uevent_bits() is called in process context and it uses
spin_lock() and spin_unlock().  This same lock is acquired/released
in interrupt context which can lead to a deadlock when running on
the same cpu.

The fix is to replace spin_lock() and spin_unlock() with
spin_lock_irqsave() and spin_unlock_irqrestore() respectively in
qib_set_uevent_bits().

Signed-off-by: Mike Marciniszyn <mike.marciniszyn@qlogic.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
Acked-by: Dean Luick <dean.luick@intel.com>
Acked-by: John Jolly <jjolly@suse.de>
---

 drivers/infiniband/hw/qib/qib_file_ops.c |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

--- a/drivers/infiniband/hw/qib/qib_file_ops.c
+++ b/drivers/infiniband/hw/qib/qib_file_ops.c
@@ -1905,8 +1905,9 @@ int qib_set_uevent_bits(struct qib_pportdata *ppd, const int evtbit)
 	struct qib_ctxtdata *rcd;
 	unsigned ctxt;
 	int ret = 0;
+	unsigned long flags;
 
-	spin_lock(&ppd->dd->uctxt_lock);
+	spin_lock_irqsave(&ppd->dd->uctxt_lock, flags);
 	for (ctxt = ppd->dd->first_user_ctxt; ctxt < ppd->dd->cfgctxts;
 	     ctxt++) {
 		rcd = ppd->dd->rcd[ctxt];
@@ -1925,7 +1926,7 @@ int qib_set_uevent_bits(struct qib_pportdata *ppd, const int evtbit)
 		ret = 1;
 		break;
 	}
-	spin_unlock(&ppd->dd->uctxt_lock);
+	spin_unlock_irqrestore(&ppd->dd->uctxt_lock, flags);
 
 	return ret;
 }


