Sophie

Sophie

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

kernel-2.6.18-194.11.1.el5.src.rpm

From: Ivan Vecera <ivecera@redhat.com>
Date: Tue, 19 Aug 2008 11:44:32 +0200
Subject: [scsi] cciss: possible race condition during init
Message-id: 48AA9600.6070400@redhat.com
O-Subject: [RHEL5 PATCH] Possible race condition in cciss
Bugzilla: 455663
RH-Acked-by: David Milburn <dmilburn@redhat.com>
RH-Acked-by: David Milburn <dmilburn@redhat.com>
RH-Acked-by: David Milburn <dmilburn@redhat.com>
RH-Acked-by: David Milburn <dmilburn@redhat.com>
RH-Acked-by: John Feeney <jfeeney@redhat.com>
RH-Acked-by: John Feeney <jfeeney@redhat.com>
RH-Acked-by: Anton Arapov <aarapov@redhat.com>
RH-Acked-by: Tomas Henzl <thenzl@redhat.com>

BZ: https://bugzilla.redhat.com/show_bug.cgi?id=455663

Description:
There is a potential race condition during init where the interrupt handler
may fire on a queue that has not been completely set up. The results is a kernel
panic.

Testing status:
Patched kernel was tested by the bug reporter. No problems found.

Upstream status:
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=e14ac67026b46e94478134df9521682fc6501ac0
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=77b96bd7e5ee0b44aed1b77fef5949bc19e8301f

Please review the patch below.

Regards,
Ivan

===

diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 93a247c..a108669 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -1364,6 +1364,10 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
 		spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
 		h->drv[drv_index].busy_configuring = 1;
 		spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+
+		/* deregister_disk sets h->drv[drv_index].queue = NULL */
+		/* which keeps the interrupt handler from starting */
+		/* the queue. */
 		ret = deregister_disk(h->gendisk[drv_index],
 				      &h->drv[drv_index], 0);
 		h->drv[drv_index].busy_configuring = 0;
@@ -1434,6 +1438,10 @@ geo_inq:
 		blk_queue_hardsect_size(disk->queue,
 					hba[ctlr]->drv[drv_index].block_size);
 
+		/* Make sure all queue data is written out before */
+		/* setting h->drv[drv_index].queue, as setting this */
+		/* allows the interrupt handler to start the queue */
+		wmb();
 		h->drv[drv_index].queue = disk->queue;
 		add_disk(disk);
 	}
@@ -3677,10 +3685,21 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
 			continue;
 		blk_queue_hardsect_size(q, drv->block_size);
 		set_capacity(disk, drv->nr_blocks);
-		add_disk(disk);
 		j++;
 	} while (j <= hba[i]->highest_lun);
 
+	/* Make sure all queue data is written out before */
+	/* interrupt handler, triggered by add_disk,  */
+	/* is allowed to start them. */
+	wmb();
+
+	for (j = 0; j <= hba[i]->highest_lun; j++)
+		add_disk(hba[i]->gendisk[j]);
+
+	/* we must register the controller even if no disks exist */
+	if (hba[i]->highest_lun == -1)
+		add_disk(hba[i]->gendisk[0]);
+
 	return 1;
 
       clean4: