mei: amthif: fix deadlock in initialization during a reset
authorAlexander Usyskin <alexander.usyskin@intel.com>
Mon, 25 Jul 2016 22:06:09 +0000 (01:06 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 30 Aug 2016 12:39:43 +0000 (14:39 +0200)
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@vger.kernel.org> # 4.6+
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/misc/mei/amthif.c
drivers/misc/mei/bus.c

index 2222b60e92083976de2a0b3209c197bac759d3ce..082462ea90c92ec47cbf5bd7695ea705cfcecea0 100644 (file)
@@ -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;
 }
 
index cdf13f6d2697e4b0fba5763f39eeda4f060f370e..8cac7ef9ad0d98789c3f910dced1b61bc2b3ab62 100644 (file)
@@ -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);
 }