Bug 9046 (usb-serial-uevent)

Summary: USB Serial not sending uevent on device disconnect if port open
Product: Drivers Reporter: Tysen Moore (tsmoore)
Component: USBAssignee: Greg Kroah-Hartman (greg)
Status: CLOSED CODE_FIX    
Severity: normal CC: protasnb, yyyeer.bo
Priority: P1    
Hardware: All   
OS: Linux   
Kernel Version: 2.6.20.15 and 2.6.19.2 Subsystem:
Regression: --- Bisected commit-id:
Bug Depends on: 5089    
Bug Blocks:    

Description Tysen Moore 2007-09-20 14:05:59 UTC
Most recent kernel where this bug did not occur: still seen
Distribution: KUbuntu 2.6.20.15 and Freescale BSP 2.6.19.2
Hardware Environment: Dell Optiplex x86 and Freescale ARM Development Board
Software Environment: Vmware running Kubuntu on Windows XP and Embedded ARM development board
Problem Description:
If you have a program that opens a port using usb-serial and the USB device is disconnected there is no uevent indicating the ACTION "remove" for the tty device (e.g ttyUSB0).  Once the port is closed the uevent is triggered and notifies the system the device has disconnected.  When using the port there is no way to get notified that the device has disconnected.  If no ports are open the uevent is sent without problems.  I admit this could be a design decision but it seems like a limitation.  I've seen the same problem in the cdc-acm driver.

I've debugged the problem and found a potential solution.  When the serial->kref is initialized it starts as one.  When the port is opened it obviously gets incremented.  The problem is that on the serial_disconnect there should be a kref_put for each port that calls tty_hangup.  Also the port->tty->driver_data MUST be reset to NULL otherwise when the program closes its open port it will crash the driver.

The proposed change is as follows:
    if (serial) {
		for (i = 0; i < serial->num_ports; ++i) {
			port = serial->port[i];
			if (port && port->tty)
            {
                tty_hangup(port->tty);

+                /* prevents a close from an open device crashing the driver */
+               port->tty->driver_data = NULL; 
+
+               /* we are also done with the reference used by tty */
+              usb_serial_put(serial);
            }
		}
		/* let the last holder of this object 
		 * cause it to be cleaned up */
		usb_serial_put(serial);
	}
Steps to reproduce:
1. Connect usb-serial device
2. Open the port (e.g. ttyUSB0) using some program (e.g. minicom)
3. Disconnect the usb-serial device
4. problem occurs here, no uevent for the remove of ttyUSB0.  /dev/ttyUSB0 is still around.
5. Can now kill/terminate the program that had the port open and the uevent will be sent out.
Comment 1 Greg Kroah-Hartman 2007-09-20 14:18:27 UTC
I don't think the patch is needed to keep the code from oopsing, right?  It still works fine to keep a port open and yank out the device.

I ran udevmonitor and if I hold the port open with 'cat', yank out the device, the hangup happens and notifies cat, cat lets the port go, and then the uevent remove event happens.

So I don't see a bug here, what am I missing?

Can you try the 2.6.22 kernel or newer?
Comment 2 Anonymous Emailer 2007-09-20 14:23:39 UTC
Reply-To: akpm@linux-foundation.org

On Thu, 20 Sep 2007 14:05:59 -0700 (PDT)
bugme-daemon@bugzilla.kernel.org wrote:

> http://bugzilla.kernel.org/show_bug.cgi?id=9046
> 
>            Summary: USB Serial not sending uevent on device disconnect if
>                     port open
>            Product: Drivers
>            Version: 2.5
>      KernelVersion: 2.6.20.15 and 2.6.19.2
>           Platform: All
>         OS/Version: Linux
>               Tree: Mainline
>             Status: NEW
>           Severity: normal
>           Priority: P1
>          Component: USB
>         AssignedTo: greg@kroah.com
>         ReportedBy: tsmoore@wideopenwest.com
> 
> 
> Most recent kernel where this bug did not occur: still seen
> Distribution: KUbuntu 2.6.20.15 and Freescale BSP 2.6.19.2
> Hardware Environment: Dell Optiplex x86 and Freescale ARM Development Board
> Software Environment: Vmware running Kubuntu on Windows XP and Embedded ARM
> development board
> Problem Description:
> If you have a program that opens a port using usb-serial and the USB device
> is
> disconnected there is no uevent indicating the ACTION "remove" for the tty
> device (e.g ttyUSB0).  Once the port is closed the uevent is triggered and
> notifies the system the device has disconnected.  When using the port there
> is
> no way to get notified that the device has disconnected.  If no ports are
> open
> the uevent is sent without problems.  I admit this could be a design decision
> but it seems like a limitation.  I've seen the same problem in the cdc-acm
> driver.
> 
> I've debugged the problem and found a potential solution.  When the
> serial->kref is initialized it starts as one.  When the port is opened it
> obviously gets incremented.  The problem is that on the serial_disconnect
> there
> should be a kref_put for each port that calls tty_hangup.  Also the
> port->tty->driver_data MUST be reset to NULL otherwise when the program
> closes
> its open port it will crash the driver.
> 
> The proposed change is as follows:
>     if (serial) {
>                 for (i = 0; i < serial->num_ports; ++i) {
>                         port = serial->port[i];
>                         if (port && port->tty)
>             {
>                 tty_hangup(port->tty);
> 
> +                /* prevents a close from an open device crashing the driver
> */
> +               port->tty->driver_data = NULL; 
> +
> +               /* we are also done with the reference used by tty */
> +              usb_serial_put(serial);
>             }
>                 }
>                 /* let the last holder of this object 
>                  * cause it to be cleaned up */
>                 usb_serial_put(serial);
>         }
> Steps to reproduce:
> 1. Connect usb-serial device
> 2. Open the port (e.g. ttyUSB0) using some program (e.g. minicom)
> 3. Disconnect the usb-serial device
> 4. problem occurs here, no uevent for the remove of ttyUSB0.  /dev/ttyUSB0 is
> still around.
> 5. Can now kill/terminate the program that had the port open and the uevent
> will be sent out.
> 
Comment 3 Alan 2007-09-20 14:32:24 UTC
> > If you have a program that opens a port using usb-serial and the USB device
> is
> > disconnected there is no uevent indicating the ACTION "remove" for the tty
> > device (e.g ttyUSB0).  Once the port is closed the uevent is triggered and

You should get a hangup on the port. That notifies the open process.

No comment on the other bits although the whole open/close stuff has a
couple of other races and is on the hit list for a rewrite so a semi-ugly
patch here for now isn't too worrying
Comment 4 Natalie Protasevich 2007-11-28 19:11:46 UTC
What's the verdict on this, Alan? Should it be closed?

Tysen, have you found a solution to your problem basing on the comments from developers?
Comment 5 Tysen Moore 2007-12-03 06:38:11 UTC
[sorry for the delayed response] Based on the comments I do have a work around.  Thanks for the help and sorry for any wasted effort cause.