aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-03-06 19:34:34 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2010-03-06 19:34:34 -0500
commit7bc80cd935a4d5fd8574f6994bd95d0aad273d56 (patch)
tree8251afeab690b2f2d81bc403fef224160fc83bc6 /drivers
parent66b89159c25a47d2177743526c61b5ada7acc39e (diff)
usbfs: fix deadlock on 'usbfs_mutex', clean up poll
The caller of usbfs_conn_disc_event() in some cases (but not always) already holds usbfs_mutex, so trying to protect the event counter with that lock causes nasty deadlocks. The problem was introduced by commit 554f76962d ("USB: Remove BKL from poll()") when the BLK protection was turned into using the mutex instead. So fix this by using an atomic variable instead. And while we're at it, get rid of the atrocious naming of said variable and the waitqueue it is associated with. This also cleans up the unnecessary locking in the poll routine, since the whole point of how the pollwait table works is that you can just add yourself to the waiting list, and then check the condition you're waiting for afterwards - avoiding all races. It also gets rid of the unnecessary dynamic allocation of the device status that just contained a single word. We should use f_version for this, as Dmitry Torokhov points out. That simplifies everything further. Reported-and-tested-by: Jeff Chua <jeff.chua.linux@gmail.com> Acked-by: Greg Kroah-Hartman <gregkh@suse.de> Acked-by: Alan Stern <stern@rowland.harvard.edu> Cc: Oliver Neukum <oliver@neukum.org> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/core/devices.c66
1 files changed, 24 insertions, 42 deletions
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index c83c975152a6..6053a8b730cd 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -117,9 +117,21 @@ static const char *format_endpt =
117 * However, these will come from functions that return ptrs to each of them. 117 * However, these will come from functions that return ptrs to each of them.
118 */ 118 */
119 119
120static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq); 120/*
121/* guarded by usbfs_mutex */ 121 * Wait for an connect/disconnect event to happen. We initialize
122static unsigned int conndiscevcnt; 122 * the event counter with an odd number, and each event will increment
123 * the event counter by two, so it will always _stay_ odd. That means
124 * that it will never be zero, so "event 0" will never match a current
125 * event, and thus 'poll' will always trigger as readable for the first
126 * time it gets called.
127 */
128static struct device_connect_event {
129 atomic_t count;
130 wait_queue_head_t wait;
131} device_event = {
132 .count = ATOMIC_INIT(1),
133 .wait = __WAIT_QUEUE_HEAD_INITIALIZER(device_event.wait)
134};
123 135
124/* this struct stores the poll state for <mountpoint>/devices pollers */ 136/* this struct stores the poll state for <mountpoint>/devices pollers */
125struct usb_device_status { 137struct usb_device_status {
@@ -157,10 +169,8 @@ static const struct class_info clas_info[] =
157 169
158void usbfs_conn_disc_event(void) 170void usbfs_conn_disc_event(void)
159{ 171{
160 mutex_lock(&usbfs_mutex); 172 atomic_add(2, &device_event.count);
161 conndiscevcnt++; 173 wake_up(&device_event.wait);
162 mutex_unlock(&usbfs_mutex);
163 wake_up(&deviceconndiscwq);
164} 174}
165 175
166static const char *class_decode(const int class) 176static const char *class_decode(const int class)
@@ -632,42 +642,16 @@ static ssize_t usb_device_read(struct file *file, char __user *buf,
632static unsigned int usb_device_poll(struct file *file, 642static unsigned int usb_device_poll(struct file *file,
633 struct poll_table_struct *wait) 643 struct poll_table_struct *wait)
634{ 644{
635 struct usb_device_status *st; 645 unsigned int event_count;
636 unsigned int mask = 0;
637
638 mutex_lock(&usbfs_mutex);
639 st = file->private_data;
640 if (!st) {
641 st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL);
642 if (!st) {
643 mutex_unlock(&usbfs_mutex);
644 return POLLIN;
645 }
646
647 st->lastev = conndiscevcnt;
648 file->private_data = st;
649 mask = POLLIN;
650 }
651 646
652 if (file->f_mode & FMODE_READ) 647 poll_wait(file, &device_event.wait, wait);
653 poll_wait(file, &deviceconndiscwq, wait);
654 if (st->lastev != conndiscevcnt)
655 mask |= POLLIN;
656 st->lastev = conndiscevcnt;
657 mutex_unlock(&usbfs_mutex);
658 return mask;
659}
660 648
661static int usb_device_open(struct inode *inode, struct file *file) 649 event_count = atomic_read(&device_event.count);
662{ 650 if (file->f_version != event_count) {
663 file->private_data = NULL; 651 file->f_version = event_count;
664 return 0; 652 return POLLIN | POLLRDNORM;
665} 653 }
666 654
667static int usb_device_release(struct inode *inode, struct file *file)
668{
669 kfree(file->private_data);
670 file->private_data = NULL;
671 return 0; 655 return 0;
672} 656}
673 657
@@ -699,6 +683,4 @@ const struct file_operations usbfs_devices_fops = {
699 .llseek = usb_device_lseek, 683 .llseek = usb_device_lseek,
700 .read = usb_device_read, 684 .read = usb_device_read,
701 .poll = usb_device_poll, 685 .poll = usb_device_poll,
702 .open = usb_device_open,
703 .release = usb_device_release,
704}; 686};