2015-02-02 22:01 GMT+09:00 Christoph Hellwig <[email protected]>:
> This effectively reverts commits 85b6c7 ("[SCSI] sd: fix cache flushing on
> module removal (and individual device removal)" and dc4515ea ("scsi: always
> increment reference count").
>
> We now never call scsi_device_get from the shutdown path, and the fact
> that we started grabbing reference there in commit 85b6c7 turned out
> turned out to create more problems than it solves, and required
> workarounds for workarounds for workarounds. Move back to properly checking
> the device state and carefully handle module refcounting.
>
> Signed-off-by: Christoph Hellwig <[email protected]>
> ---
> drivers/scsi/scsi.c | 20 +++++++++++++-------
> 1 file changed, 13 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
> index 9b38299..9b7fd0b 100644
> --- a/drivers/scsi/scsi.c
> +++ b/drivers/scsi/scsi.c
> @@ -979,18 +979,24 @@ EXPORT_SYMBOL(scsi_report_opcode);
> * Description: Gets a reference to the scsi_device and increments the use
> count
> * of the underlying LLDD module. You must hold host_lock of the
> * parent Scsi_Host or already have a reference when calling this.
> + *
> + * This will fail if a device is deleted or cancelled, or when the LLD module
> + * is in the process of being unloaded.
> */
> int scsi_device_get(struct scsi_device *sdev)
Hi Christoph,
This change broke ufs driver.
Because scsi_device_get() can be called while the module is being
unloaded with the device runtime suspended.
(i.e. driver_detach -> ... pm_runtime_get_sync() ... ->
ufshcd_runtime_resume -> ufshcd_resume -> ufshcd_set_dev_pwr_mode ->
scsi_device_get -> try_module_get -> return -ENXIO)
The reason for scsi_device_get() in ufshcd_set_dev_pwr_mode() is
to avoid manual delete of UFS device W-LUN by holding the reference
to it. So can we acquire shost->scan_mutex lock instead of
scsi_device_get()? I tried attached patch and it seems to be working,
but I would like to ask your opinion about this change.
> {
> - if (sdev->sdev_state == SDEV_DEL)
> - return -ENXIO;
> + if (sdev->sdev_state == SDEV_DEL || sdev->sdev_state == SDEV_CANCEL)
> + goto fail;
> if (!get_device(&sdev->sdev_gendev))
> - return -ENXIO;
> - /* We can fail try_module_get if we're doing SCSI operations
> - * from module exit (like cache flush) */
> - __module_get(sdev->host->hostt->module);
> -
> + goto fail;
> + if (!try_module_get(sdev->host->hostt->module))
> + goto fail_put_device;
> return 0;
> +
> +fail_put_device:
> + put_device(&sdev->sdev_gendev);
> +fail:
> + return -ENXIO;
> }
> EXPORT_SYMBOL(scsi_device_get);
>
> --
> 1.9.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
From a305a5284cac23adbf7f86b3014cc2e6325c7b88 Mon Sep 17 00:00:00 2001
From: Akinobu Mita <[email protected]>
Date: Wed, 29 Apr 2015 10:02:17 +0900
Subject: [PATCH] scsi: ufs: fix ufshcd_set_dev_pwr_mode() when unloading
module
---
drivers/scsi/ufs/ufshcd.c | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 540e00d..91cbc04 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4695,23 +4695,19 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
struct scsi_sense_hdr sshdr;
struct scsi_device *sdp;
unsigned long flags;
- int ret;
+ int ret = 0;
+ mutex_lock(&hba->host->scan_mutex);
spin_lock_irqsave(hba->host->host_lock, flags);
sdp = hba->sdev_ufs_device;
- if (sdp) {
- ret = scsi_device_get(sdp);
- if (!ret && !scsi_device_online(sdp)) {
- ret = -ENODEV;
- scsi_device_put(sdp);
- }
- } else {
+ if (!sdp || !scsi_device_online(sdp))
ret = -ENODEV;
- }
spin_unlock_irqrestore(hba->host->host_lock, flags);
- if (ret)
+ if (ret) {
+ mutex_unlock(&hba->host->scan_mutex);
return ret;
+ }
/*
* If scsi commands fail, the scsi mid-layer schedules scsi error-
@@ -4748,7 +4744,7 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
if (!ret)
hba->curr_dev_pwr_mode = pwr_mode;
out:
- scsi_device_put(sdp);
+ mutex_unlock(&hba->host->scan_mutex);
hba->host->eh_noresume = 0;
return ret;
}
--
1.9.1