diff options
author | Jiri Slaby <jirislaby@gmail.com> | 2008-09-08 19:23:03 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2008-10-14 17:50:59 -0400 |
commit | d92870ddd248e8c2562a8c4047885d3ad221ece7 (patch) | |
tree | 27dc3359f8ed8beff068eda6feae205f0d136a79 | |
parent | d1d3a5f6eaee337d793ab9ac28e696f0262c3c8a (diff) |
HID: fix tty<->hid deadlock
hid_compat_load() runs on the default workqueue, it request_module(), it
execs modprobe, it exits, tty flushes default workqueue, it hangs, because
we are still in it.
Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
Tested-by: <Valdis.Kletnieks@vt.edu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r-- | drivers/hid/hid-core.c | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 18b277a833f0..63c8ce5540fe 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
@@ -1657,6 +1657,7 @@ static void hid_compat_load(struct work_struct *ws) | |||
1657 | request_module("hid-dummy"); | 1657 | request_module("hid-dummy"); |
1658 | } | 1658 | } |
1659 | static DECLARE_WORK(hid_compat_work, hid_compat_load); | 1659 | static DECLARE_WORK(hid_compat_work, hid_compat_load); |
1660 | static struct workqueue_struct *hid_compat_wq; | ||
1660 | #endif | 1661 | #endif |
1661 | 1662 | ||
1662 | static int __init hid_init(void) | 1663 | static int __init hid_init(void) |
@@ -1674,7 +1675,12 @@ static int __init hid_init(void) | |||
1674 | goto err_bus; | 1675 | goto err_bus; |
1675 | 1676 | ||
1676 | #ifdef CONFIG_HID_COMPAT | 1677 | #ifdef CONFIG_HID_COMPAT |
1677 | schedule_work(&hid_compat_work); | 1678 | hid_compat_wq = create_workqueue("hid_compat"); |
1679 | if (!hid_compat_wq) { | ||
1680 | hidraw_exit(); | ||
1681 | goto err; | ||
1682 | } | ||
1683 | queue_work(hid_compat_wq, &hid_compat_work); | ||
1678 | #endif | 1684 | #endif |
1679 | 1685 | ||
1680 | return 0; | 1686 | return 0; |
@@ -1686,6 +1692,9 @@ err: | |||
1686 | 1692 | ||
1687 | static void __exit hid_exit(void) | 1693 | static void __exit hid_exit(void) |
1688 | { | 1694 | { |
1695 | #ifdef CONFIG_HID_COMPAT | ||
1696 | destroy_workqueue(hid_compat_wq); | ||
1697 | #endif | ||
1689 | hidraw_exit(); | 1698 | hidraw_exit(); |
1690 | bus_unregister(&hid_bus_type); | 1699 | bus_unregister(&hid_bus_type); |
1691 | } | 1700 | } |