On Sat, Apr 23, 2022 at 02:22:18PM -0700, Dan Williams wrote:
> Lockdep reports the following deadlock scenarios for CXL root device
> power-management, device_prepare(), operations, and device_shutdown()
> operations for 'nd_region' devices:
> 
> ---
>  Chain exists of:
>    &nvdimm_region_key --> &nvdimm_bus->reconfig_mutex --> 
> system_transition_mutex
> 
>   Possible unsafe locking scenario:
> 
>         CPU0                    CPU1
>         ----                    ----
>    lock(system_transition_mutex);
>                                 lock(&nvdimm_bus->reconfig_mutex);
>                                 lock(system_transition_mutex);
>    lock(&nvdimm_region_key);
> 
> --
> 
>  Chain exists of:
>    &cxl_nvdimm_bridge_key --> acpi_scan_lock --> &cxl_root_key
> 
>   Possible unsafe locking scenario:
> 
>         CPU0                    CPU1
>         ----                    ----
>    lock(&cxl_root_key);
>                                 lock(acpi_scan_lock);
>                                 lock(&cxl_root_key);
>    lock(&cxl_nvdimm_bridge_key);
> 
> ---
> 
> These stem from holding nvdimm_bus_lock() over hibernate_quiet_exec()
> which walks the entire system device topology taking device_lock() along
> the way. The nvdimm_bus_lock() is protecting against unregistration,
> multiple simultaneous ops callers, and preventing activate_show() from
> racing activate_store(). For the first 2, the lock is redundant.
> Unregistration already flushes all ops users, and sysfs already prevents
> multiple threads to be active in an ops handler at the same time. For
> the last userspace should already be waiting for its last
> activate_store() to complete, and does not need activate_show() to flush
> the write side, so this lock usage can be deleted in these attributes.
> 
> Fixes: 48001ea50d17 ("PM, libnvdimm: Add runtime firmware activation support")
> Signed-off-by: Dan Williams <[email protected]>

Reviewed-by: Ira Weiny <[email protected]>

> ---
> Changes since v3:
> - Remove nvdimm_bus_lock() from all ->capability() invocations (Ira)
> 
>  drivers/nvdimm/core.c |    9 ---------
>  1 file changed, 9 deletions(-)
> 
> diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c
> index 144926b7451c..d91799b71d23 100644
> --- a/drivers/nvdimm/core.c
> +++ b/drivers/nvdimm/core.c
> @@ -368,9 +368,7 @@ static ssize_t capability_show(struct device *dev,
>       if (!nd_desc->fw_ops)
>               return -EOPNOTSUPP;
>  
> -     nvdimm_bus_lock(dev);
>       cap = nd_desc->fw_ops->capability(nd_desc);
> -     nvdimm_bus_unlock(dev);
>  
>       switch (cap) {
>       case NVDIMM_FWA_CAP_QUIESCE:
> @@ -395,10 +393,8 @@ static ssize_t activate_show(struct device *dev,
>       if (!nd_desc->fw_ops)
>               return -EOPNOTSUPP;
>  
> -     nvdimm_bus_lock(dev);
>       cap = nd_desc->fw_ops->capability(nd_desc);
>       state = nd_desc->fw_ops->activate_state(nd_desc);
> -     nvdimm_bus_unlock(dev);
>  
>       if (cap < NVDIMM_FWA_CAP_QUIESCE)
>               return -EOPNOTSUPP;
> @@ -443,7 +439,6 @@ static ssize_t activate_store(struct device *dev,
>       else
>               return -EINVAL;
>  
> -     nvdimm_bus_lock(dev);
>       state = nd_desc->fw_ops->activate_state(nd_desc);
>  
>       switch (state) {
> @@ -461,7 +456,6 @@ static ssize_t activate_store(struct device *dev,
>       default:
>               rc = -ENXIO;
>       }
> -     nvdimm_bus_unlock(dev);
>  
>       if (rc == 0)
>               rc = len;
> @@ -484,10 +478,7 @@ static umode_t nvdimm_bus_firmware_visible(struct 
> kobject *kobj, struct attribut
>       if (!nd_desc->fw_ops)
>               return 0;
>  
> -     nvdimm_bus_lock(dev);
>       cap = nd_desc->fw_ops->capability(nd_desc);
> -     nvdimm_bus_unlock(dev);
> -
>       if (cap < NVDIMM_FWA_CAP_QUIESCE)
>               return 0;
>  
> 

Reply via email to