diff options
Diffstat (limited to 'drivers/scsi/scsi_scan.c')
| -rw-r--r-- | drivers/scsi/scsi_scan.c | 49 |
1 files changed, 39 insertions, 10 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 94e5167f260d..4e6709f448e1 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c | |||
| @@ -400,6 +400,36 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
| 400 | return found_target; | 400 | return found_target; |
| 401 | } | 401 | } |
| 402 | 402 | ||
| 403 | struct work_queue_wrapper { | ||
| 404 | struct work_struct work; | ||
| 405 | struct scsi_target *starget; | ||
| 406 | }; | ||
| 407 | |||
| 408 | static void scsi_target_reap_work(void *data) { | ||
| 409 | struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; | ||
| 410 | struct scsi_target *starget = wqw->starget; | ||
| 411 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | ||
| 412 | unsigned long flags; | ||
| 413 | |||
| 414 | kfree(wqw); | ||
| 415 | |||
| 416 | spin_lock_irqsave(shost->host_lock, flags); | ||
| 417 | |||
| 418 | if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { | ||
| 419 | list_del_init(&starget->siblings); | ||
| 420 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
| 421 | transport_remove_device(&starget->dev); | ||
| 422 | device_del(&starget->dev); | ||
| 423 | transport_destroy_device(&starget->dev); | ||
| 424 | put_device(&starget->dev); | ||
| 425 | return; | ||
| 426 | |||
| 427 | } | ||
| 428 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
| 429 | |||
| 430 | return; | ||
| 431 | } | ||
| 432 | |||
| 403 | /** | 433 | /** |
| 404 | * scsi_target_reap - check to see if target is in use and destroy if not | 434 | * scsi_target_reap - check to see if target is in use and destroy if not |
| 405 | * | 435 | * |
| @@ -411,19 +441,18 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
| 411 | */ | 441 | */ |
| 412 | void scsi_target_reap(struct scsi_target *starget) | 442 | void scsi_target_reap(struct scsi_target *starget) |
| 413 | { | 443 | { |
| 414 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | 444 | struct work_queue_wrapper *wqw = |
| 415 | unsigned long flags; | 445 | kzalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC); |
| 416 | spin_lock_irqsave(shost->host_lock, flags); | ||
| 417 | 446 | ||
| 418 | if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { | 447 | if (!wqw) { |
| 419 | list_del_init(&starget->siblings); | 448 | starget_printk(KERN_ERR, starget, |
| 420 | spin_unlock_irqrestore(shost->host_lock, flags); | 449 | "Failed to allocate memory in scsi_reap_target()\n"); |
| 421 | device_del(&starget->dev); | ||
| 422 | transport_unregister_device(&starget->dev); | ||
| 423 | put_device(&starget->dev); | ||
| 424 | return; | 450 | return; |
| 425 | } | 451 | } |
| 426 | spin_unlock_irqrestore(shost->host_lock, flags); | 452 | |
| 453 | INIT_WORK(&wqw->work, scsi_target_reap_work, wqw); | ||
| 454 | wqw->starget = starget; | ||
| 455 | schedule_work(&wqw->work); | ||
| 427 | } | 456 | } |
| 428 | 457 | ||
| 429 | /** | 458 | /** |
