diff options
Diffstat (limited to 'drivers/hid/usbhid/hiddev.c')
| -rw-r--r-- | drivers/hid/usbhid/hiddev.c | 19 |
1 files changed, 17 insertions, 2 deletions
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 433602aed468..c24d2fa3e3b6 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c | |||
| @@ -267,6 +267,7 @@ static int hiddev_open(struct inode *inode, struct file *file) | |||
| 267 | struct hiddev_list *list; | 267 | struct hiddev_list *list; |
| 268 | int res, i; | 268 | int res, i; |
| 269 | 269 | ||
| 270 | /* See comment in hiddev_connect() for BKL explanation */ | ||
| 270 | lock_kernel(); | 271 | lock_kernel(); |
| 271 | i = iminor(inode) - HIDDEV_MINOR_BASE; | 272 | i = iminor(inode) - HIDDEV_MINOR_BASE; |
| 272 | 273 | ||
| @@ -894,8 +895,22 @@ int hiddev_connect(struct hid_device *hid, unsigned int force) | |||
| 894 | hiddev->hid = hid; | 895 | hiddev->hid = hid; |
| 895 | hiddev->exist = 1; | 896 | hiddev->exist = 1; |
| 896 | 897 | ||
| 897 | /* when lock_kernel() usage is fixed in usb_open(), | 898 | /* |
| 898 | * we could also fix it here */ | 899 | * BKL here is used to avoid race after usb_register_dev(). |
| 900 | * Once the device node has been created, open() could happen on it. | ||
| 901 | * The code below will then fail, as hiddev_table hasn't been | ||
| 902 | * updated. | ||
| 903 | * | ||
| 904 | * The obvious fix -- introducing mutex to guard hiddev_table[] | ||
| 905 | * doesn't work, as usb_open() and usb_register_dev() both take | ||
| 906 | * minor_rwsem, thus we'll have ABBA deadlock. | ||
| 907 | * | ||
| 908 | * Before BKL pushdown, usb_open() had been acquiring it in right | ||
| 909 | * order, so _open() was safe to use it to protect from this race. | ||
| 910 | * Now the order is different, but AB-BA deadlock still doesn't occur | ||
| 911 | * as BKL is dropped on schedule() (i.e. while sleeping on | ||
| 912 | * minor_rwsem). Fugly. | ||
| 913 | */ | ||
| 899 | lock_kernel(); | 914 | lock_kernel(); |
| 900 | retval = usb_register_dev(usbhid->intf, &hiddev_class); | 915 | retval = usb_register_dev(usbhid->intf, &hiddev_class); |
| 901 | if (retval) { | 916 | if (retval) { |
