diff options
-rw-r--r-- | drivers/usb/core/devices.c | 28 |
1 files changed, 9 insertions, 19 deletions
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 355dffcc23b..175529fd02f 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c | |||
@@ -118,6 +118,7 @@ static const char *format_endpt = | |||
118 | */ | 118 | */ |
119 | 119 | ||
120 | static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq); | 120 | static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq); |
121 | /* guarded by usbfs_mutex */ | ||
121 | static unsigned int conndiscevcnt; | 122 | static unsigned int conndiscevcnt; |
122 | 123 | ||
123 | /* this struct stores the poll state for <mountpoint>/devices pollers */ | 124 | /* this struct stores the poll state for <mountpoint>/devices pollers */ |
@@ -156,7 +157,9 @@ static const struct class_info clas_info[] = | |||
156 | 157 | ||
157 | void usbfs_conn_disc_event(void) | 158 | void usbfs_conn_disc_event(void) |
158 | { | 159 | { |
160 | mutex_lock(&usbfs_mutex); | ||
159 | conndiscevcnt++; | 161 | conndiscevcnt++; |
162 | mutex_unlock(&usbfs_mutex); | ||
160 | wake_up(&deviceconndiscwq); | 163 | wake_up(&deviceconndiscwq); |
161 | } | 164 | } |
162 | 165 | ||
@@ -629,42 +632,29 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, | |||
629 | static unsigned int usb_device_poll(struct file *file, | 632 | static unsigned int usb_device_poll(struct file *file, |
630 | struct poll_table_struct *wait) | 633 | struct poll_table_struct *wait) |
631 | { | 634 | { |
632 | struct usb_device_status *st = file->private_data; | 635 | struct usb_device_status *st; |
633 | unsigned int mask = 0; | 636 | unsigned int mask = 0; |
634 | 637 | ||
635 | lock_kernel(); | 638 | mutex_lock(&usbfs_mutex); |
639 | st = file->private_data; | ||
636 | if (!st) { | 640 | if (!st) { |
637 | st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL); | 641 | st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL); |
638 | |||
639 | /* we may have dropped BKL - | ||
640 | * need to check for having lost the race */ | ||
641 | if (file->private_data) { | ||
642 | kfree(st); | ||
643 | st = file->private_data; | ||
644 | goto lost_race; | ||
645 | } | ||
646 | /* we haven't lost - check for allocation failure now */ | ||
647 | if (!st) { | 642 | if (!st) { |
648 | unlock_kernel(); | 643 | mutex_unlock(&usbfs_mutex); |
649 | return POLLIN; | 644 | return POLLIN; |
650 | } | 645 | } |
651 | 646 | ||
652 | /* | ||
653 | * need to prevent the module from being unloaded, since | ||
654 | * proc_unregister does not call the release method and | ||
655 | * we would have a memory leak | ||
656 | */ | ||
657 | st->lastev = conndiscevcnt; | 647 | st->lastev = conndiscevcnt; |
658 | file->private_data = st; | 648 | file->private_data = st; |
659 | mask = POLLIN; | 649 | mask = POLLIN; |
660 | } | 650 | } |
661 | lost_race: | 651 | |
662 | if (file->f_mode & FMODE_READ) | 652 | if (file->f_mode & FMODE_READ) |
663 | poll_wait(file, &deviceconndiscwq, wait); | 653 | poll_wait(file, &deviceconndiscwq, wait); |
664 | if (st->lastev != conndiscevcnt) | 654 | if (st->lastev != conndiscevcnt) |
665 | mask |= POLLIN; | 655 | mask |= POLLIN; |
666 | st->lastev = conndiscevcnt; | 656 | st->lastev = conndiscevcnt; |
667 | unlock_kernel(); | 657 | mutex_unlock(&usbfs_mutex); |
668 | return mask; | 658 | return mask; |
669 | } | 659 | } |
670 | 660 | ||