Hi all: When tty->low_latency = 1, tty_flip_buffer_push() may sleep in tasklet context which will lead to a kernel crash.I think we should use workqueue instead of tasklet in gs_rx_push() in u_serial.c. Here is the patch. It works fine. --- a/drivers/usb/gadget/u_serial.c 2010-01-19 02:23:35.000000000 +0800 +++ b/drivers/usb/gadget/u_serial.c 2010-01-20 14:42:17.000000000 +0800 @@ -105,7 +105,7 @@ struct gs_port { struct list_head read_pool; struct list_head read_queue; unsigned n_read; - struct tasklet_struct push; + struct work_struct push; struct list_head write_pool; struct gs_buf port_write_buf; @@ -464,9 +464,9 @@ __acquires(&port->port_lock) * So QUEUE_SIZE packets plus however many the FIFO holds (usually two) * can be buffered before the TTY layer's buffers (currently 64 KB). */ -static void gs_rx_push(unsigned long _port) +static void gs_rx_push(struct work_struct *work) { - struct gs_port *port = (void *)_port; + struct gs_port *port = container_of(work, struct gs_port, push); struct tty_struct *tty; struct list_head *queue = &port->read_queue; bool disconnect = false; @@ -560,7 +560,7 @@ recycle: if (!list_empty(queue) && tty) { if (!test_bit(TTY_THROTTLED, &tty->flags)) { if (do_push) - tasklet_schedule(&port->push); + schedule_work(&port->push); else pr_warning(PREFIX "%d: RX not scheduled?\n", port->port_num); @@ -581,7 +581,7 @@ static void gs_read_complete(struct usb_ /* Queue all received data until the tty layer is ready for it. */ spin_lock(&port->port_lock); list_add_tail(&req->list, &port->read_queue); - tasklet_schedule(&port->push); + schedule_work(&port->push); spin_unlock(&port->port_lock); } @@ -975,7 +975,7 @@ static void gs_unthrottle(struct tty_str * rts/cts, or other handshaking with the host, but if the * read queue backs up enough we'll be NAKing OUT packets. */ - tasklet_schedule(&port->push); + schedule_work(&port->push); pr_vdebug(PREFIX "%d: unthrottle\n", port->port_num); } spin_unlock_irqrestore(&port->port_lock, flags); @@ -1028,7 +1028,7 @@ gs_port_alloc(unsigned port_num, struct init_waitqueue_head(&port->close_wait); init_waitqueue_head(&port->drain_wait); - tasklet_init(&port->push, gs_rx_push, (unsigned long) port); + INIT_WORK(&port->push, gs_rx_push); INIT_LIST_HEAD(&port->read_pool); INIT_LIST_HEAD(&port->read_queue); @@ -1182,7 +1182,7 @@ void gserial_cleanup(void) ports[i].port = NULL; mutex_unlock(&ports[i].lock); - tasklet_kill(&port->push); + flush_scheduled_work(); /* wait for old opens to finish */ wait_event(port->close_wait, gs_closed(port)); -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html