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