Greg --

Here is a new version of the patch to usb-serial.c to fix
the unbalanced kref and module get/put in serial_open and
serial_close when there are errors.  This version works
correctly when try_module_get fails and now "rmmod --wait"
works correctly.

This patch applies to 2.6.10-rc1-bk20.

Please apply.

Thanks,
-- Al

Change Log

* If the low level usb serial open fails, the kref and
  module use counts are decremented once in open.  Before,
  they were mistakenly decremented again in close.

* If try_module_get fails, the module use count is not
  changed.  Before, the module use count was mistakenly
  decremented.  Now "rmmod --wait" works correctly.

* The tty->driver_data pointer is never set to NULL once
  the port is open.  Before there was a small window when
  it was mistakenly set to NULL for an already open port.

Signed-off-by: Al Borchers <[EMAIL PROTECTED]>

--- linux-2.6.10-rc1-bk20.orig/drivers/usb/serial/usb-serial.c  2004-11-10 
09:30:10.000000000 -0600
+++ linux-2.6.10-rc1-bk20.new/drivers/usb/serial/usb-serial.c   2004-11-11 
01:33:52.000000000 -0600
@@ -480,45 +480,51 @@
        struct usb_serial *serial;
        struct usb_serial_port *port;
        unsigned int portNumber;
-       int retval = -ENODEV;
+       int retval;
        
        dbg("%s", __FUNCTION__);
 
-       /* initialize the pointer incase something fails */
-       tty->driver_data = NULL;
-
        /* get the serial object associated with this tty pointer */
        serial = usb_serial_get_by_index(tty->index);
-       if (!serial)
-               goto bailout;
+       if (!serial) {
+               tty->driver_data = NULL;
+               return -ENODEV;
+       }
 
-       /* set up our port structure making the tty driver remember our port 
object, and us it */
        portNumber = tty->index - serial->minor;
        port = serial->port[portNumber];
-       tty->driver_data = port;
-
-       port->tty = tty;
         
-       /* lock this module before we call it,
-          this may, which means we must bail out, safe because we are called 
with BKL held */
-       if (!try_module_get(serial->type->owner)) {
-               kref_put(&serial->kref, destroy_serial);
-               goto bailout;
-       }
-
-       retval = 0;
        ++port->open_count;
+
        if (port->open_count == 1) {
+
+               /* set up our port structure making the tty driver
+                * remember our port object, and us it */
+               tty->driver_data = port;
+               port->tty = tty;
+
+               /* lock this module before we call it
+                * this may fail, which means we must bail out,
+                * safe because we are called with BKL held */
+               if (!try_module_get(serial->type->owner)) {
+                       retval = -ENODEV;
+                       goto bailout_kref_put;
+               }
+
                /* only call the device specific open if this 
                 * is the first time the port is opened */
                retval = serial->type->open(port, filp);
-               if (retval) {
-                       port->open_count = 0;
-                       module_put(serial->type->owner);
-                       kref_put(&serial->kref, destroy_serial);
-               }
+               if (retval)
+                       goto bailout_module_put;
        }
-bailout:
+
+       return 0;
+
+bailout_module_put:
+       module_put(serial->type->owner);
+bailout_kref_put:
+       kref_put(&serial->kref, destroy_serial);
+       port->open_count = 0;
        return retval;
 }
 
@@ -531,21 +537,24 @@
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
+       if (port->open_count == 0)
+               return;
+
        --port->open_count;
-       if (port->open_count <= 0) {
+       if (port->open_count == 0) {
                /* only call the device specific close if this 
                 * port is being closed by the last owner */
                port->serial->type->close(port, filp);
-               port->open_count = 0;
 
                if (port->tty) {
                        if (port->tty->driver_data)
                                port->tty->driver_data = NULL;
                        port->tty = NULL;
                }
+
+               module_put(port->serial->type->owner);
        }
 
-       module_put(port->serial->type->owner);
        kref_put(&port->serial->kref, destroy_serial);
 }
 




-------------------------------------------------------
This SF.Net email is sponsored by:
Sybase ASE Linux Express Edition - download now for FREE
LinuxWorld Reader's Choice Award Winner for best database on Linux.
http://ads.osdn.com/?ad_id=5588&alloc_id=12065&op=click
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to