This corrects the kobject_add -EEXIST failure reported in 
http://marc.info/?l=linux-scsi&m=117699334422336&w=2

Basically, there was a collision between async scsi scan's
scsi_sysfs_add_devices() and asynchronous scanning kicked off by the
fc transport's rport code.  Both called scsi_sysfs_add_sdev() for the
same sdev.

The problem was that async scsi scan's call did not hold the scan_mutex
when making the call to scsi_sysfs_add_sdev().  Additionally, looking at
the shost->async_scan flag, which is critical for whether the sdev gets
enumerated or not, many uses were fuzzy. As a bit flag, it should have
been under the scsi_host lock, but via the way it's used within
scsi_scan.c, it should have been under the scan_mutex. It was positioned
within the async scan semaphore, which didn't help anything. Key to its
change, is that is done prior to releasing the scan_mutex after around
the scsi_sysfs_add_sdev() calls.  To avoid all the lock repositioning,
I simply converted it to an atomic. A little overkill, but has the
coherency it needs.

Confirmed by Josef that it corrected his problems.

-- james s


Signed-off-by: James Smart <[EMAIL PROTECTED]>



diff -upNr a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
--- a/drivers/scsi/scsi_scan.c  2007-04-25 23:08:32.000000000 -0400
+++ b/drivers/scsi/scsi_scan.c  2007-05-04 18:35:58.000000000 -0400
@@ -1081,7 +1081,8 @@ static int scsi_probe_and_add_lun(struct
                goto out_free_result;
        }
 
-       res = scsi_add_lun(sdev, result, &bflags, shost->async_scan);
+       res = scsi_add_lun(sdev, result, &bflags,
+                               atomic_read(&shost->async_scan));
        if (res == SCSI_SCAN_LUN_PRESENT) {
                if (bflags & BLIST_KEY) {
                        sdev->lockable = 0;
@@ -1470,7 +1471,7 @@ struct scsi_device *__scsi_add_device(st
        if (strncmp(scsi_scan_type, "none", 4) == 0)
                return ERR_PTR(-ENODEV);
 
-       if (!shost->async_scan)
+       if (!atomic_read(&shost->async_scan))
                scsi_complete_async_scans();
 
        starget = scsi_alloc_target(parent, channel, id);
@@ -1590,7 +1591,7 @@ void scsi_scan_target(struct device *par
        if (strncmp(scsi_scan_type, "none", 4) == 0)
                return;
 
-       if (!shost->async_scan)
+       if (!atomic_read(&shost->async_scan))
                scsi_complete_async_scans();
 
        mutex_lock(&shost->scan_mutex);
@@ -1638,7 +1639,7 @@ int scsi_scan_host_selected(struct Scsi_
                "%s: <%u:%u:%u>\n",
                __FUNCTION__, channel, id, lun));
 
-       if (!shost->async_scan)
+       if (!atomic_read(&shost->async_scan))
                scsi_complete_async_scans();
 
        if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
@@ -1687,7 +1688,7 @@ static struct async_scan_data *scsi_prep
        if (strncmp(scsi_scan_type, "sync", 4) == 0)
                return NULL;
 
-       if (shost->async_scan) {
+       if (atomic_read(&shost->async_scan)) {
                printk("%s called twice for host %d", __FUNCTION__,
                                shost->host_no);
                dump_stack();
@@ -1702,8 +1703,9 @@ static struct async_scan_data *scsi_prep
                goto err;
        init_completion(&data->prev_finished);
 
+       atomic_set(&shost->async_scan, 1);
+
        spin_lock(&async_scan_lock);
-       shost->async_scan = 1;
        if (list_empty(&scanning_hosts))
                complete(&data->prev_finished);
        list_add_tail(&data->list, &scanning_hosts);
@@ -1732,7 +1734,7 @@ static void scsi_finish_async_scan(struc
                return;
 
        shost = data->shost;
-       if (!shost->async_scan) {
+       if (!atomic_read(&shost->async_scan)) {
                printk("%s called twice for host %d", __FUNCTION__,
                                shost->host_no);
                dump_stack();
@@ -1741,10 +1743,12 @@ static void scsi_finish_async_scan(struc
 
        wait_for_completion(&data->prev_finished);
 
+       mutex_lock(&shost->scan_mutex);
        scsi_sysfs_add_devices(shost);
+       atomic_set(&shost->async_scan, 0);
+       mutex_unlock(&shost->scan_mutex);
 
        spin_lock(&async_scan_lock);
-       shost->async_scan = 0;
        list_del(&data->list);
        if (!list_empty(&scanning_hosts)) {
                struct async_scan_data *next = list_entry(scanning_hosts.next,
diff -upNr a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
--- a/include/scsi/scsi_host.h  2007-04-25 23:08:32.000000000 -0400
+++ b/include/scsi/scsi_host.h  2007-05-04 17:48:48.000000000 -0400
@@ -6,6 +6,7 @@
 #include <linux/types.h>
 #include <linux/workqueue.h>
 #include <linux/mutex.h>
+#include <asm/atomic.h>
 
 struct request_queue;
 struct block_device;
@@ -605,7 +606,7 @@ struct Scsi_Host {
        unsigned tmf_in_progress:1;
 
        /* Asynchronous scan in progress */
-       unsigned async_scan:1;
+       atomic_t async_scan;
 
        /*
         * Optional work queue to be utilized by the transport




-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to