[PATCH] USB: serial: Fix atomic schedule in u_serial.c

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi All:
    When tty->low_latency = 1, tty_flip_buffer_push() may sleep in
tasklet context which will lead to a kernel crash.We use
workqueue instead of tasklet.

Signed-off-by: Wang Zhi <coredump007@xxxxxxxxx>
---
--- 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

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux