| Date | Wed, 09 Nov 2011 13:30:56 -0800 | From | Greg KH <> | Subject | [009/264] staging: quatech_usb2: Potential lost wakeup scenario in TIOCMIWAIT |
| |
3.1-stable review patch. If anyone has any objections, please let me know.
------------------
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 */
|