mirror of
https://github.com/torvalds/linux.git
synced 2024-12-31 23:31:29 +00:00
[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>
This commit is contained in:
parent
faead26d7a
commit
65110b2168
@ -387,19 +387,12 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
|
|||||||
return found_target;
|
return found_target;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct work_queue_wrapper {
|
static void scsi_target_reap_usercontext(void *data)
|
||||||
struct work_struct work;
|
{
|
||||||
struct scsi_target *starget;
|
struct scsi_target *starget = data;
|
||||||
};
|
|
||||||
|
|
||||||
static void scsi_target_reap_work(void *data) {
|
|
||||||
struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data;
|
|
||||||
struct scsi_target *starget = wqw->starget;
|
|
||||||
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
kfree(wqw);
|
|
||||||
|
|
||||||
spin_lock_irqsave(shost->host_lock, flags);
|
spin_lock_irqsave(shost->host_lock, flags);
|
||||||
|
|
||||||
if (--starget->reap_ref == 0 && list_empty(&starget->devices)) {
|
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)
|
void scsi_target_reap(struct scsi_target *starget)
|
||||||
{
|
{
|
||||||
struct work_queue_wrapper *wqw =
|
scsi_execute_in_process_context(scsi_target_reap_usercontext, starget);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -217,8 +217,9 @@ static void scsi_device_cls_release(struct class_device *class_dev)
|
|||||||
put_device(&sdev->sdev_gendev);
|
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 scsi_device *sdev;
|
||||||
struct device *parent;
|
struct device *parent;
|
||||||
struct scsi_target *starget;
|
struct scsi_target *starget;
|
||||||
@ -237,6 +238,7 @@ static void scsi_device_dev_release(struct device *dev)
|
|||||||
|
|
||||||
if (sdev->request_queue) {
|
if (sdev->request_queue) {
|
||||||
sdev->request_queue->queuedata = NULL;
|
sdev->request_queue->queuedata = NULL;
|
||||||
|
/* user context needed to free queue */
|
||||||
scsi_free_queue(sdev->request_queue);
|
scsi_free_queue(sdev->request_queue);
|
||||||
/* temporary expedient, try to catch use of queue lock
|
/* temporary expedient, try to catch use of queue lock
|
||||||
* after free of sdev */
|
* after free of sdev */
|
||||||
@ -252,6 +254,11 @@ static void scsi_device_dev_release(struct device *dev)
|
|||||||
put_device(parent);
|
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 = {
|
static struct class sdev_class = {
|
||||||
.name = "scsi_device",
|
.name = "scsi_device",
|
||||||
.release = scsi_device_cls_release,
|
.release = scsi_device_cls_release,
|
||||||
|
Loading…
Reference in New Issue
Block a user