Commit 5ec1862e authored by Oliver Neukum's avatar Oliver Neukum Committed by Greg Kroah-Hartman

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: default avatarOliver Neukum <oneukum@suse.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 2f007de2
...@@ -69,6 +69,7 @@ static void omninet_write_bulk_callback (struct urb *urb); ...@@ -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 (struct usb_serial_port *port, const unsigned char *buf, int count);
static int omninet_write_room (struct usb_serial_port *port); static int omninet_write_room (struct usb_serial_port *port);
static void omninet_shutdown (struct usb_serial *serial); static void omninet_shutdown (struct usb_serial *serial);
static int omninet_attach (struct usb_serial *serial);
static struct usb_device_id id_table [] = { static struct usb_device_id id_table [] = {
{ USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) }, { USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) },
...@@ -99,6 +100,7 @@ static struct usb_serial_driver zyxel_omninet_device = { ...@@ -99,6 +100,7 @@ static struct usb_serial_driver zyxel_omninet_device = {
.num_bulk_in = 1, .num_bulk_in = 1,
.num_bulk_out = 2, .num_bulk_out = 2,
.num_ports = 1, .num_ports = 1,
.attach = omninet_attach,
.open = omninet_open, .open = omninet_open,
.close = omninet_close, .close = omninet_close,
.write = omninet_write, .write = omninet_write,
...@@ -145,22 +147,30 @@ struct omninet_data ...@@ -145,22 +147,30 @@ struct omninet_data
__u8 od_outseq; // Sequence number for bulk_out URBs __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) static int omninet_open (struct usb_serial_port *port, struct file *filp)
{ {
struct usb_serial *serial = port->serial; struct usb_serial *serial = port->serial;
struct usb_serial_port *wport; struct usb_serial_port *wport;
struct omninet_data *od; struct omninet_data *od = usb_get_serial_port_data(port);
int result = 0; int result = 0;
dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - port %d", __FUNCTION__, port->number);
od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL ); 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 = serial->port[1];
wport->tty = port->tty; wport->tty = port->tty;
...@@ -172,9 +182,6 @@ static int omninet_open (struct usb_serial_port *port, struct file *filp) ...@@ -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); result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result) { if (result) {
err("%s - failed submitting read urb, error %d", __FUNCTION__, 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; return result;
...@@ -182,16 +189,8 @@ static int omninet_open (struct usb_serial_port *port, struct file *filp) ...@@ -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) 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); dbg("%s - port %d", __FUNCTION__, port->number);
wport = serial->port[1];
usb_kill_urb(wport->write_urb);
usb_kill_urb(port->read_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) ...@@ -330,7 +329,12 @@ static void omninet_write_bulk_callback (struct urb *urb)
static void omninet_shutdown (struct usb_serial *serial) 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__); dbg ("%s", __FUNCTION__);
usb_kill_urb(wport->write_urb);
kfree(usb_get_serial_port_data(port));
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment