aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Neukum <oneukum@suse.de>2007-03-27 10:02:34 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-04-27 16:28:38 -0400
commit5ec1862e7b612d804ca10a0475dccf98c857efec (patch)
tree6670e75d9364c9d8871f8f1b85ac12bff9900e34
parent2f007de2f4296e4dafae6ab0b3cc1bc49443137a (diff)
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>
-rw-r--r--drivers/usb/serial/omninet.c40
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);
69static int omninet_write (struct usb_serial_port *port, const unsigned char *buf, int count); 69static int omninet_write (struct usb_serial_port *port, const unsigned char *buf, int count);
70static int omninet_write_room (struct usb_serial_port *port); 70static int omninet_write_room (struct usb_serial_port *port);
71static void omninet_shutdown (struct usb_serial *serial); 71static void omninet_shutdown (struct usb_serial *serial);
72static int omninet_attach (struct usb_serial *serial);
72 73
73static struct usb_device_id id_table [] = { 74static struct usb_device_id id_table [] = {
74 { USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) }, 75 { USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) },
@@ -99,6 +100,7 @@ static struct usb_serial_driver zyxel_omninet_device = {
99 .num_bulk_in = 1, 100 .num_bulk_in = 1,
100 .num_bulk_out = 2, 101 .num_bulk_out = 2,
101 .num_ports = 1, 102 .num_ports = 1,
103 .attach = omninet_attach,
102 .open = omninet_open, 104 .open = omninet_open,
103 .close = omninet_close, 105 .close = omninet_close,
104 .write = omninet_write, 106 .write = omninet_write,
@@ -145,22 +147,30 @@ struct omninet_data
145 __u8 od_outseq; // Sequence number for bulk_out URBs 147 __u8 od_outseq; // Sequence number for bulk_out URBs
146}; 148};
147 149
150static int omninet_attach (struct usb_serial *serial)
151{
152 struct omninet_data *od;
153 struct usb_serial_port *port = serial->port[0];
154
155 od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL );
156 if( !od ) {
157 err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct omninet_data));
158 return -ENOMEM;
159 }
160 usb_set_serial_port_data(port, od);
161 return 0;
162}
163
148static int omninet_open (struct usb_serial_port *port, struct file *filp) 164static int omninet_open (struct usb_serial_port *port, struct file *filp)
149{ 165{
150 struct usb_serial *serial = port->serial; 166 struct usb_serial *serial = port->serial;
151 struct usb_serial_port *wport; 167 struct usb_serial_port *wport;
152 struct omninet_data *od; 168 struct omninet_data *od = usb_get_serial_port_data(port);
153 int result = 0; 169 int result = 0;
154 170
155 dbg("%s - port %d", __FUNCTION__, port->number); 171 dbg("%s - port %d", __FUNCTION__, port->number);
156 172
157 od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL ); 173 od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL );
158 if( !od ) {
159 err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct omninet_data));
160 return -ENOMEM;
161 }
162
163 usb_set_serial_port_data(port, od);
164 wport = serial->port[1]; 174 wport = serial->port[1];
165 wport->tty = port->tty; 175 wport->tty = port->tty;
166 176
@@ -172,9 +182,6 @@ static int omninet_open (struct usb_serial_port *port, struct file *filp)
172 result = usb_submit_urb(port->read_urb, GFP_KERNEL); 182 result = usb_submit_urb(port->read_urb, GFP_KERNEL);
173 if (result) { 183 if (result) {
174 err("%s - failed submitting read urb, error %d", __FUNCTION__, result); 184 err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
175 /* open failed - all allocations must be freed */
176 kfree(od);
177 usb_set_serial_port_data(port, NULL);
178 } 185 }
179 186
180 return result; 187 return result;
@@ -182,16 +189,8 @@ static int omninet_open (struct usb_serial_port *port, struct file *filp)
182 189
183static void omninet_close (struct usb_serial_port *port, struct file * filp) 190static void omninet_close (struct usb_serial_port *port, struct file * filp)
184{ 191{
185 struct usb_serial *serial = port->serial;
186 struct usb_serial_port *wport;
187
188 dbg("%s - port %d", __FUNCTION__, port->number); 192 dbg("%s - port %d", __FUNCTION__, port->number);
189
190 wport = serial->port[1];
191 usb_kill_urb(wport->write_urb);
192 usb_kill_urb(port->read_urb); 193 usb_kill_urb(port->read_urb);
193
194 kfree(usb_get_serial_port_data(port));
195} 194}
196 195
197 196
@@ -330,7 +329,12 @@ static void omninet_write_bulk_callback (struct urb *urb)
330 329
331static void omninet_shutdown (struct usb_serial *serial) 330static void omninet_shutdown (struct usb_serial *serial)
332{ 331{
332 struct usb_serial_port *wport = serial->port[1];
333 struct usb_serial_port *port = serial->port[0];
333 dbg ("%s", __FUNCTION__); 334 dbg ("%s", __FUNCTION__);
335
336 usb_kill_urb(wport->write_urb);
337 kfree(usb_get_serial_port_data(port));
334} 338}
335 339
336 340