coresight_get_ref() currently pins the provider module and takes a reference on the parent device. That does not pin the CoreSight device itself.
A driver can still be unbound while the CoreSight device is part of an active trace path. In that case coresight_unregister() may release the coresight_device while the path still holds its csdev pointer.
Take a reference on &csdev->dev when grabbing a CoreSight device and drop it in coresight_put_ref().
Signed-off-by: Leo Yan leo.yan@arm.com --- drivers/hwtracing/coresight/coresight-core.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 5519d323f21f38d719b9030c7d77a9a61948ba1d..1a389f63ed006e054dc6bc9764f8be8c1def9da1 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -651,14 +651,18 @@ struct coresight_device *coresight_get_sink_by_id(u32 id) */ static bool coresight_get_ref(struct coresight_device *csdev) { - struct device *dev = csdev->dev.parent; + struct device *parent = csdev->dev.parent;
/* Make sure the driver can't be removed */ - if (!try_module_get(dev->driver->owner)) + if (!try_module_get(parent->driver->owner)) return false; - /* Make sure the device can't go away */ - get_device(dev); - pm_runtime_get_sync(dev); + + /* Make sure parent device can't go away and is powered on */ + get_device(parent); + pm_runtime_get_sync(parent); + + /* Make sure csdev can't go away */ + get_device(&csdev->dev); return true; }
@@ -670,11 +674,12 @@ static bool coresight_get_ref(struct coresight_device *csdev) */ static void coresight_put_ref(struct coresight_device *csdev) { - struct device *dev = csdev->dev.parent; + struct device *parent = csdev->dev.parent;
- pm_runtime_put(dev); - put_device(dev); - module_put(dev->driver->owner); + put_device(&csdev->dev); + pm_runtime_put(parent); + put_device(parent); + module_put(parent->driver->owner); }
/*