Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 3343

kernel-2.6.18-194.11.1.el5.src.rpm

From: Tomas Henzl <thenzl@redhat.com>
Date: Wed, 8 Jul 2009 18:50:27 +0300
Subject: [scsi] cciss: fix spinlock
Message-id: 4A54C043.8020008@redhat.com
O-Subject: [RHEL 5.4 PATCH] cciss fix spinlock
Bugzilla: 509818
RH-Acked-by: Pete Zaitcev <zaitcev@redhat.com>
RH-Acked-by: Jiri Pirko <jpirko@redhat.com>
RH-Acked-by: Mike Christie <mchristi@redhat.com>
RH-Acked-by: Prarit Bhargava <prarit@redhat.com>

cciss: controller cciss0 failed, stopping.
cciss0: controller not responding.
NMI Watchdog detected LOCKUP, CPU=6, registers:
...
This deadlock has been found thanks to Prarit during RHEL4 testing.
The same deadlock path exists in both RHEL4 and RHEL5 codebase.

fail_all_cmds is called (only) from do_cciss_intr with
spinlock acquired.
So when in an error-handling situation,
fail_all_cmds() is called it attempts to *reacquire* the lock.

This patch removes the spinlock lock/unlock from fail_all_cmds and adds a
spin_unlock after the call to fail_all_cmds before return.

This code path seems to be used only rarely,
"If we get here, the board is apparently dead."
The same problem is in upstream from 2005.

Brew taskID=1877701
Compile/boot tested.

BZ#509818

Tomas

diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 19aaf54..6d2bd61 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -3042,6 +3042,7 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
 					       "cciss: controller cciss%d failed, stopping.\n",
 					       h->ctlr);
 					fail_all_cmds(h->ctlr);
+					spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
 					return IRQ_HANDLED;
 				}
 
@@ -4070,8 +4071,6 @@ static void fail_all_cmds(unsigned long ctlr)
 	printk(KERN_WARNING "cciss%d: controller not responding.\n", h->ctlr);
 	h->alive = 0;		/* the controller apparently died... */
 
-	spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
-
 	pci_disable_device(h->pdev);	/* Make sure it is really dead. */
 
 	/* move everything off the request queue onto the completed queue */
@@ -4094,7 +4093,6 @@ static void fail_all_cmds(unsigned long ctlr)
 			complete_scsi_command(c, 0, 0);
 #endif
 	}
-	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
 	return;
 }