aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames 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
commit65110b2168950a19cc78b5027ed18cb811fbdae8 (patch)
tree8cdf4fc26b707e0e6ba988fd56da118d3206dceb
parentfaead26d7a06605add627f29aee73ba654ce11f9 (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>
-rw-r--r--drivers/scsi/scsi_scan.c26
-rw-r--r--drivers/scsi/scsi_sysfs.c9
2 files changed, 12 insertions, 23 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
390struct work_queue_wrapper { 390static 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
395static 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 */
429void scsi_target_reap(struct scsi_target *starget) 422void 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/**
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index a77b32deaf8f..902a5def8e62 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)
217 put_device(&sdev->sdev_gendev); 217 put_device(&sdev->sdev_gendev);
218} 218}
219 219
220static void scsi_device_dev_release(struct device *dev) 220static void scsi_device_dev_release_usercontext(void *data)
221{ 221{
222 struct device *dev = data;
222 struct scsi_device *sdev; 223 struct scsi_device *sdev;
223 struct device *parent; 224 struct device *parent;
224 struct scsi_target *starget; 225 struct scsi_target *starget;
@@ -237,6 +238,7 @@ static void scsi_device_dev_release(struct device *dev)
237 238
238 if (sdev->request_queue) { 239 if (sdev->request_queue) {
239 sdev->request_queue->queuedata = NULL; 240 sdev->request_queue->queuedata = NULL;
241 /* user context needed to free queue */
240 scsi_free_queue(sdev->request_queue); 242 scsi_free_queue(sdev->request_queue);
241 /* temporary expedient, try to catch use of queue lock 243 /* temporary expedient, try to catch use of queue lock
242 * after free of sdev */ 244 * after free of sdev */
@@ -252,6 +254,11 @@ static void scsi_device_dev_release(struct device *dev)
252 put_device(parent); 254 put_device(parent);
253} 255}
254 256
257static void scsi_device_dev_release(struct device *dev)
258{
259 scsi_execute_in_process_context(scsi_device_dev_release_usercontext, dev);
260}
261
255static struct class sdev_class = { 262static struct class sdev_class = {
256 .name = "scsi_device", 263 .name = "scsi_device",
257 .release = scsi_device_cls_release, 264 .release = scsi_device_cls_release,