Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scsi: Add intermediate STARGET_REMOVE state to scsi_target_state

Add intermediate STARGET_REMOVE state to scsi_target_state to avoid
running into the BUG_ON() in scsi_target_reap(). The STARGET_REMOVE
state is only valid in the path from scsi_remove_target() to
scsi_target_destroy() indicating this target is going to be removed.

This re-fixes the problem introduced in commits bc3f02a795d3 ("[SCSI]
scsi_remove_target: fix softlockup regression on hot remove") and
40998193560d ("scsi: restart list search after unlock in
scsi_remove_target") in a more comprehensive way.

[mkp: Included James' fix for scsi_target_destroy()]

Signed-off-by: Johannes Thumshirn <jthumshirn@suse.de>
Fixes: 40998193560dab6c3ce8d25f4fa58a23e252ef38
Cc: stable@vger.kernel.org
Reported-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Tested-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Reviewed-by: Ewan D. Milne <emilne@redhat.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Reviewed-by: James Bottomley <jejb@linux.vnet.ibm.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Johannes Thumshirn and committed by
Martin K. Petersen
f05795d3 be2a266d

+4
+1
drivers/scsi/scsi_scan.c
··· 319 319 struct Scsi_Host *shost = dev_to_shost(dev->parent); 320 320 unsigned long flags; 321 321 322 + BUG_ON(starget->state == STARGET_DEL); 322 323 starget->state = STARGET_DEL; 323 324 transport_destroy_device(dev); 324 325 spin_lock_irqsave(shost->host_lock, flags);
+2
drivers/scsi/scsi_sysfs.c
··· 1374 1374 spin_lock_irqsave(shost->host_lock, flags); 1375 1375 list_for_each_entry(starget, &shost->__targets, siblings) { 1376 1376 if (starget->state == STARGET_DEL || 1377 + starget->state == STARGET_REMOVE || 1377 1378 starget == last_target) 1378 1379 continue; 1379 1380 if (starget->dev.parent == dev || &starget->dev == dev) { 1380 1381 kref_get(&starget->reap_ref); 1381 1382 last_target = starget; 1383 + starget->state = STARGET_REMOVE; 1382 1384 spin_unlock_irqrestore(shost->host_lock, flags); 1383 1385 __scsi_remove_target(starget); 1384 1386 scsi_target_reap(starget);
+1
include/scsi/scsi_device.h
··· 248 248 enum scsi_target_state { 249 249 STARGET_CREATED = 1, 250 250 STARGET_RUNNING, 251 + STARGET_REMOVE, 251 252 STARGET_DEL, 252 253 }; 253 254