[char-misc-next v2 9/9] mei: amthif: fix deadlock in initialization during a reset

From: Tomas Winkler
Date: Mon Jul 25 2016 - 18:07:39 EST


From: Alexander Usyskin <alexander.usyskin@xxxxxxxxx>

The device lock was unnecessary obtained in bus rescan work before the
amthif client search. That causes incorrect lock ordering and task
hang:
...
[88004.613213] INFO: task kworker/1:14:21832 blocked for more than 120 seconds.
...
[88004.645934] Workqueue: events mei_cl_bus_rescan_work
...

The correct lock order is
cl_bus_lock
device_lock
me_clients_rwsem

Move device_lock into amthif init function that called
after me_clients_rwsem is released.

This fixes regression introduced by commit:
commit 025fb792bac3 ("mei: split amthif client init from end of clients enumeration")

Cc: <stable@xxxxxxxxxxxxxxx> # 4.6+
Signed-off-by: Alexander Usyskin <alexander.usyskin@xxxxxxxxx>
Signed-off-by: Tomas Winkler <tomas.winkler@xxxxxxxxx>
---
V2: new in the seriese

drivers/misc/mei/amthif.c | 12 +++++++++---
drivers/misc/mei/bus.c | 2 --
2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 2222b60e9208..082462ea90c9 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -66,8 +66,12 @@ int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
struct mei_cl *cl = &dev->iamthif_cl;
int ret;

- if (mei_cl_is_connected(cl))
- return 0;
+ mutex_lock(&dev->device_lock);
+
+ if (mei_cl_is_connected(cl)) {
+ ret = 0;
+ goto out;
+ }

dev->iamthif_state = MEI_IAMTHIF_IDLE;

@@ -76,11 +80,13 @@ int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
ret = mei_cl_link(cl);
if (ret < 0) {
dev_err(dev->dev, "amthif: failed cl_link %d\n", ret);
- return ret;
+ goto out;
}

ret = mei_cl_connect(cl, me_cl, NULL);

+out:
+ mutex_unlock(&dev->device_lock);
return ret;
}

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index cdf13f6d2697..8cac7ef9ad0d 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -984,12 +984,10 @@ void mei_cl_bus_rescan_work(struct work_struct *work)
container_of(work, struct mei_device, bus_rescan_work);
struct mei_me_client *me_cl;

- mutex_lock(&bus->device_lock);
me_cl = mei_me_cl_by_uuid(bus, &mei_amthif_guid);
if (me_cl)
mei_amthif_host_init(bus, me_cl);
mei_me_cl_put(me_cl);
- mutex_unlock(&bus->device_lock);

mei_cl_bus_rescan(bus);
}
--
2.7.4