diff options
author | Tomas Winkler <tomas.winkler@intel.com> | 2015-10-28 08:34:34 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-10-28 20:02:16 -0400 |
commit | 2da55cfd603d1c08dd1a396f943d6205eca47227 (patch) | |
tree | 74006b846090085e41dd0e86ea2ec3801331a09b | |
parent | 2be7010cad9ed7a3b67a84c274db1e7bc70e0556 (diff) |
mei: bus: use correct lock ordering
The correct lock order is
cl_bus_lock
device_lock
me_clients_rwsem
This order was violated in bus rescan and remove routines
when me_client_rwsem was locked before cl_bus_lock.
Chain exists of:
[ 4.321653] &dev->device_lock --> &dev->me_clients_rwsem -->
&dev->cl_bus_lock
[ 4.321653]
[ 4.321679] Possible unsafe locking scenario:
[ 4.321679]
[ 4.321693] CPU0 CPU1
[ 4.321701] ---- ----
[ 4.321709] lock(&dev->cl_bus_lock);
[ 4.321720]
lock(&dev->me_clients_rwsem);
[ 4.321733] lock(&dev->cl_bus_lock);
[ 4.321745] lock(&dev->device_lock);
[ 4.321755]
[ 4.321755] *** DEADLOCK ***
[ 4.321755]
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/misc/mei/bus.c | 18 |
1 files changed, 13 insertions, 5 deletions
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 160e084ae800..46403e48be4f 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c | |||
@@ -830,17 +830,20 @@ static void mei_cl_bus_dev_stop(struct mei_cl_device *cldev) | |||
830 | * mei_cl_bus_dev_destroy - destroy me client devices object | 830 | * mei_cl_bus_dev_destroy - destroy me client devices object |
831 | * | 831 | * |
832 | * @cldev: me client device | 832 | * @cldev: me client device |
833 | * | ||
834 | * Locking: called under "dev->cl_bus_lock" lock | ||
833 | */ | 835 | */ |
834 | static void mei_cl_bus_dev_destroy(struct mei_cl_device *cldev) | 836 | static void mei_cl_bus_dev_destroy(struct mei_cl_device *cldev) |
835 | { | 837 | { |
838 | |||
839 | WARN_ON(!mutex_is_locked(&cldev->bus->cl_bus_lock)); | ||
840 | |||
836 | if (!cldev->is_added) | 841 | if (!cldev->is_added) |
837 | return; | 842 | return; |
838 | 843 | ||
839 | device_del(&cldev->dev); | 844 | device_del(&cldev->dev); |
840 | 845 | ||
841 | mutex_lock(&cldev->bus->cl_bus_lock); | ||
842 | list_del_init(&cldev->bus_list); | 846 | list_del_init(&cldev->bus_list); |
843 | mutex_unlock(&cldev->bus->cl_bus_lock); | ||
844 | 847 | ||
845 | cldev->is_added = 0; | 848 | cldev->is_added = 0; |
846 | put_device(&cldev->dev); | 849 | put_device(&cldev->dev); |
@@ -866,8 +869,10 @@ void mei_cl_bus_remove_devices(struct mei_device *bus) | |||
866 | { | 869 | { |
867 | struct mei_cl_device *cldev, *next; | 870 | struct mei_cl_device *cldev, *next; |
868 | 871 | ||
872 | mutex_lock(&bus->cl_bus_lock); | ||
869 | list_for_each_entry_safe(cldev, next, &bus->device_list, bus_list) | 873 | list_for_each_entry_safe(cldev, next, &bus->device_list, bus_list) |
870 | mei_cl_bus_remove_device(cldev); | 874 | mei_cl_bus_remove_device(cldev); |
875 | mutex_unlock(&bus->cl_bus_lock); | ||
871 | } | 876 | } |
872 | 877 | ||
873 | 878 | ||
@@ -877,12 +882,16 @@ void mei_cl_bus_remove_devices(struct mei_device *bus) | |||
877 | * | 882 | * |
878 | * @bus: mei device | 883 | * @bus: mei device |
879 | * @me_cl: me client | 884 | * @me_cl: me client |
885 | * | ||
886 | * Locking: called under "dev->cl_bus_lock" lock | ||
880 | */ | 887 | */ |
881 | static void mei_cl_bus_dev_init(struct mei_device *bus, | 888 | static void mei_cl_bus_dev_init(struct mei_device *bus, |
882 | struct mei_me_client *me_cl) | 889 | struct mei_me_client *me_cl) |
883 | { | 890 | { |
884 | struct mei_cl_device *cldev; | 891 | struct mei_cl_device *cldev; |
885 | 892 | ||
893 | WARN_ON(!mutex_is_locked(&bus->cl_bus_lock)); | ||
894 | |||
886 | dev_dbg(bus->dev, "initializing %pUl", mei_me_cl_uuid(me_cl)); | 895 | dev_dbg(bus->dev, "initializing %pUl", mei_me_cl_uuid(me_cl)); |
887 | 896 | ||
888 | if (me_cl->bus_added) | 897 | if (me_cl->bus_added) |
@@ -892,10 +901,8 @@ static void mei_cl_bus_dev_init(struct mei_device *bus, | |||
892 | if (!cldev) | 901 | if (!cldev) |
893 | return; | 902 | return; |
894 | 903 | ||
895 | mutex_lock(&cldev->bus->cl_bus_lock); | ||
896 | me_cl->bus_added = true; | 904 | me_cl->bus_added = true; |
897 | list_add_tail(&cldev->bus_list, &bus->device_list); | 905 | list_add_tail(&cldev->bus_list, &bus->device_list); |
898 | mutex_unlock(&cldev->bus->cl_bus_lock); | ||
899 | 906 | ||
900 | } | 907 | } |
901 | 908 | ||
@@ -910,12 +917,13 @@ void mei_cl_bus_rescan(struct mei_device *bus) | |||
910 | struct mei_cl_device *cldev, *n; | 917 | struct mei_cl_device *cldev, *n; |
911 | struct mei_me_client *me_cl; | 918 | struct mei_me_client *me_cl; |
912 | 919 | ||
920 | mutex_lock(&bus->cl_bus_lock); | ||
921 | |||
913 | down_read(&bus->me_clients_rwsem); | 922 | down_read(&bus->me_clients_rwsem); |
914 | list_for_each_entry(me_cl, &bus->me_clients, list) | 923 | list_for_each_entry(me_cl, &bus->me_clients, list) |
915 | mei_cl_bus_dev_init(bus, me_cl); | 924 | mei_cl_bus_dev_init(bus, me_cl); |
916 | up_read(&bus->me_clients_rwsem); | 925 | up_read(&bus->me_clients_rwsem); |
917 | 926 | ||
918 | mutex_lock(&bus->cl_bus_lock); | ||
919 | list_for_each_entry_safe(cldev, n, &bus->device_list, bus_list) { | 927 | list_for_each_entry_safe(cldev, n, &bus->device_list, bus_list) { |
920 | 928 | ||
921 | if (!mei_me_cl_is_active(cldev->me_cl)) { | 929 | if (!mei_me_cl_is_active(cldev->me_cl)) { |