Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 65110b21 authored by James Bottomley's avatar James Bottomley Committed by
Browse files

[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: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent faead26d
Loading
Loading
Loading
Loading
+4 −22
Original line number Diff line number Diff line
@@ -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);
}

/**
+8 −1
Original line number Diff line number Diff line
@@ -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,