diff options
author | Oliver Neukum <oneukum@suse.de> | 2007-03-27 16:02:34 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-04-27 13:28:38 -0700 |
commit | 5ec1862e7b612d804ca10a0475dccf98c857efec (patch) | |
tree | 6670e75d9364c9d8871f8f1b85ac12bff9900e34 /drivers/usb | |
parent | 2f007de2f4296e4dafae6ab0b3cc1bc49443137a (diff) | |
download | linux-5ec1862e7b612d804ca10a0475dccf98c857efec.tar.gz linux-5ec1862e7b612d804ca10a0475dccf98c857efec.tar.bz2 linux-5ec1862e7b612d804ca10a0475dccf98c857efec.zip |
USB: fix omninet write vs. close race
omninet kills all URBs in close. However write() returns as soon as
the URB has been submitted. Killing the last URB means a race that
can lose that date written in the last call to write().
As a fix this is moved to shutdown().
Signed-off-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/serial/omninet.c | 40 |
1 files changed, 22 insertions, 18 deletions
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 357cc11915cf..4adfab988e86 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -69,6 +69,7 @@ static void omninet_write_bulk_callback (struct urb *urb); static int omninet_write (struct usb_serial_port *port, const unsigned char *buf, int count); static int omninet_write_room (struct usb_serial_port *port); static void omninet_shutdown (struct usb_serial *serial); +static int omninet_attach (struct usb_serial *serial); static struct usb_device_id id_table [] = { { USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) }, @@ -99,6 +100,7 @@ static struct usb_serial_driver zyxel_omninet_device = { .num_bulk_in = 1, .num_bulk_out = 2, .num_ports = 1, + .attach = omninet_attach, .open = omninet_open, .close = omninet_close, .write = omninet_write, @@ -145,22 +147,30 @@ struct omninet_data __u8 od_outseq; // Sequence number for bulk_out URBs }; +static int omninet_attach (struct usb_serial *serial) +{ + struct omninet_data *od; + struct usb_serial_port *port = serial->port[0]; + + od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL ); + if( !od ) { + err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct omninet_data)); + return -ENOMEM; + } + usb_set_serial_port_data(port, od); + return 0; +} + static int omninet_open (struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial = port->serial; struct usb_serial_port *wport; - struct omninet_data *od; + struct omninet_data *od = usb_get_serial_port_data(port); int result = 0; dbg("%s - port %d", __FUNCTION__, port->number); od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL ); - if( !od ) { - err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct omninet_data)); - return -ENOMEM; - } - - usb_set_serial_port_data(port, od); wport = serial->port[1]; wport->tty = port->tty; @@ -172,9 +182,6 @@ static int omninet_open (struct usb_serial_port *port, struct file *filp) result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) { err("%s - failed submitting read urb, error %d", __FUNCTION__, result); - /* open failed - all allocations must be freed */ - kfree(od); - usb_set_serial_port_data(port, NULL); } return result; @@ -182,16 +189,8 @@ static int omninet_open (struct usb_serial_port *port, struct file *filp) static void omninet_close (struct usb_serial_port *port, struct file * filp) { - struct usb_serial *serial = port->serial; - struct usb_serial_port *wport; - dbg("%s - port %d", __FUNCTION__, port->number); - - wport = serial->port[1]; - usb_kill_urb(wport->write_urb); usb_kill_urb(port->read_urb); - - kfree(usb_get_serial_port_data(port)); } @@ -330,7 +329,12 @@ static void omninet_write_bulk_callback (struct urb *urb) static void omninet_shutdown (struct usb_serial *serial) { + struct usb_serial_port *wport = serial->port[1]; + struct usb_serial_port *port = serial->port[0]; dbg ("%s", __FUNCTION__); + + usb_kill_urb(wport->write_urb); + kfree(usb_get_serial_port_data(port)); } |