Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+22 −18
Original line number Diff line number Diff line
@@ -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_open (struct usb_serial_port *port, struct file *filp)
static int omninet_attach (struct usb_serial *serial)
{
	struct usb_serial	*serial = port->serial;
	struct usb_serial_port	*wport;
	struct omninet_data *od;
	int			result = 0;

	dbg("%s - port %d", __FUNCTION__, port->number);
	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 = 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->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));
}