Commit ce888220 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull SCSI fixes from James Bottomley:
 "Eight patches which looks like quite a large core change, but most of
  the diffstat is reverting the attempt to rejig reference counting
  introduced in the last merge window which caused issues with device
  and module removal.

  Of the remaining four patches, only the fix use-after-free is
  substantial"

* tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi:
  scsi: mpt3sas: Fix use-after-free warning
  scsi: core: Fix a use-after-free
  scsi: core: Revert "Make sure that targets outlive devices"
  scsi: core: Revert "Make sure that hosts outlive targets"
  scsi: core: Revert "Simplify LLD module reference counting"
  scsi: core: Revert "Call blk_mq_free_tag_set() earlier"
  scsi: lpfc: Add missing destroy_workqueue() in error path
  scsi: lpfc: Return DID_TRANSPORT_DISRUPTED instead of DID_REQUEUE
parents e35be05d 991df3dd
Loading
Loading
Loading
Loading
+15 −13
Original line number Diff line number Diff line
@@ -182,6 +182,15 @@ void scsi_remove_host(struct Scsi_Host *shost)
	mutex_unlock(&shost->scan_mutex);
	scsi_proc_host_rm(shost);

	/*
	 * 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);
	if (scsi_host_set_state(shost, SHOST_DEL))
		BUG_ON(scsi_host_set_state(shost, SHOST_DEL_RECOVERY));
@@ -190,15 +199,6 @@ void scsi_remove_host(struct Scsi_Host *shost)
	transport_unregister_device(&shost->shost_gendev);
	device_unregister(&shost->shost_dev);
	device_del(&shost->shost_gendev);

	/*
	 * After scsi_remove_host() has returned the scsi LLD module can be
	 * unloaded and/or the host resources can be released. Hence wait until
	 * the dependent SCSI targets and devices are gone before returning.
	 */
	wait_event(shost->targets_wq, atomic_read(&shost->target_count) == 0);

	scsi_mq_destroy_tags(shost);
}
EXPORT_SYMBOL(scsi_remove_host);

@@ -254,6 +254,9 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
	if (error)
		goto fail;

	kref_init(&shost->tagset_refcnt);
	init_completion(&shost->tagset_freed);

	/*
	 * Increase usage count temporarily here so that calling
	 * scsi_autopm_put_host() will trigger runtime idle if there is
@@ -309,8 +312,8 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
	return error;

	/*
	 * Any resources associated with the SCSI host in this function except
	 * the tag set will be freed by scsi_host_dev_release().
	 * Any host allocation in this function will be freed in
	 * scsi_host_dev_release().
	 */
 out_del_dev:
	device_del(&shost->shost_dev);
@@ -326,7 +329,7 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
	pm_runtime_disable(&shost->shost_gendev);
	pm_runtime_set_suspended(&shost->shost_gendev);
	pm_runtime_put_noidle(&shost->shost_gendev);
	scsi_mq_destroy_tags(shost);
	kref_put(&shost->tagset_refcnt, scsi_mq_free_tags);
 fail:
	return error;
}
@@ -406,7 +409,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
	INIT_LIST_HEAD(&shost->starved_list);
	init_waitqueue_head(&shost->host_wait);
	mutex_init(&shost->scan_mutex);
	init_waitqueue_head(&shost->targets_wq);

	index = ida_alloc(&host_index_ida, GFP_KERNEL);
	if (index < 0) {
+4 −1
Original line number Diff line number Diff line
@@ -8053,7 +8053,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
	/* Allocate device driver memory */
	rc = lpfc_mem_alloc(phba, SGL_ALIGN_SZ);
	if (rc)
		return -ENOMEM;
		goto out_destroy_workqueue;

	/* IF Type 2 ports get initialized now. */
	if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >=
@@ -8481,6 +8481,9 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
	lpfc_destroy_bootstrap_mbox(phba);
out_free_mem:
	lpfc_mem_free(phba);
out_destroy_workqueue:
	destroy_workqueue(phba->wq);
	phba->wq = NULL;
	return rc;
}

+2 −2
Original line number Diff line number Diff line
@@ -4272,7 +4272,7 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
		    lpfc_cmd->result == IOERR_ABORT_REQUESTED ||
		    lpfc_cmd->result == IOERR_RPI_SUSPENDED ||
		    lpfc_cmd->result == IOERR_SLER_CMD_RCV_FAILURE) {
			cmd->result = DID_REQUEUE << 16;
			cmd->result = DID_TRANSPORT_DISRUPTED << 16;
			break;
		}
		if ((lpfc_cmd->result == IOERR_RX_DMA_FAILED ||
@@ -4562,7 +4562,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
			    lpfc_cmd->result == IOERR_NO_RESOURCES ||
			    lpfc_cmd->result == IOERR_ABORT_REQUESTED ||
			    lpfc_cmd->result == IOERR_SLER_CMD_RCV_FAILURE) {
				cmd->result = DID_REQUEUE << 16;
				cmd->result = DID_TRANSPORT_DISRUPTED << 16;
				break;
			}
			if ((lpfc_cmd->result == IOERR_RX_DMA_FAILED ||
+1 −1
Original line number Diff line number Diff line
@@ -3670,6 +3670,7 @@ static struct fw_event_work *dequeue_next_fw_event(struct MPT3SAS_ADAPTER *ioc)
		fw_event = list_first_entry(&ioc->fw_event_list,
				struct fw_event_work, list);
		list_del_init(&fw_event->list);
		fw_event_work_put(fw_event);
	}
	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);

@@ -3751,7 +3752,6 @@ _scsih_fw_event_cleanup_queue(struct MPT3SAS_ADAPTER *ioc)
		if (cancel_work_sync(&fw_event->work))
			fw_event_work_put(fw_event);

		fw_event_work_put(fw_event);
	}
	ioc->fw_events_cleanup = 0;
}
+3 −6
Original line number Diff line number Diff line
@@ -586,13 +586,10 @@ EXPORT_SYMBOL(scsi_device_get);
 */
void scsi_device_put(struct scsi_device *sdev)
{
	/*
	 * Decreasing the module reference count before the device reference
	 * count is safe since scsi_remove_host() only returns after all
	 * devices have been removed.
	 */
	module_put(sdev->host->hostt->module);
	struct module *mod = sdev->host->hostt->module;

	put_device(&sdev->sdev_gendev);
	module_put(mod);
}
EXPORT_SYMBOL(scsi_device_put);

Loading