[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>

authored by James Bottomley and committed by 65110b21 faead26d

+12 -23
+4 -22
drivers/scsi/scsi_scan.c
··· 387 return found_target; 388 } 389 390 - struct work_queue_wrapper { 391 - struct work_struct work; 392 - struct scsi_target *starget; 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); 399 unsigned long flags; 400 - 401 - kfree(wqw); 402 403 spin_lock_irqsave(shost->host_lock, flags); 404 ··· 421 */ 422 void scsi_target_reap(struct scsi_target *starget) 423 { 424 - struct work_queue_wrapper *wqw = 425 - kzalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC); 426 - 427 - if (!wqw) { 428 - starget_printk(KERN_ERR, starget, 429 - "Failed to allocate memory in scsi_reap_target()\n"); 430 - return; 431 - } 432 - 433 - INIT_WORK(&wqw->work, scsi_target_reap_work, wqw); 434 - wqw->starget = starget; 435 - schedule_work(&wqw->work); 436 } 437 438 /**
··· 387 return found_target; 388 } 389 390 + static void scsi_target_reap_usercontext(void *data) 391 + { 392 + struct scsi_target *starget = data; 393 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 394 unsigned long flags; 395 396 spin_lock_irqsave(shost->host_lock, flags); 397 ··· 428 */ 429 void scsi_target_reap(struct scsi_target *starget) 430 { 431 + scsi_execute_in_process_context(scsi_target_reap_usercontext, starget); 432 } 433 434 /**
+8 -1
drivers/scsi/scsi_sysfs.c
··· 217 put_device(&sdev->sdev_gendev); 218 } 219 220 - static void scsi_device_dev_release(struct device *dev) 221 { 222 struct scsi_device *sdev; 223 struct device *parent; 224 struct scsi_target *starget; ··· 238 239 if (sdev->request_queue) { 240 sdev->request_queue->queuedata = NULL; 241 scsi_free_queue(sdev->request_queue); 242 /* temporary expedient, try to catch use of queue lock 243 * after free of sdev */ ··· 252 253 if (parent) 254 put_device(parent); 255 } 256 257 static struct class sdev_class = {
··· 217 put_device(&sdev->sdev_gendev); 218 } 219 220 + static void scsi_device_dev_release_usercontext(void *data) 221 { 222 + struct device *dev = data; 223 struct scsi_device *sdev; 224 struct device *parent; 225 struct scsi_target *starget; ··· 237 238 if (sdev->request_queue) { 239 sdev->request_queue->queuedata = NULL; 240 + /* user context needed to free queue */ 241 scsi_free_queue(sdev->request_queue); 242 /* temporary expedient, try to catch use of queue lock 243 * after free of sdev */ ··· 250 251 if (parent) 252 put_device(parent); 253 + } 254 + 255 + static void scsi_device_dev_release(struct device *dev) 256 + { 257 + scsi_execute_in_process_context(scsi_device_dev_release_usercontext, dev); 258 } 259 260 static struct class sdev_class = {