提交 f2495e22 编写于 作者: J James Bottomley

[SCSI] dual scan thread bug fix

In the highly unusual case where two threads are running concurrently through
the scanning code scanning the same target, we run into the situation where
one may allocate the target while the other is still using it.  In this case,
because the reap checks for STARGET_CREATED and kills the target without
reference counting, the second thread will do the wrong thing on reap.

Fix this by reference counting even creates and doing the STARGET_CREATED
check in the final put.
Tested-by: NSarah Sharp <sarah.a.sharp@linux.intel.com>
Cc: stable@vger.kernel.org # delay backport for 2 months for field testing
Signed-off-by: NJames Bottomley <JBottomley@Parallels.com>
上级 e63ed0d7
...@@ -320,6 +320,7 @@ static void scsi_target_destroy(struct scsi_target *starget) ...@@ -320,6 +320,7 @@ static void scsi_target_destroy(struct scsi_target *starget)
struct Scsi_Host *shost = dev_to_shost(dev->parent); struct Scsi_Host *shost = dev_to_shost(dev->parent);
unsigned long flags; unsigned long flags;
starget->state = STARGET_DEL;
transport_destroy_device(dev); transport_destroy_device(dev);
spin_lock_irqsave(shost->host_lock, flags); spin_lock_irqsave(shost->host_lock, flags);
if (shost->hostt->target_destroy) if (shost->hostt->target_destroy)
...@@ -384,9 +385,15 @@ static void scsi_target_reap_ref_release(struct kref *kref) ...@@ -384,9 +385,15 @@ static void scsi_target_reap_ref_release(struct kref *kref)
struct scsi_target *starget struct scsi_target *starget
= container_of(kref, struct scsi_target, reap_ref); = container_of(kref, struct scsi_target, reap_ref);
/*
* if we get here and the target is still in the CREATED state that
* means it was allocated but never made visible (because a scan
* turned up no LUNs), so don't call device_del() on it.
*/
if (starget->state != STARGET_CREATED) {
transport_remove_device(&starget->dev); transport_remove_device(&starget->dev);
device_del(&starget->dev); device_del(&starget->dev);
starget->state = STARGET_DEL; }
scsi_target_destroy(starget); scsi_target_destroy(starget);
} }
...@@ -506,10 +513,12 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, ...@@ -506,10 +513,12 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
*/ */
void scsi_target_reap(struct scsi_target *starget) void scsi_target_reap(struct scsi_target *starget)
{ {
/*
* serious problem if this triggers: STARGET_DEL is only set in the if
* the reap_ref drops to zero, so we're trying to do another final put
* on an already released kref
*/
BUG_ON(starget->state == STARGET_DEL); BUG_ON(starget->state == STARGET_DEL);
if (starget->state == STARGET_CREATED)
scsi_target_destroy(starget);
else
scsi_target_reap_ref_put(starget); scsi_target_reap_ref_put(starget);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册