* [PATCH] Restart scsi_device_lookup_by_target
@ 2009-01-13 13:50 Hannes Reinecke
2009-01-13 13:58 ` Matthew Wilcox
2009-01-13 15:22 ` James Bottomley
0 siblings, 2 replies; 9+ messages in thread
From: Hannes Reinecke @ 2009-01-13 13:50 UTC (permalink / raw)
To: James Bottomley; +Cc: SCSI Mailing List
[-- Attachment #1: Type: text/plain, Size: 1344 bytes --]
Hi all,
currently we have this:
struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget,
uint lun)
{
struct scsi_device *sdev;
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
unsigned long flags;
spin_lock_irqsave(shost->host_lock, flags);
sdev = __scsi_device_lookup_by_target(starget, lun);
if (sdev && scsi_device_get(sdev))
sdev = NULL;
spin_unlock_irqrestore(shost->host_lock, flags);
return sdev;
}
now consider an sdev list with two entries for LUN 0, the first
being in SDEV_DEL and the second being in SDEV_RUNNING.
scsi_device_lookup_by_target will always return NULL here, as
it will never be able to skip past the first (unuseable)
entry. So scsi_report_lun_scan will happily create duplicate
sdevs for LUN 0 and we'll be getting the infamous
sysfs: duplicate filename 'xxxx' can not be created
errors.
What we should be doing here is to restart
__scsi_device_lookup_by_target() if we find an
sdev but cannot use it (ie is in SDEV_DEL).
James, please apply.
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Markus Rex, HRB 16746 (AG Nürnberg)
[-- Attachment #2: scsi-restart-lookup-by-target --]
[-- Type: text/plain, Size: 3627 bytes --]
Restart scsi_device_lookup_by_target()
When scsi_device_lookup_by_target() will always return
the first sdev with a matching LUN, regardless of
the state. However, when this sdev is in SDEV_DEL
it's quite possible to have additional sdevs in the
list with the same LUN which are active.
So we should restart __scsi_device_lookup_by_target()
whenever we find an sdev with state SDEV_DEL.
Signed-off-by: Hannes Reinecke <hare@suse.de>
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index 62a4618..ac0488b 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -1158,7 +1158,7 @@ static int esp_reconnect(struct esp *esp)
ESP_BUSID);
tp = &esp->target[target];
- dev = __scsi_device_lookup_by_target(tp->starget, lun);
+ dev = __scsi_device_lookup_by_target(tp->starget, NULL, lun);
if (!dev) {
printk(KERN_ERR PFX "esp%d: Reconnect, no lp "
"tgt[%u] lun[%u]\n",
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index f8b79d4..b2c3c61 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -1094,23 +1094,29 @@ EXPORT_SYMBOL(__starget_for_each_device);
/**
* __scsi_device_lookup_by_target - find a device given the target (UNLOCKED)
* @starget: SCSI target pointer
+ * @sdev: SCSI device pointer
* @lun: SCSI Logical Unit Number
*
* Description: Looks up the scsi_device with the specified @lun for a given
* @starget. The returned scsi_device does not have an additional
* reference. You must hold the host's host_lock over this call and
- * any access to the returned scsi_device.
+ * any access to the returned scsi_device. If @sdev is not NULL use the
+ * specified @sdev as a starting point after which to start the lookup.
*
* Note: The only reason why drivers should use this is because
* they need to access the device list in irq context. Otherwise you
* really want to use scsi_device_lookup_by_target instead.
**/
struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *starget,
+ struct scsi_device *sdev,
uint lun)
{
- struct scsi_device *sdev;
+ if (!sdev)
+ sdev = list_prepare_entry(sdev, &starget->devices,
+ same_target_siblings);
- list_for_each_entry(sdev, &starget->devices, same_target_siblings) {
+ list_for_each_entry_continue(sdev, &starget->devices,
+ same_target_siblings) {
if (sdev->lun ==lun)
return sdev;
}
@@ -1131,14 +1137,15 @@ EXPORT_SYMBOL(__scsi_device_lookup_by_target);
struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget,
uint lun)
{
- struct scsi_device *sdev;
+ struct scsi_device *sdev = NULL;
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
unsigned long flags;
spin_lock_irqsave(shost->host_lock, flags);
- sdev = __scsi_device_lookup_by_target(starget, lun);
+ restart:
+ sdev = __scsi_device_lookup_by_target(starget, sdev, lun);
if (sdev && scsi_device_get(sdev))
- sdev = NULL;
+ goto restart;
spin_unlock_irqrestore(shost->host_lock, flags);
return sdev;
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index bb80937..710f150 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -285,6 +285,7 @@ extern struct scsi_device *__scsi_device_lookup(struct Scsi_Host *,
extern struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *,
uint);
extern struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *,
+ struct scsi_device *,
uint);
extern void starget_for_each_device(struct scsi_target *, void *,
void (*fn)(struct scsi_device *, void *));
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH] Restart scsi_device_lookup_by_target
2009-01-13 13:50 [PATCH] Restart scsi_device_lookup_by_target Hannes Reinecke
@ 2009-01-13 13:58 ` Matthew Wilcox
2009-01-13 14:02 ` Hannes Reinecke
2009-01-13 15:22 ` James Bottomley
1 sibling, 1 reply; 9+ messages in thread
From: Matthew Wilcox @ 2009-01-13 13:58 UTC (permalink / raw)
To: Hannes Reinecke; +Cc: James Bottomley, SCSI Mailing List
On Tue, Jan 13, 2009 at 02:50:30PM +0100, Hannes Reinecke wrote:
> @@ -1131,14 +1137,15 @@ EXPORT_SYMBOL(__scsi_device_lookup_by_target);
> struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget,
> uint lun)
> {
> - struct scsi_device *sdev;
> + struct scsi_device *sdev = NULL;
> struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
> unsigned long flags;
>
> spin_lock_irqsave(shost->host_lock, flags);
> - sdev = __scsi_device_lookup_by_target(starget, lun);
> + restart:
> + sdev = __scsi_device_lookup_by_target(starget, sdev, lun);
> if (sdev && scsi_device_get(sdev))
> - sdev = NULL;
> + goto restart;
> spin_unlock_irqrestore(shost->host_lock, flags);
>
> return sdev;
Backwards jumps are generally disapproved of. How about:
spin_lock_irqsave(shost->host_lock, flags);
for (;;) {
sdev = __scsi_device_lookup_by_target(starget, sdev, lun);
if (!sdev || !scsi_device_get(sdev))
break;
}
spin_unlock_irqrestore(shost->host_lock, flags);
--
Matthew Wilcox Intel Open Source Technology Centre
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours. We can't possibly take such
a retrograde step."
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH] Restart scsi_device_lookup_by_target
2009-01-13 13:58 ` Matthew Wilcox
@ 2009-01-13 14:02 ` Hannes Reinecke
2009-01-13 14:05 ` Hannes Reinecke
2009-01-13 14:11 ` Matthew Wilcox
0 siblings, 2 replies; 9+ messages in thread
From: Hannes Reinecke @ 2009-01-13 14:02 UTC (permalink / raw)
To: SCSI Mailing List
Hi Matthew,
Matthew Wilcox wrote:
> On Tue, Jan 13, 2009 at 02:50:30PM +0100, Hannes Reinecke wrote:
>> @@ -1131,14 +1137,15 @@ EXPORT_SYMBOL(__scsi_device_lookup_by_target);
>> struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget,
>> uint lun)
>> {
>> - struct scsi_device *sdev;
>> + struct scsi_device *sdev = NULL;
>> struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
>> unsigned long flags;
>>
>> spin_lock_irqsave(shost->host_lock, flags);
>> - sdev = __scsi_device_lookup_by_target(starget, lun);
>> + restart:
>> + sdev = __scsi_device_lookup_by_target(starget, sdev, lun);
>> if (sdev && scsi_device_get(sdev))
>> - sdev = NULL;
>> + goto restart;
>> spin_unlock_irqrestore(shost->host_lock, flags);
>>
>> return sdev;
>
> Backwards jumps are generally disapproved of. How about:
>
> spin_lock_irqsave(shost->host_lock, flags);
> for (;;) {
> sdev = __scsi_device_lookup_by_target(starget, sdev, lun);
> if (!sdev || !scsi_device_get(sdev))
> break;
> }
> spin_unlock_irqrestore(shost->host_lock, flags);
>
>
I must say I don't really like the for(;;) construct.
And it's really confusing as we want to find an sdev, so breaking
if it's _not_ found is ... weird.
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Markus Rex, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH] Restart scsi_device_lookup_by_target
2009-01-13 14:02 ` Hannes Reinecke
@ 2009-01-13 14:05 ` Hannes Reinecke
2009-01-13 14:11 ` Matthew Wilcox
1 sibling, 0 replies; 9+ messages in thread
From: Hannes Reinecke @ 2009-01-13 14:05 UTC (permalink / raw)
To: SCSI Mailing List
Hi Matthew,
Hannes Reinecke wrote:
> Matthew Wilcox wrote:
>> On Tue, Jan 13, 2009 at 02:50:30PM +0100, Hannes Reinecke wrote:
>>> @@ -1131,14 +1137,15 @@ EXPORT_SYMBOL(__scsi_device_lookup_by_target);
>>> struct scsi_device *scsi_device_lookup_by_target(struct scsi_target
>>> *starget,
>>> uint lun)
>>> {
>>> - struct scsi_device *sdev;
>>> + struct scsi_device *sdev = NULL;
>>> struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
>>> unsigned long flags;
>>>
>>> spin_lock_irqsave(shost->host_lock, flags);
>>> - sdev = __scsi_device_lookup_by_target(starget, lun);
>>> + restart:
>>> + sdev = __scsi_device_lookup_by_target(starget, sdev, lun);
>>> if (sdev && scsi_device_get(sdev))
>>> - sdev = NULL;
>>> + goto restart;
>>> spin_unlock_irqrestore(shost->host_lock, flags);
>>>
>>> return sdev;
>>
>> Backwards jumps are generally disapproved of. How about:
>>
>> spin_lock_irqsave(shost->host_lock, flags);
>> for (;;) {
>> sdev = __scsi_device_lookup_by_target(starget, sdev, lun);
>> if (!sdev || !scsi_device_get(sdev))
>> break;
>> }
>> spin_unlock_irqrestore(shost->host_lock, flags);
>>
>>
> I must say I don't really like the for(;;) construct.
> And it's really confusing as we want to find an sdev, so breaking
> if it's _not_ found is ... weird.
>
What about
do {
sdev = __scsi_device_lookup_by_target(starget, sdev, lun);
} while (sdev && scsi_device_get(sdev));
?
Should be identical and easier to read ...
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Markus Rex, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH] Restart scsi_device_lookup_by_target
2009-01-13 14:02 ` Hannes Reinecke
2009-01-13 14:05 ` Hannes Reinecke
@ 2009-01-13 14:11 ` Matthew Wilcox
2009-01-13 14:17 ` Hannes Reinecke
1 sibling, 1 reply; 9+ messages in thread
From: Matthew Wilcox @ 2009-01-13 14:11 UTC (permalink / raw)
To: Hannes Reinecke; +Cc: SCSI Mailing List
On Tue, Jan 13, 2009 at 03:02:27PM +0100, Hannes Reinecke wrote:
> Matthew Wilcox wrote:
> >Backwards jumps are generally disapproved of. How about:
> >
> > spin_lock_irqsave(shost->host_lock, flags);
> > for (;;) {
> > sdev = __scsi_device_lookup_by_target(starget, sdev, lun);
> > if (!sdev || !scsi_device_get(sdev))
> > break;
> > }
> > spin_unlock_irqrestore(shost->host_lock, flags);
> I must say I don't really like the for(;;) construct.
I'd be fine with:
do {
sdev = __scsi_device_lookup_by_target(starget, sdev, lun);
} while (sdev && scsi_device_get(sdev));
though I find that slightly less clear than the for (;;) construct.
> And it's really confusing as we want to find an sdev, so breaking
> if it's _not_ found is ... weird.
Those are the two conditions when we want to stop trying -- if there's
no device or if the device we've found is bad. I can definitely see an
argument for splitting the two conditions to make that more obvious. I
can also see an argument for not returning an sdev in the _DEL state
from __scsi_device_lookup_by_target in the first place.
--
Matthew Wilcox Intel Open Source Technology Centre
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours. We can't possibly take such
a retrograde step."
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH] Restart scsi_device_lookup_by_target
2009-01-13 14:11 ` Matthew Wilcox
@ 2009-01-13 14:17 ` Hannes Reinecke
0 siblings, 0 replies; 9+ messages in thread
From: Hannes Reinecke @ 2009-01-13 14:17 UTC (permalink / raw)
To: Matthew Wilcox; +Cc: SCSI Mailing List, James Bottomley
Hi Matthew,
Matthew Wilcox wrote:
> On Tue, Jan 13, 2009 at 03:02:27PM +0100, Hannes Reinecke wrote:
>> Matthew Wilcox wrote:
>>> Backwards jumps are generally disapproved of. How about:
>>>
>>> spin_lock_irqsave(shost->host_lock, flags);
>>> for (;;) {
>>> sdev = __scsi_device_lookup_by_target(starget, sdev, lun);
>>> if (!sdev || !scsi_device_get(sdev))
>>> break;
>>> }
>>> spin_unlock_irqrestore(shost->host_lock, flags);
>
>> I must say I don't really like the for(;;) construct.
>
> I'd be fine with:
>
> do {
> sdev = __scsi_device_lookup_by_target(starget, sdev, lun);
> } while (sdev && scsi_device_get(sdev));
>
> though I find that slightly less clear than the for (;;) construct.
>
Opinons differ.
Something for the maintainer to decide. James?
>> And it's really confusing as we want to find an sdev, so breaking
>> if it's _not_ found is ... weird.
>
> Those are the two conditions when we want to stop trying -- if there's
> no device or if the device we've found is bad. I can definitely see an
> argument for splitting the two conditions to make that more obvious. I
> can also see an argument for not returning an sdev in the _DEL state
> from __scsi_device_lookup_by_target in the first place.
>
Not sure if that would work with esp_scsi.c (the other user of
__scsi_device_lookup_by_target()).
And don't have a device to try it with.
But modifying __scsi_device_lookup_by_target() would alter the behaviour,
whereas this patch does not.
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Markus Rex, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] Restart scsi_device_lookup_by_target
2009-01-13 13:50 [PATCH] Restart scsi_device_lookup_by_target Hannes Reinecke
2009-01-13 13:58 ` Matthew Wilcox
@ 2009-01-13 15:22 ` James Bottomley
2009-01-13 15:28 ` Hannes Reinecke
1 sibling, 1 reply; 9+ messages in thread
From: James Bottomley @ 2009-01-13 15:22 UTC (permalink / raw)
To: Hannes Reinecke; +Cc: SCSI Mailing List
On Tue, 2009-01-13 at 14:50 +0100, Hannes Reinecke wrote:
> Hi all,
>
> currently we have this:
>
> struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget,
> uint lun)
> {
> struct scsi_device *sdev;
> struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
> unsigned long flags;
>
> spin_lock_irqsave(shost->host_lock, flags);
> sdev = __scsi_device_lookup_by_target(starget, lun);
> if (sdev && scsi_device_get(sdev))
> sdev = NULL;
> spin_unlock_irqrestore(shost->host_lock, flags);
>
> return sdev;
> }
>
> now consider an sdev list with two entries for LUN 0, the first
> being in SDEV_DEL and the second being in SDEV_RUNNING.
>
> scsi_device_lookup_by_target will always return NULL here, as
> it will never be able to skip past the first (unuseable)
> entry. So scsi_report_lun_scan will happily create duplicate
> sdevs for LUN 0 and we'll be getting the infamous
>
> sysfs: duplicate filename 'xxxx' can not be created
>
> errors.
>
> What we should be doing here is to restart
> __scsi_device_lookup_by_target() if we find an
> sdev but cannot use it (ie is in SDEV_DEL).
>
> James, please apply.
>
> Cheers,
>
> Hannes
> plain text document attachment (scsi-restart-lookup-by-target)
> Restart scsi_device_lookup_by_target()
>
> When scsi_device_lookup_by_target() will always return
> the first sdev with a matching LUN, regardless of
> the state. However, when this sdev is in SDEV_DEL
> it's quite possible to have additional sdevs in the
> list with the same LUN which are active.
> So we should restart __scsi_device_lookup_by_target()
> whenever we find an sdev with state SDEV_DEL.
>
> Signed-off-by: Hannes Reinecke <hare@suse.de>
That's brilliant, thanks for finding this bug.
rather than go to the trouble of restarting the scan looking for
duplicates, since none of the users of __scsi_device_lookup_by_target
actually want invisible dying devices in SDEV_DEL, why not just make it
skip over them. If we ignore devices in SDEV_DEL, the target id of the
visible devices should all be unique, so alter the
if (sdev->lun == lun)
to
if (sdev->lun == lun && sdev->sdev_state != SDEV_DEL)
And everything should work.
I think this is the correct fix because scsi_device_get() is also
programmed to ignore devices in SDEV_DEL (for the same reason).
James
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH] Restart scsi_device_lookup_by_target
2009-01-13 15:22 ` James Bottomley
@ 2009-01-13 15:28 ` Hannes Reinecke
2009-01-13 15:32 ` James Bottomley
0 siblings, 1 reply; 9+ messages in thread
From: Hannes Reinecke @ 2009-01-13 15:28 UTC (permalink / raw)
To: James Bottomley; +Cc: SCSI Mailing List
Hi James,
James Bottomley wrote:
> On Tue, 2009-01-13 at 14:50 +0100, Hannes Reinecke wrote:
>> Hi all,
>>
>> currently we have this:
>>
>> struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget,
>> uint lun)
>> {
>> struct scsi_device *sdev;
>> struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
>> unsigned long flags;
>>
>> spin_lock_irqsave(shost->host_lock, flags);
>> sdev = __scsi_device_lookup_by_target(starget, lun);
>> if (sdev && scsi_device_get(sdev))
>> sdev = NULL;
>> spin_unlock_irqrestore(shost->host_lock, flags);
>>
>> return sdev;
>> }
>>
>> now consider an sdev list with two entries for LUN 0, the first
>> being in SDEV_DEL and the second being in SDEV_RUNNING.
>>
>> scsi_device_lookup_by_target will always return NULL here, as
>> it will never be able to skip past the first (unuseable)
>> entry. So scsi_report_lun_scan will happily create duplicate
>> sdevs for LUN 0 and we'll be getting the infamous
>>
>> sysfs: duplicate filename 'xxxx' can not be created
>>
>> errors.
>>
>> What we should be doing here is to restart
>> __scsi_device_lookup_by_target() if we find an
>> sdev but cannot use it (ie is in SDEV_DEL).
>>
>> James, please apply.
>>
>> Cheers,
>>
>> Hannes
>> plain text document attachment (scsi-restart-lookup-by-target)
>> Restart scsi_device_lookup_by_target()
>>
>> When scsi_device_lookup_by_target() will always return
>> the first sdev with a matching LUN, regardless of
>> the state. However, when this sdev is in SDEV_DEL
>> it's quite possible to have additional sdevs in the
>> list with the same LUN which are active.
>> So we should restart __scsi_device_lookup_by_target()
>> whenever we find an sdev with state SDEV_DEL.
>>
>> Signed-off-by: Hannes Reinecke <hare@suse.de>
>
> That's brilliant, thanks for finding this bug.
>
> rather than go to the trouble of restarting the scan looking for
> duplicates, since none of the users of __scsi_device_lookup_by_target
> actually want invisible dying devices in SDEV_DEL, why not just make it
> skip over them. If we ignore devices in SDEV_DEL, the target id of the
> visible devices should all be unique, so alter the
>
> if (sdev->lun == lun)
>
> to
>
> if (sdev->lun == lun && sdev->sdev_state != SDEV_DEL)
>
> And everything should work.
>
> I think this is the correct fix because scsi_device_get() is also
> programmed to ignore devices in SDEV_DEL (for the same reason).
>
As already mentioned, I'm not sure if esp_scsi.c expects it to
be that way. If someone confirms that we won't break it with this
change, then of course it's the easier way.
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Markus Rex, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH] Restart scsi_device_lookup_by_target
2009-01-13 15:28 ` Hannes Reinecke
@ 2009-01-13 15:32 ` James Bottomley
0 siblings, 0 replies; 9+ messages in thread
From: James Bottomley @ 2009-01-13 15:32 UTC (permalink / raw)
To: Hannes Reinecke; +Cc: SCSI Mailing List
On Tue, 2009-01-13 at 16:28 +0100, Hannes Reinecke wrote:
> Hi James,
>
> James Bottomley wrote:
> > On Tue, 2009-01-13 at 14:50 +0100, Hannes Reinecke wrote:
> >> Hi all,
> >>
> >> currently we have this:
> >>
> >> struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget,
> >> uint lun)
> >> {
> >> struct scsi_device *sdev;
> >> struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
> >> unsigned long flags;
> >>
> >> spin_lock_irqsave(shost->host_lock, flags);
> >> sdev = __scsi_device_lookup_by_target(starget, lun);
> >> if (sdev && scsi_device_get(sdev))
> >> sdev = NULL;
> >> spin_unlock_irqrestore(shost->host_lock, flags);
> >>
> >> return sdev;
> >> }
> >>
> >> now consider an sdev list with two entries for LUN 0, the first
> >> being in SDEV_DEL and the second being in SDEV_RUNNING.
> >>
> >> scsi_device_lookup_by_target will always return NULL here, as
> >> it will never be able to skip past the first (unuseable)
> >> entry. So scsi_report_lun_scan will happily create duplicate
> >> sdevs for LUN 0 and we'll be getting the infamous
> >>
> >> sysfs: duplicate filename 'xxxx' can not be created
> >>
> >> errors.
> >>
> >> What we should be doing here is to restart
> >> __scsi_device_lookup_by_target() if we find an
> >> sdev but cannot use it (ie is in SDEV_DEL).
> >>
> >> James, please apply.
> >>
> >> Cheers,
> >>
> >> Hannes
> >> plain text document attachment (scsi-restart-lookup-by-target)
> >> Restart scsi_device_lookup_by_target()
> >>
> >> When scsi_device_lookup_by_target() will always return
> >> the first sdev with a matching LUN, regardless of
> >> the state. However, when this sdev is in SDEV_DEL
> >> it's quite possible to have additional sdevs in the
> >> list with the same LUN which are active.
> >> So we should restart __scsi_device_lookup_by_target()
> >> whenever we find an sdev with state SDEV_DEL.
> >>
> >> Signed-off-by: Hannes Reinecke <hare@suse.de>
> >
> > That's brilliant, thanks for finding this bug.
> >
> > rather than go to the trouble of restarting the scan looking for
> > duplicates, since none of the users of __scsi_device_lookup_by_target
> > actually want invisible dying devices in SDEV_DEL, why not just make it
> > skip over them. If we ignore devices in SDEV_DEL, the target id of the
> > visible devices should all be unique, so alter the
> >
> > if (sdev->lun == lun)
> >
> > to
> >
> > if (sdev->lun == lun && sdev->sdev_state != SDEV_DEL)
> >
> > And everything should work.
> >
> > I think this is the correct fix because scsi_device_get() is also
> > programmed to ignore devices in SDEV_DEL (for the same reason).
> >
> As already mentioned, I'm not sure if esp_scsi.c expects it to
> be that way. If someone confirms that we won't break it with this
> change, then of course it's the easier way.
I did check esp ... it's looking for the hostdata in the device, so
returning a SDEV_DEL device to it while another is in the list will
really confuse it, because it will have a stale (and possibly freed)
hostdata structure, so checking for SDEV_DEL will correct a potential
bug in it as well ... that's why I was suggesting this way. All of the
users are expecting live and visible devices.
James
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2009-01-13 15:32 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-01-13 13:50 [PATCH] Restart scsi_device_lookup_by_target Hannes Reinecke
2009-01-13 13:58 ` Matthew Wilcox
2009-01-13 14:02 ` Hannes Reinecke
2009-01-13 14:05 ` Hannes Reinecke
2009-01-13 14:11 ` Matthew Wilcox
2009-01-13 14:17 ` Hannes Reinecke
2009-01-13 15:22 ` James Bottomley
2009-01-13 15:28 ` Hannes Reinecke
2009-01-13 15:32 ` James Bottomley
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox