diff options
author | James Bottomley <James.Bottomley@steeleye.com> | 2006-02-23 15:27:18 -0500 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-02-28 00:37:45 -0500 |
commit | ffedb4522571ac170f941678d138a31bc0884ab4 (patch) | |
tree | 996572da6cecf4295c730b13c959d5d19836a8c5 /drivers/scsi/scsi_scan.c | |
parent | 1fa44ecad2b86475e038aed81b0bf333fa484f8b (diff) |
[SCSI] fix scsi process problems and clean up the target reap issues
In order to use the new execute_in_process_context() API, you have to
provide it with the work storage, which I do in SCSI in scsi_device and
scsi_target, but which also means that we can no longer queue up the
target reaps, so instead I moved the target to a state model which
allows target_alloc to detect if we've received a dying target and wait
for it to be gone. Hopefully, this should also solve the target
namespace race.
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/scsi_scan.c')
-rw-r--r-- | drivers/scsi/scsi_scan.c | 49 |
1 files changed, 33 insertions, 16 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 94b86d5b1469..84f01fd0c8fd 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c | |||
@@ -349,6 +349,8 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
349 | starget->channel = channel; | 349 | starget->channel = channel; |
350 | INIT_LIST_HEAD(&starget->siblings); | 350 | INIT_LIST_HEAD(&starget->siblings); |
351 | INIT_LIST_HEAD(&starget->devices); | 351 | INIT_LIST_HEAD(&starget->devices); |
352 | starget->state = STARGET_RUNNING; | ||
353 | retry: | ||
352 | spin_lock_irqsave(shost->host_lock, flags); | 354 | spin_lock_irqsave(shost->host_lock, flags); |
353 | 355 | ||
354 | found_target = __scsi_find_target(parent, channel, id); | 356 | found_target = __scsi_find_target(parent, channel, id); |
@@ -381,8 +383,15 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
381 | found_target->reap_ref++; | 383 | found_target->reap_ref++; |
382 | spin_unlock_irqrestore(shost->host_lock, flags); | 384 | spin_unlock_irqrestore(shost->host_lock, flags); |
383 | put_device(parent); | 385 | put_device(parent); |
384 | kfree(starget); | 386 | if (found_target->state != STARGET_DEL) { |
385 | return found_target; | 387 | kfree(starget); |
388 | return found_target; | ||
389 | } | ||
390 | /* Unfortunately, we found a dying target; need to | ||
391 | * wait until it's dead before we can get a new one */ | ||
392 | put_device(&found_target->dev); | ||
393 | flush_scheduled_work(); | ||
394 | goto retry; | ||
386 | } | 395 | } |
387 | 396 | ||
388 | static void scsi_target_reap_usercontext(void *data) | 397 | static void scsi_target_reap_usercontext(void *data) |
@@ -391,21 +400,13 @@ static void scsi_target_reap_usercontext(void *data) | |||
391 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | 400 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); |
392 | unsigned long flags; | 401 | unsigned long flags; |
393 | 402 | ||
403 | transport_remove_device(&starget->dev); | ||
404 | device_del(&starget->dev); | ||
405 | transport_destroy_device(&starget->dev); | ||
394 | spin_lock_irqsave(shost->host_lock, flags); | 406 | spin_lock_irqsave(shost->host_lock, flags); |
395 | 407 | list_del_init(&starget->siblings); | |
396 | if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { | ||
397 | list_del_init(&starget->siblings); | ||
398 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
399 | transport_remove_device(&starget->dev); | ||
400 | device_del(&starget->dev); | ||
401 | transport_destroy_device(&starget->dev); | ||
402 | put_device(&starget->dev); | ||
403 | return; | ||
404 | |||
405 | } | ||
406 | spin_unlock_irqrestore(shost->host_lock, flags); | 408 | spin_unlock_irqrestore(shost->host_lock, flags); |
407 | 409 | put_device(&starget->dev); | |
408 | return; | ||
409 | } | 410 | } |
410 | 411 | ||
411 | /** | 412 | /** |
@@ -419,7 +420,23 @@ static void scsi_target_reap_usercontext(void *data) | |||
419 | */ | 420 | */ |
420 | void scsi_target_reap(struct scsi_target *starget) | 421 | void scsi_target_reap(struct scsi_target *starget) |
421 | { | 422 | { |
422 | scsi_execute_in_process_context(scsi_target_reap_usercontext, starget); | 423 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); |
424 | unsigned long flags; | ||
425 | |||
426 | spin_lock_irqsave(shost->host_lock, flags); | ||
427 | |||
428 | if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { | ||
429 | BUG_ON(starget->state == STARGET_DEL); | ||
430 | starget->state = STARGET_DEL; | ||
431 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
432 | execute_in_process_context(scsi_target_reap_usercontext, | ||
433 | starget, &starget->ew); | ||
434 | return; | ||
435 | |||
436 | } | ||
437 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
438 | |||
439 | return; | ||
423 | } | 440 | } |
424 | 441 | ||
425 | /** | 442 | /** |