Re: [RESEND PATCH V3 1/3] USB: serial: f81232: clear overrun flag

From: Oliver Neukum
Date: Mon Apr 01 2019 - 04:35:03 EST


On Mo, 2019-04-01 at 14:00 +0800, Ji-Ze Hong (Peter Hong) wrote:

Hi,
I am afraid there is a race condiion in this code.


> @@ -315,6 +318,7 @@ static void f81232_process_read_urb(struct urb *urb)
>
> if (lsr & UART_LSR_OE) {
> port->icount.overrun++;
> + schedule_work(&priv->lsr_work);

Unconditionally scheduled

> tty_insert_flip_char(&port->port, 0,
> TTY_OVERRUN);
> }

[..]
> +static int f81232_suspend(struct usb_serial *serial, pm_message_t message)
> +{
> + struct f81232_private *port_priv;
> +
> + port_priv = usb_get_serial_port_data(serial->port[0]);
> + flush_work(&port_priv->lsr_work);
> +
> + return 0;
> +}
> +
> static struct usb_serial_driver f81232_device = {
> .driver = {
> .owner = THIS_MODULE,
> @@ -655,6 +688,7 @@ static struct usb_serial_driver f81232_device = {
> .read_int_callback = f81232_read_int_callback,
> .port_probe = f81232_port_probe,
> .port_remove = f81232_port_remove,
> + .suspend = f81232_suspend,

Please have a look at:
int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
{
struct usb_serial *serial = usb_get_intfdata(intf);
int i, r = 0;


serial->suspending = 1;


/*
* serial->type->suspend() MUST return 0 in system sleep context,
* otherwise, the resume callback has to recover device from
* previous suspend failure.
*/
if (serial->type->suspend) {
r = serial->type->suspend(serial, message);
if (r < 0) {
serial->suspending = 0;
goto err_out;
}
}


for (i = 0; i < serial->num_ports; ++i)
usb_serial_port_poison_urbs(serial->port[i]);
err_out:
return r;
}
EXPORT_SYMBOL(usb_serial_suspend);

As you can see, the suspend method is called first and then the URBs
are poisoned. That means that after you have flushed the work, it may
be submitted again. The fix would be to test the 'suspending' flag
before you schedule work (and recheck the need to schedule it
during resume)

Regards
Oliver