• Bug#261706: usb-storage hangs all USB devices (2/3)

    From Horms@1:229/2 to Matt Zimmerman on Thu Aug 12 05:30:08 2004
    [continued from previous message]

    + spin_lock_irqsave(&post_lock, flags);
    + list_add_tail(&job->link, &post_list);
    + serial->ref++; /* Protect the port->sem from kfree() */
    + schedule_task(&post_task);
    + spin_unlock_irqrestore(&post_lock, flags);
    +
    + return count;
    +}
    +
    static int serial_write_room (struct tty_struct *tty)
    {
    struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
    @@ -620,6 +738,9 @@
    if (!serial)
    return -ENODEV;

    + if (in_interrupt())
    + return POST_BSIZE;
    +
    down (&port->sem);

    dbg("%s - port %d", __FUNCTION__, port->number);
    @@ -1128,6 +1249,7 @@
    int num_ports;
    int max_endpoints;
    const struct usb_device_id *id_pattern = NULL;
    + unsigned long flags;

    /* loop through our list of known serial converters, and see if this
    device matches. */
    @@ -1338,11 +1460,15 @@
    init_MUTEX (&port->sem);
    }

    + spin_lock_irqsave(&post_lock, flags);
    + serial->ref = 1;
    + spin_unlock_irqrestore(&post_lock, flags);
    +
    /* if this device type has a startup function, call it */
    if (type->startup) {
    i = type->startup (serial);
    if (i < 0)
    - goto probe_error;
    + goto startup_error;
    if (i > 0)
    return serial;
    }
    @@ -1357,6 +1483,12 @@
    return serial; /* success */


    +startup_error:
    + spin_lock_irqsave(&post_lock, flags);
    + if (serial->ref != 1) {
    + err("bug in component startup: ref %d\n", serial->ref);
    + }
    + spin_unlock_irqrestore(&post_lock, flags);
    probe_error:
    for (i = 0; i < num_bulk_in; ++i) {
    port = &serial->port[i];
    @@ -1392,6 +1524,7 @@
    {
    struct usb_serial *serial = (struct usb_serial *) ptr;
    struct usb_serial_port *port;
    + unsigned long flags;
    int i;

    dbg ("%s", __FUNCTION__);
    @@ -1452,7 +1585,10 @@
    return_serial (serial);

    /* free up any memory that we allocated */
    - kfree (serial);
    + spin_lock_irqsave(&post_lock, flags);
    + if (--serial->ref == 0)
    + kfree(serial);
    + spin_unlock_irqrestore(&post_lock, flags);

    } else {
    info("device disconnected");
    @@ -1504,6 +1640,7 @@
    for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
    serial_table[i] = NULL;
    }
    + post_task.routine = post_helper;

    /* register the tty driver */
    serial_tty_driver.init_termios = tty_std_termios;
    diff -ur linux-2.4.20-20.7.5/drivers/usb/serial/usb-serial.h linux-2.4.20-20.7.5-u1/drivers/usb/serial/usb-serial.h
    --- linux-2.4.20-20.7.5/drivers/usb/serial/usb-serial.h 2002-11-28 18:53:15.000000000 -0500
    +++ linux-2.4.20-20.7.5-u1/drivers/usb/serial/usb-serial.h 2003-11-17 22:32:55.000000000 -0500
    @@ -151,6 +151,9 @@
    __u16 product;
    struct usb_serial_port port[MAX_NUM_PORTS];
    void * private;
    +#ifndef __GENKSYMS__
    + int ref;
    +#endif
    };



    diff -urN -X dontdiff linux-2.4.22-1.2176/drivers/usb/serial/usbserial.c linux-2.4.22-1.2176-u1/drivers/usb/serial/usbserial.c
    --- linux-2.4.22-1.2176/drivers/usb/serial/usbserial.c 2004-03-11 20:53:43.000000000 -0800
    +++ linux-2.4.22-1.2176-u1/drivers/usb/serial/usbserial.c 2004-03-23 11:07:12.000000000 -0800
    @@ -367,6 +367,10 @@
    static void serial_close (struct tty_struct *tty, struct file * filp);
    static int __serial_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
    static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count);
    +static int serial_post_job(struct u