summaryrefslogtreecommitdiffstats
path: root/drivers/staging/quatech_usb2
diff options
context:
space:
mode:
authorKautuk Consul <consul.kautuk@gmail.com>2011-09-14 08:56:21 +0530
committerGreg Kroah-Hartman <gregkh@suse.de>2011-09-19 10:46:18 -0700
commite8df1674d383d2ecc6efa8d7dba74c03aafdfdd7 (patch)
tree029417765ee8f4d4e38b055f1744d1152417f8ae /drivers/staging/quatech_usb2
parente228b7426e65df0f2e93c783c2c89baabe318b9b (diff)
downloadlinux-stable-e8df1674d383d2ecc6efa8d7dba74c03aafdfdd7.tar.gz
linux-stable-e8df1674d383d2ecc6efa8d7dba74c03aafdfdd7.tar.bz2
linux-stable-e8df1674d383d2ecc6efa8d7dba74c03aafdfdd7.zip
staging: quatech_usb2: Potential lost wakeup scenario in TIOCMIWAIT
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> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/quatech_usb2')
-rw-r--r--drivers/staging/quatech_usb2/quatech_usb2.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/drivers/staging/quatech_usb2/quatech_usb2.c b/drivers/staging/quatech_usb2/quatech_usb2.c
index ca098cabc2bc..02fafecd4773 100644
--- 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 *tty,
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 *tty,
/* 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 *tty,
(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 */