Revert "scsi: core: Fix a use-after-free"
This reverts commit 5ce8fad941
which is
commit 8fe4ce5836e932f5766317cb651c1ff2a4cd0506 upstream.
It breaks the Android kernel abi and can be brought back in the future
in an abi-safe way if it is really needed.
Bug: 161946584
Change-Id: I939984e199db400ce2107dedaec05c186eae11d8
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
@@ -182,15 +182,6 @@ void scsi_remove_host(struct Scsi_Host *shost)
|
|||||||
scsi_proc_host_rm(shost);
|
scsi_proc_host_rm(shost);
|
||||||
scsi_proc_hostdir_rm(shost->hostt);
|
scsi_proc_hostdir_rm(shost->hostt);
|
||||||
|
|
||||||
/*
|
|
||||||
* New SCSI devices cannot be attached anymore because of the SCSI host
|
|
||||||
* state so drop the tag set refcnt. Wait until the tag set refcnt drops
|
|
||||||
* to zero because .exit_cmd_priv implementations may need the host
|
|
||||||
* pointer.
|
|
||||||
*/
|
|
||||||
kref_put(&shost->tagset_refcnt, scsi_mq_free_tags);
|
|
||||||
wait_for_completion(&shost->tagset_freed);
|
|
||||||
|
|
||||||
spin_lock_irqsave(shost->host_lock, flags);
|
spin_lock_irqsave(shost->host_lock, flags);
|
||||||
if (scsi_host_set_state(shost, SHOST_DEL))
|
if (scsi_host_set_state(shost, SHOST_DEL))
|
||||||
BUG_ON(scsi_host_set_state(shost, SHOST_DEL_RECOVERY));
|
BUG_ON(scsi_host_set_state(shost, SHOST_DEL_RECOVERY));
|
||||||
@@ -249,9 +240,6 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
|
|||||||
|
|
||||||
shost->dma_dev = dma_dev;
|
shost->dma_dev = dma_dev;
|
||||||
|
|
||||||
kref_init(&shost->tagset_refcnt);
|
|
||||||
init_completion(&shost->tagset_freed);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Increase usage count temporarily here so that calling
|
* Increase usage count temporarily here so that calling
|
||||||
* scsi_autopm_put_host() will trigger runtime idle if there is
|
* scsi_autopm_put_host() will trigger runtime idle if there is
|
||||||
@@ -324,7 +312,6 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
|
|||||||
pm_runtime_disable(&shost->shost_gendev);
|
pm_runtime_disable(&shost->shost_gendev);
|
||||||
pm_runtime_set_suspended(&shost->shost_gendev);
|
pm_runtime_set_suspended(&shost->shost_gendev);
|
||||||
pm_runtime_put_noidle(&shost->shost_gendev);
|
pm_runtime_put_noidle(&shost->shost_gendev);
|
||||||
kref_put(&shost->tagset_refcnt, scsi_mq_free_tags);
|
|
||||||
fail:
|
fail:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@@ -357,6 +344,9 @@ static void scsi_host_dev_release(struct device *dev)
|
|||||||
kfree(dev_name(&shost->shost_dev));
|
kfree(dev_name(&shost->shost_dev));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shost->tag_set.tags)
|
||||||
|
scsi_mq_destroy_tags(shost);
|
||||||
|
|
||||||
kfree(shost->shost_data);
|
kfree(shost->shost_data);
|
||||||
|
|
||||||
ida_simple_remove(&host_index_ida, shost->host_no);
|
ida_simple_remove(&host_index_ida, shost->host_no);
|
||||||
|
@@ -1921,13 +1921,9 @@ int scsi_mq_setup_tags(struct Scsi_Host *shost)
|
|||||||
return blk_mq_alloc_tag_set(tag_set);
|
return blk_mq_alloc_tag_set(tag_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
void scsi_mq_free_tags(struct kref *kref)
|
void scsi_mq_destroy_tags(struct Scsi_Host *shost)
|
||||||
{
|
{
|
||||||
struct Scsi_Host *shost = container_of(kref, typeof(*shost),
|
|
||||||
tagset_refcnt);
|
|
||||||
|
|
||||||
blk_mq_free_tag_set(&shost->tag_set);
|
blk_mq_free_tag_set(&shost->tag_set);
|
||||||
complete(&shost->tagset_freed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -93,7 +93,7 @@ extern void scsi_requeue_run_queue(struct work_struct *work);
|
|||||||
extern struct request_queue *scsi_mq_alloc_queue(struct scsi_device *sdev);
|
extern struct request_queue *scsi_mq_alloc_queue(struct scsi_device *sdev);
|
||||||
extern void scsi_start_queue(struct scsi_device *sdev);
|
extern void scsi_start_queue(struct scsi_device *sdev);
|
||||||
extern int scsi_mq_setup_tags(struct Scsi_Host *shost);
|
extern int scsi_mq_setup_tags(struct Scsi_Host *shost);
|
||||||
extern void scsi_mq_free_tags(struct kref *kref);
|
extern void scsi_mq_destroy_tags(struct Scsi_Host *shost);
|
||||||
extern void scsi_exit_queue(void);
|
extern void scsi_exit_queue(void);
|
||||||
extern void scsi_evt_thread(struct work_struct *work);
|
extern void scsi_evt_thread(struct work_struct *work);
|
||||||
struct request_queue;
|
struct request_queue;
|
||||||
|
@@ -273,7 +273,6 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
|
|||||||
kfree(sdev);
|
kfree(sdev);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
kref_get(&sdev->host->tagset_refcnt);
|
|
||||||
WARN_ON_ONCE(!blk_get_queue(sdev->request_queue));
|
WARN_ON_ONCE(!blk_get_queue(sdev->request_queue));
|
||||||
sdev->request_queue->queuedata = sdev;
|
sdev->request_queue->queuedata = sdev;
|
||||||
|
|
||||||
|
@@ -1481,7 +1481,6 @@ void __scsi_remove_device(struct scsi_device *sdev)
|
|||||||
mutex_unlock(&sdev->state_mutex);
|
mutex_unlock(&sdev->state_mutex);
|
||||||
|
|
||||||
blk_cleanup_queue(sdev->request_queue);
|
blk_cleanup_queue(sdev->request_queue);
|
||||||
kref_put(&sdev->host->tagset_refcnt, scsi_mq_free_tags);
|
|
||||||
cancel_work_sync(&sdev->requeue_work);
|
cancel_work_sync(&sdev->requeue_work);
|
||||||
|
|
||||||
if (sdev->host->hostt->slave_destroy)
|
if (sdev->host->hostt->slave_destroy)
|
||||||
|
@@ -554,8 +554,6 @@ struct Scsi_Host {
|
|||||||
struct scsi_host_template *hostt;
|
struct scsi_host_template *hostt;
|
||||||
struct scsi_transport_template *transportt;
|
struct scsi_transport_template *transportt;
|
||||||
|
|
||||||
struct kref tagset_refcnt;
|
|
||||||
struct completion tagset_freed;
|
|
||||||
/* Area to keep a shared tag map */
|
/* Area to keep a shared tag map */
|
||||||
struct blk_mq_tag_set tag_set;
|
struct blk_mq_tag_set tag_set;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user