Commit e14ac670 authored by scameron@beardog.cca.cpqcorp.net's avatar scameron@beardog.cca.cpqcorp.net Committed by Jens Axboe

cciss: Fix race between disk-adding code and interrupt handler

Fix race condition between cciss_init_one(), cciss_update_drive_info(),
and cciss_check_queues().
Signed-off-by: default avatarStephen M. Cameron <scameron@beardog.cca.cpqcorp.net>
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent f18573ab
...@@ -1349,6 +1349,10 @@ static void cciss_update_drive_info(int ctlr, int drv_index) ...@@ -1349,6 +1349,10 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
h->drv[drv_index].busy_configuring = 1; h->drv[drv_index].busy_configuring = 1;
spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); 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], ret = deregister_disk(h->gendisk[drv_index],
&h->drv[drv_index], 0); &h->drv[drv_index], 0);
h->drv[drv_index].busy_configuring = 0; h->drv[drv_index].busy_configuring = 0;
...@@ -1419,6 +1423,10 @@ geo_inq: ...@@ -1419,6 +1423,10 @@ geo_inq:
blk_queue_hardsect_size(disk->queue, blk_queue_hardsect_size(disk->queue,
hba[ctlr]->drv[drv_index].block_size); 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; h->drv[drv_index].queue = disk->queue;
add_disk(disk); add_disk(disk);
} }
...@@ -3520,10 +3528,17 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, ...@@ -3520,10 +3528,17 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
continue; continue;
blk_queue_hardsect_size(q, drv->block_size); blk_queue_hardsect_size(q, drv->block_size);
set_capacity(disk, drv->nr_blocks); set_capacity(disk, drv->nr_blocks);
add_disk(disk);
j++; j++;
} while (j <= hba[i]->highest_lun); } 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]);
return 1; return 1;
clean4: clean4:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment