diff options
author | James Bottomley <James.Bottomley@steeleye.com> | 2006-02-14 16:48:46 (GMT) |
---|---|---|
committer | <jejb@mulgrave.il.steeleye.com> | 2006-02-14 17:15:11 (GMT) |
commit | 65110b2168950a19cc78b5027ed18cb811fbdae8 (patch) | |
tree | 8cdf4fc26b707e0e6ba988fd56da118d3206dceb /drivers | |
parent | faead26d7a06605add627f29aee73ba654ce11f9 (diff) | |
download | linux-fsl-qoriq-65110b2168950a19cc78b5027ed18cb811fbdae8.tar.xz |
[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')
-rw-r--r-- | drivers/scsi/scsi_scan.c | 26 | ||||
-rw-r--r-- | drivers/scsi/scsi_sysfs.c | 9 |
2 files changed, 12 insertions, 23 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 752fb5d..5acb83c 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, return found_target; } -struct work_queue_wrapper { - struct work_struct work; - struct scsi_target *starget; -}; - -static void scsi_target_reap_work(void *data) { - struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; - struct scsi_target *starget = wqw->starget; +static void scsi_target_reap_usercontext(void *data) +{ + struct scsi_target *starget = data; struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); unsigned long flags; - kfree(wqw); - spin_lock_irqsave(shost->host_lock, flags); if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { @@ -428,18 +421,7 @@ static void scsi_target_reap_work(void *data) { */ void scsi_target_reap(struct scsi_target *starget) { - struct work_queue_wrapper *wqw = - kzalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC); - - if (!wqw) { - starget_printk(KERN_ERR, starget, - "Failed to allocate memory in scsi_reap_target()\n"); - return; - } - - INIT_WORK(&wqw->work, scsi_target_reap_work, wqw); - wqw->starget = starget; - schedule_work(&wqw->work); + scsi_execute_in_process_context(scsi_target_reap_usercontext, starget); } /** diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index a77b32d..902a5de 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -217,8 +217,9 @@ static void scsi_device_cls_release(struct class_device *class_dev) put_device(&sdev->sdev_gendev); } -static void scsi_device_dev_release(struct device *dev) +static void scsi_device_dev_release_usercontext(void *data) { + struct device *dev = data; struct scsi_device *sdev; struct device *parent; struct scsi_target *starget; @@ -237,6 +238,7 @@ static void scsi_device_dev_release(struct device *dev) if (sdev->request_queue) { sdev->request_queue->queuedata = NULL; + /* user context needed to free queue */ scsi_free_queue(sdev->request_queue); /* temporary expedient, try to catch use of queue lock * after free of sdev */ @@ -252,6 +254,11 @@ static void scsi_device_dev_release(struct device *dev) put_device(parent); } +static void scsi_device_dev_release(struct device *dev) +{ + scsi_execute_in_process_context(scsi_device_dev_release_usercontext, dev); +} + static struct class sdev_class = { .name = "scsi_device", .release = scsi_device_cls_release, |