diff options
-rw-r--r-- | drivers/base/core.c | 2 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 23 |
2 files changed, 23 insertions, 2 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index cadcade65825..9badd7f7fe62 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -884,6 +884,8 @@ static void device_link_put_kref(struct device_link *link) { if (link->flags & DL_FLAG_STATELESS) kref_put(&link->kref, __device_link_del); + else if (!device_is_registered(link->consumer)) + __device_link_del(&link->kref); else WARN(1, "Unable to drop a managed device link reference\n"); } diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 38cf516b0c6d..b408be3c5cb7 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -5028,6 +5028,7 @@ static int ufshcd_slave_configure(struct scsi_device *sdev) static void ufshcd_slave_destroy(struct scsi_device *sdev) { struct ufs_hba *hba; + unsigned long flags; hba = shost_priv(sdev->host); @@ -5035,11 +5036,29 @@ static void ufshcd_slave_destroy(struct scsi_device *sdev) /* Drop the reference as it won't be needed anymore */ if (ufshcd_scsi_to_upiu_lun(sdev->lun) == UFS_UPIU_UFS_DEVICE_WLUN) { - unsigned long flags; - spin_lock_irqsave(hba->host->host_lock, flags); hba->sdev_ufs_device = NULL; spin_unlock_irqrestore(hba->host->host_lock, flags); + } else if (hba->sdev_ufs_device) { + struct device *supplier = NULL; + + /* Ensure UFS Device WLUN exists and does not disappear */ + spin_lock_irqsave(hba->host->host_lock, flags); + if (hba->sdev_ufs_device) { + supplier = &hba->sdev_ufs_device->sdev_gendev; + get_device(supplier); + } + spin_unlock_irqrestore(hba->host->host_lock, flags); + + if (supplier) { + /* + * If a LUN fails to probe (e.g. absent BOOT WLUN), the + * device will not have been registered but can still + * have a device link holding a reference to the device. + */ + device_link_remove(&sdev->sdev_gendev, supplier); + put_device(supplier); + } } } |