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>
This commit is contained in:
parent
2f007de2f4
commit
5ec1862e7b
|
@ -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 = {
|
||||||
.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
|
||||||
__u8 od_outseq; // Sequence number for bulk_out URBs
|
__u8 od_outseq; // Sequence number for bulk_out URBs
|
||||||
};
|
};
|
||||||
|
|
||||||
static int omninet_open (struct usb_serial_port *port, struct file *filp)
|
static int omninet_attach (struct usb_serial *serial)
|
||||||
{
|
{
|
||||||
struct usb_serial *serial = port->serial;
|
struct omninet_data *od;
|
||||||
struct usb_serial_port *wport;
|
struct usb_serial_port *port = serial->port[0];
|
||||||
struct omninet_data *od;
|
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
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 ) {
|
if( !od ) {
|
||||||
err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct omninet_data));
|
err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct omninet_data));
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_set_serial_port_data(port, od);
|
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 = usb_get_serial_port_data(port);
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
dbg("%s - port %d", __FUNCTION__, port->number);
|
||||||
|
|
||||||
|
od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL );
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue