Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Kautuk Consul and committed by
Greg Kroah-Hartman
e8df1674 e228b742

+7 -2
+7 -2
drivers/staging/quatech_usb2/quatech_usb2.c
··· 916 916 dbg("%s() port %d, cmd == TIOCMIWAIT enter", 917 917 __func__, port->number); 918 918 prev_msr_value = port_extra->shadowMSR & QT2_SERIAL_MSR_MASK; 919 + barrier(); 920 + __set_current_state(TASK_INTERRUPTIBLE); 919 921 while (1) { 920 922 add_wait_queue(&port_extra->wait, &wait); 921 - set_current_state(TASK_INTERRUPTIBLE); 922 923 schedule(); 923 924 dbg("%s(): port %d, cmd == TIOCMIWAIT here\n", 924 925 __func__, port->number); ··· 927 926 /* see if a signal woke us up */ 928 927 if (signal_pending(current)) 929 928 return -ERESTARTSYS; 929 + set_current_state(TASK_INTERRUPTIBLE); 930 930 msr_value = port_extra->shadowMSR & QT2_SERIAL_MSR_MASK; 931 - if (msr_value == prev_msr_value) 931 + if (msr_value == prev_msr_value) { 932 + __set_current_state(TASK_RUNNING); 932 933 return -EIO; /* no change - error */ 934 + } 933 935 if ((arg & TIOCM_RNG && 934 936 ((prev_msr_value & QT2_SERIAL_MSR_RI) == 935 937 (msr_value & QT2_SERIAL_MSR_RI))) || ··· 945 941 (arg & TIOCM_CTS && 946 942 ((prev_msr_value & QT2_SERIAL_MSR_CTS) == 947 943 (msr_value & QT2_SERIAL_MSR_CTS)))) { 944 + __set_current_state(TASK_RUNNING); 948 945 return 0; 949 946 } 950 947 } /* end inifinite while */