| From e8df1674d383d2ecc6efa8d7dba74c03aafdfdd7 Mon Sep 17 00:00:00 2001 |
| From: Kautuk Consul <consul.kautuk@gmail.com> |
| Date: Wed, 14 Sep 2011 08:56:21 +0530 |
| Subject: staging: quatech_usb2: Potential lost wakeup scenario in TIOCMIWAIT |
| |
| From: Kautuk Consul <consul.kautuk@gmail.com> |
| |
| commit e8df1674d383d2ecc6efa8d7dba74c03aafdfdd7 upstream. |
| |
| If the usermode app does an ioctl over this serial device by |
| using TIOCMIWAIT, then the code will wait by setting the current |
| task state to TASK_INTERRUPTIBLE and then calling schedule(). |
| This will be woken up by the qt2_process_modem_status on URB |
| completion when the port_extra->shadowMSR is set to the new |
| modem status. |
| |
| However, this could result in a lost wakeup scenario due to a race |
| in the logic in the qt2_ioctl(TIOCMIWAIT) loop and the URB completion |
| for new modem status in qt2_process_modem_status. |
| Due to this, the usermode app's task will continue to sleep despite a |
| change in the modem status. |
| |
| Signed-off-by: Kautuk Consul <consul.kautuk@gmail.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| drivers/staging/quatech_usb2/quatech_usb2.c | 9 +++++++-- |
| 1 file changed, 7 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/staging/quatech_usb2/quatech_usb2.c |
| +++ b/drivers/staging/quatech_usb2/quatech_usb2.c |
| @@ -916,9 +916,10 @@ static int qt2_ioctl(struct tty_struct * |
| dbg("%s() port %d, cmd == TIOCMIWAIT enter", |
| __func__, port->number); |
| prev_msr_value = port_extra->shadowMSR & QT2_SERIAL_MSR_MASK; |
| + barrier(); |
| + __set_current_state(TASK_INTERRUPTIBLE); |
| while (1) { |
| add_wait_queue(&port_extra->wait, &wait); |
| - set_current_state(TASK_INTERRUPTIBLE); |
| schedule(); |
| dbg("%s(): port %d, cmd == TIOCMIWAIT here\n", |
| __func__, port->number); |
| @@ -926,9 +927,12 @@ static int qt2_ioctl(struct tty_struct * |
| /* see if a signal woke us up */ |
| if (signal_pending(current)) |
| return -ERESTARTSYS; |
| + set_current_state(TASK_INTERRUPTIBLE); |
| msr_value = port_extra->shadowMSR & QT2_SERIAL_MSR_MASK; |
| - if (msr_value == prev_msr_value) |
| + if (msr_value == prev_msr_value) { |
| + __set_current_state(TASK_RUNNING); |
| return -EIO; /* no change - error */ |
| + } |
| if ((arg & TIOCM_RNG && |
| ((prev_msr_value & QT2_SERIAL_MSR_RI) == |
| (msr_value & QT2_SERIAL_MSR_RI))) || |
| @@ -941,6 +945,7 @@ static int qt2_ioctl(struct tty_struct * |
| (arg & TIOCM_CTS && |
| ((prev_msr_value & QT2_SERIAL_MSR_CTS) == |
| (msr_value & QT2_SERIAL_MSR_CTS)))) { |
| + __set_current_state(TASK_RUNNING); |
| return 0; |
| } |
| } /* end inifinite while */ |