diff options
author | James Bottomley <James.Bottomley@steeleye.com> | 2006-02-14 11:48:46 -0500 |
---|---|---|
committer | <jejb@mulgrave.il.steeleye.com> | 2006-02-14 12:15:11 -0500 |
commit | 65110b2168950a19cc78b5027ed18cb811fbdae8 (patch) | |
tree | 8cdf4fc26b707e0e6ba988fd56da118d3206dceb /drivers/scsi/scsi_scan.c | |
parent | faead26d7a06605add627f29aee73ba654ce11f9 (diff) |
[SCSI] fix wrong context bugs in SCSI
There's a bug in releasing scsi_device where the release function
actually frees the block queue. However, the block queue release
calls flush_work(), which requires process context (the scsi_device
structure may release from irq context). Update the release function
to invoke via the execute_in_process_context() API.
Also clean up the scsi_target structure releasing via this API.
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 | 26 |
1 files changed, 4 insertions, 22 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 752fb5da3de4..5acb83ca5ae5 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c | |||
@@ -387,19 +387,12 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
387 | return found_target; | 387 | return found_target; |
388 | } | 388 | } |
389 | 389 | ||
390 | struct work_queue_wrapper { | 390 | static void scsi_target_reap_usercontext(void *data) |
391 | struct work_struct work; | 391 | { |
392 | struct scsi_target *starget; | 392 | struct scsi_target *starget = data; |
393 | }; | ||
394 | |||
395 | static void scsi_target_reap_work(void *data) { | ||
396 | struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; | ||
397 | struct scsi_target *starget = wqw->starget; | ||
398 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | 393 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); |
399 | unsigned long flags; | 394 | unsigned long flags; |
400 | 395 | ||
401 | kfree(wqw); | ||
402 | |||
403 | spin_lock_irqsave(shost->host_lock, flags); | 396 | spin_lock_irqsave(shost->host_lock, flags); |
404 | 397 | ||
405 | if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { | 398 | if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { |
@@ -428,18 +421,7 @@ static void scsi_target_reap_work(void *data) { | |||
428 | */ | 421 | */ |
429 | void scsi_target_reap(struct scsi_target *starget) | 422 | void scsi_target_reap(struct scsi_target *starget) |
430 | { | 423 | { |
431 | struct work_queue_wrapper *wqw = | 424 | scsi_execute_in_process_context(scsi_target_reap_usercontext, starget); |
432 | kzalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC); | ||
433 | |||
434 | if (!wqw) { | ||
435 | starget_printk(KERN_ERR, starget, | ||
436 | "Failed to allocate memory in scsi_reap_target()\n"); | ||
437 | return; | ||
438 | } | ||
439 | |||
440 | INIT_WORK(&wqw->work, scsi_target_reap_work, wqw); | ||
441 | wqw->starget = starget; | ||
442 | schedule_work(&wqw->work); | ||
443 | } | 425 | } |
444 | 426 | ||
445 | /** | 427 | /** |