| From 19bb2e79deed0f9d8b2165e8a5c1dfc6fce7c72b Mon Sep 17 00:00:00 2001 |
| From: Alexander Duyck <alexander.h.duyck@linux.intel.com> |
| Date: Wed, 28 Nov 2018 16:32:11 -0800 |
| Subject: driver core: Move async_synchronize_full call |
| |
| [ Upstream commit c37d721c68ad88925ba0e72f6e14acb829a8c6bb ] |
| |
| Move the async_synchronize_full call out of __device_release_driver and |
| into driver_detach. |
| |
| The idea behind this is that the async_synchronize_full call will only |
| guarantee that any existing async operations are flushed. This doesn't do |
| anything to guarantee that a hotplug event that may occur while we are |
| doing the release of the driver will not be asynchronously scheduled. |
| |
| By moving this into the driver_detach path we can avoid potential deadlocks |
| as we aren't holding the device lock at this point and we should not have |
| the driver we want to flush loaded so the flush will take care of any |
| asynchronous events the driver we are detaching might have scheduled. |
| |
| Fixes: 765230b5f084 ("driver-core: add asynchronous probing support for drivers") |
| Reviewed-by: Bart Van Assche <bvanassche@acm.org> |
| Reviewed-by: Dan Williams <dan.j.williams@intel.com> |
| Signed-off-by: Alexander Duyck <alexander.h.duyck@linux.intel.com> |
| Reviewed-by: Luis Chamberlain <mcgrof@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/base/dd.c | 6 +++--- |
| 1 file changed, 3 insertions(+), 3 deletions(-) |
| |
| diff --git a/drivers/base/dd.c b/drivers/base/dd.c |
| index 55fc31f6fe7f..d928cc6d0638 100644 |
| --- a/drivers/base/dd.c |
| +++ b/drivers/base/dd.c |
| @@ -813,9 +813,6 @@ static void __device_release_driver(struct device *dev, struct device *parent) |
| |
| drv = dev->driver; |
| if (drv) { |
| - if (driver_allows_async_probing(drv)) |
| - async_synchronize_full(); |
| - |
| while (device_links_busy(dev)) { |
| device_unlock(dev); |
| if (parent) |
| @@ -920,6 +917,9 @@ void driver_detach(struct device_driver *drv) |
| struct device_private *dev_prv; |
| struct device *dev; |
| |
| + if (driver_allows_async_probing(drv)) |
| + async_synchronize_full(); |
| + |
| for (;;) { |
| spin_lock(&drv->p->klist_devices.k_lock); |
| if (list_empty(&drv->p->klist_devices.k_list)) { |
| -- |
| 2.19.1 |
| |