aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/devices.c
diff options
context:
space:
mode:
authorOliver Neukum <oliver@neukum.org>2010-01-13 09:30:47 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2010-03-02 17:54:22 -0500
commit554f76962d3a6eb5110415f1591aca83f96a84ae (patch)
tree8b0408fafca6558b626be65eed95a52587f32b1b /drivers/usb/core/devices.c
parent08add0c780b9f5c35de49d83abb7a4e14a9cd457 (diff)
USB: Remove BKL from poll()
Replace BKL with usbfs_mutex to protect a global counter and a per file data structure Signed-off-by: Oliver Neukum <oliver@neukum.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core/devices.c')
-rw-r--r--drivers/usb/core/devices.c28
1 files changed, 9 insertions, 19 deletions
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index 355dffcc23b0..175529fd02f3 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
120static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq); 120static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq);
121/* guarded by usbfs_mutex */
121static unsigned int conndiscevcnt; 122static 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
157void usbfs_conn_disc_event(void) 158void 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,
629static unsigned int usb_device_poll(struct file *file, 632static 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 }
661lost_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