aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorMatthew Wilcox <matthew@wil.cx>2007-06-26 17:18:51 -0400
committerJames Bottomley <jejb@mulgrave.localdomain>2007-10-12 14:38:24 -0400
commit6b7f123f378743d739377871c0cbfbaf28c7d25a (patch)
treeada283aaa62629e09b9edb7c351eaa62cdf3ccce /drivers/scsi
parentafd9a033ca1354e95c95201f5d21a097da9f7fb2 (diff)
[SCSI] Fix async scanning double-add problems
Stress-testing and some thought has revealed some places where asynchronous scanning needs some more attention to locking. - Since async_scan is a bit, we need to hold the host_lock while modifying it to prevent races against other CPUs modifying the word that bit is in. This is probably a theoretical race for the moment, but other patches may change that. - The async_scan bit means not only that this host is being scanned asynchronously, but that all the devices attached to this host are not yet added to sysfs. So we must ensure that this bit is always in sync. I've chosen to do this with the scan_mutex since it's already acquired in most of the right places. - If the host changes state to deleted while we're in the middle of a scan, we'll end up with some devices on the host's list which must be deleted. Add a check to scsi_sysfs_add_devices() to ensure the host is still running. - To avoid the async_scan bit being protected by three locks, the async_scan_lock now only protects the scanning_list. Signed-off-by: Matthew Wilcox <matthew@wil.cx> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/scsi_scan.c37
1 files changed, 27 insertions, 10 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index a86e62f4b3ba..309b2246d2d3 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -121,6 +121,7 @@ MODULE_PARM_DESC(inq_timeout,
121 "Timeout (in seconds) waiting for devices to answer INQUIRY." 121 "Timeout (in seconds) waiting for devices to answer INQUIRY."
122 " Default is 5. Some non-compliant devices need more."); 122 " Default is 5. Some non-compliant devices need more.");
123 123
124/* This lock protects only this list */
124static DEFINE_SPINLOCK(async_scan_lock); 125static DEFINE_SPINLOCK(async_scan_lock);
125static LIST_HEAD(scanning_hosts); 126static LIST_HEAD(scanning_hosts);
126 127
@@ -1466,14 +1467,14 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
1466 if (strncmp(scsi_scan_type, "none", 4) == 0) 1467 if (strncmp(scsi_scan_type, "none", 4) == 0)
1467 return ERR_PTR(-ENODEV); 1468 return ERR_PTR(-ENODEV);
1468 1469
1469 if (!shost->async_scan)
1470 scsi_complete_async_scans();
1471
1472 starget = scsi_alloc_target(parent, channel, id); 1470 starget = scsi_alloc_target(parent, channel, id);
1473 if (!starget) 1471 if (!starget)
1474 return ERR_PTR(-ENOMEM); 1472 return ERR_PTR(-ENOMEM);
1475 1473
1476 mutex_lock(&shost->scan_mutex); 1474 mutex_lock(&shost->scan_mutex);
1475 if (!shost->async_scan)
1476 scsi_complete_async_scans();
1477
1477 if (scsi_host_scan_allowed(shost)) 1478 if (scsi_host_scan_allowed(shost))
1478 scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); 1479 scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
1479 mutex_unlock(&shost->scan_mutex); 1480 mutex_unlock(&shost->scan_mutex);
@@ -1586,10 +1587,10 @@ void scsi_scan_target(struct device *parent, unsigned int channel,
1586 if (strncmp(scsi_scan_type, "none", 4) == 0) 1587 if (strncmp(scsi_scan_type, "none", 4) == 0)
1587 return; 1588 return;
1588 1589
1590 mutex_lock(&shost->scan_mutex);
1589 if (!shost->async_scan) 1591 if (!shost->async_scan)
1590 scsi_complete_async_scans(); 1592 scsi_complete_async_scans();
1591 1593
1592 mutex_lock(&shost->scan_mutex);
1593 if (scsi_host_scan_allowed(shost)) 1594 if (scsi_host_scan_allowed(shost))
1594 __scsi_scan_target(parent, channel, id, lun, rescan); 1595 __scsi_scan_target(parent, channel, id, lun, rescan);
1595 mutex_unlock(&shost->scan_mutex); 1596 mutex_unlock(&shost->scan_mutex);
@@ -1634,15 +1635,15 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
1634 "%s: <%u:%u:%u>\n", 1635 "%s: <%u:%u:%u>\n",
1635 __FUNCTION__, channel, id, lun)); 1636 __FUNCTION__, channel, id, lun));
1636 1637
1637 if (!shost->async_scan)
1638 scsi_complete_async_scans();
1639
1640 if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) || 1638 if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
1641 ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) || 1639 ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) ||
1642 ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun))) 1640 ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
1643 return -EINVAL; 1641 return -EINVAL;
1644 1642
1645 mutex_lock(&shost->scan_mutex); 1643 mutex_lock(&shost->scan_mutex);
1644 if (!shost->async_scan)
1645 scsi_complete_async_scans();
1646
1646 if (scsi_host_scan_allowed(shost)) { 1647 if (scsi_host_scan_allowed(shost)) {
1647 if (channel == SCAN_WILD_CARD) 1648 if (channel == SCAN_WILD_CARD)
1648 for (channel = 0; channel <= shost->max_channel; 1649 for (channel = 0; channel <= shost->max_channel;
@@ -1661,7 +1662,8 @@ static void scsi_sysfs_add_devices(struct Scsi_Host *shost)
1661{ 1662{
1662 struct scsi_device *sdev; 1663 struct scsi_device *sdev;
1663 shost_for_each_device(sdev, shost) { 1664 shost_for_each_device(sdev, shost) {
1664 if (scsi_sysfs_add_sdev(sdev) != 0) 1665 if (!scsi_host_scan_allowed(shost) ||
1666 scsi_sysfs_add_sdev(sdev) != 0)
1665 scsi_destroy_sdev(sdev); 1667 scsi_destroy_sdev(sdev);
1666 } 1668 }
1667} 1669}
@@ -1679,6 +1681,7 @@ static void scsi_sysfs_add_devices(struct Scsi_Host *shost)
1679static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost) 1681static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
1680{ 1682{
1681 struct async_scan_data *data; 1683 struct async_scan_data *data;
1684 unsigned long flags;
1682 1685
1683 if (strncmp(scsi_scan_type, "sync", 4) == 0) 1686 if (strncmp(scsi_scan_type, "sync", 4) == 0)
1684 return NULL; 1687 return NULL;
@@ -1698,8 +1701,13 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
1698 goto err; 1701 goto err;
1699 init_completion(&data->prev_finished); 1702 init_completion(&data->prev_finished);
1700 1703
1701 spin_lock(&async_scan_lock); 1704 mutex_lock(&shost->scan_mutex);
1705 spin_lock_irqsave(shost->host_lock, flags);
1702 shost->async_scan = 1; 1706 shost->async_scan = 1;
1707 spin_unlock_irqrestore(shost->host_lock, flags);
1708 mutex_unlock(&shost->scan_mutex);
1709
1710 spin_lock(&async_scan_lock);
1703 if (list_empty(&scanning_hosts)) 1711 if (list_empty(&scanning_hosts))
1704 complete(&data->prev_finished); 1712 complete(&data->prev_finished);
1705 list_add_tail(&data->list, &scanning_hosts); 1713 list_add_tail(&data->list, &scanning_hosts);
@@ -1723,11 +1731,15 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
1723static void scsi_finish_async_scan(struct async_scan_data *data) 1731static void scsi_finish_async_scan(struct async_scan_data *data)
1724{ 1732{
1725 struct Scsi_Host *shost; 1733 struct Scsi_Host *shost;
1734 unsigned long flags;
1726 1735
1727 if (!data) 1736 if (!data)
1728 return; 1737 return;
1729 1738
1730 shost = data->shost; 1739 shost = data->shost;
1740
1741 mutex_lock(&shost->scan_mutex);
1742
1731 if (!shost->async_scan) { 1743 if (!shost->async_scan) {
1732 printk("%s called twice for host %d", __FUNCTION__, 1744 printk("%s called twice for host %d", __FUNCTION__,
1733 shost->host_no); 1745 shost->host_no);
@@ -1739,8 +1751,13 @@ static void scsi_finish_async_scan(struct async_scan_data *data)
1739 1751
1740 scsi_sysfs_add_devices(shost); 1752 scsi_sysfs_add_devices(shost);
1741 1753
1742 spin_lock(&async_scan_lock); 1754 spin_lock_irqsave(shost->host_lock, flags);
1743 shost->async_scan = 0; 1755 shost->async_scan = 0;
1756 spin_unlock_irqrestore(shost->host_lock, flags);
1757
1758 mutex_unlock(&shost->scan_mutex);
1759
1760 spin_lock(&async_scan_lock);
1744 list_del(&data->list); 1761 list_del(&data->list);
1745 if (!list_empty(&scanning_hosts)) { 1762 if (!list_empty(&scanning_hosts)) {
1746 struct async_scan_data *next = list_entry(scanning_hosts.next, 1763 struct async_scan_data *next = list_entry(scanning_hosts.next,