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>

diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 357cc11..4adfab9 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -69,6 +69,7 @@
 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 @@
 	.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 @@
 	__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 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 = 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 @@
 	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 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_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));
 }