aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial
diff options
context:
space:
mode:
authorJohan Hovold <jhovold@gmail.com>2010-03-17 18:06:07 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-05-20 16:21:35 -0400
commit25d514ca227e1ac81d0906a4ccf2aa171f50a600 (patch)
tree599690248485fb28cd61cf0ce73004e4fbbf3559 /drivers/usb/serial
parent40f92f0dcd9b215c48c53a226328e8e36615e367 (diff)
USB: serial: re-implement multi-urb writes in generic driver
Use dynamic transfer buffer sizes since it is more efficient to let the host controller do the partitioning to fit endpoint size. This way we also do not use more than one urb per write request. Replace max_in_flight_urbs with multi_urb_write flag in struct usb_serial_driver to enable multi-urb writes. Use MAX_TX_URBS=40 and a max buffer size of PAGE_SIZE to prevent DoS attacks. Signed-off-by: Johan Hovold <jhovold@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r--drivers/usb/serial/generic.c132
1 files changed, 56 insertions, 76 deletions
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index be52c748bccb..ad4823bbfa19 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -25,6 +25,8 @@
25 25
26static int debug; 26static int debug;
27 27
28#define MAX_TX_URBS 40
29
28#ifdef CONFIG_USB_SERIAL_GENERIC 30#ifdef CONFIG_USB_SERIAL_GENERIC
29 31
30static int generic_probe(struct usb_interface *interface, 32static int generic_probe(struct usb_interface *interface,
@@ -172,78 +174,63 @@ static int usb_serial_multi_urb_write(struct tty_struct *tty,
172 struct urb *urb; 174 struct urb *urb;
173 unsigned char *buffer; 175 unsigned char *buffer;
174 int status; 176 int status;
175 int towrite;
176 int bwrite = 0;
177
178 dbg("%s - port %d", __func__, port->number);
179
180 if (count == 0)
181 dbg("%s - write request of 0 bytes", __func__);
182 177
183 while (count > 0) { 178 spin_lock_irqsave(&port->lock, flags);
184 towrite = (count > port->bulk_out_size) ? 179 if (port->tx_urbs == MAX_TX_URBS) {
185 port->bulk_out_size : count;
186 spin_lock_irqsave(&port->lock, flags);
187 if (port->urbs_in_flight >
188 port->serial->type->max_in_flight_urbs) {
189 spin_unlock_irqrestore(&port->lock, flags);
190 dbg("%s - write limit hit", __func__);
191 return bwrite;
192 }
193 port->tx_bytes_flight += towrite;
194 port->urbs_in_flight++;
195 spin_unlock_irqrestore(&port->lock, flags); 180 spin_unlock_irqrestore(&port->lock, flags);
181 dbg("%s - write limit hit", __func__);
182 return 0;
183 }
184 port->tx_urbs++;
185 spin_unlock_irqrestore(&port->lock, flags);
196 186
197 buffer = kmalloc(towrite, GFP_ATOMIC); 187 urb = usb_alloc_urb(0, GFP_ATOMIC);
198 if (!buffer) { 188 if (!urb) {
199 dev_err(&port->dev, 189 dev_err(&port->dev, "%s - no free urbs available\n", __func__);
200 "%s ran out of kernel memory for urb ...\n", __func__); 190 status = -ENOMEM;
201 goto error_no_buffer; 191 goto err_urb;
202 } 192 }
203 193
204 urb = usb_alloc_urb(0, GFP_ATOMIC); 194 count = min_t(int, count, PAGE_SIZE);
205 if (!urb) { 195 buffer = kmalloc(count, GFP_ATOMIC);
206 dev_err(&port->dev, "%s - no more free urbs\n", 196 if (!buffer) {
197 dev_err(&port->dev, "%s - could not allocate buffer\n",
207 __func__); 198 __func__);
208 goto error_no_urb; 199 status = -ENOMEM;
209 } 200 goto err_buf;
201 }
210 202
211 /* Copy data */ 203 memcpy(buffer, buf, count);
212 memcpy(buffer, buf + bwrite, towrite); 204 usb_serial_debug_data(debug, &port->dev, __func__, count, buffer);
213 usb_serial_debug_data(debug, &port->dev, __func__, 205 usb_fill_bulk_urb(urb, port->serial->dev,
214 towrite, buffer);
215 /* fill the buffer and send it */
216 usb_fill_bulk_urb(urb, port->serial->dev,
217 usb_sndbulkpipe(port->serial->dev, 206 usb_sndbulkpipe(port->serial->dev,
218 port->bulk_out_endpointAddress), 207 port->bulk_out_endpointAddress),
219 buffer, towrite, 208 buffer, count,
220 port->serial->type->write_bulk_callback, port); 209 port->serial->type->write_bulk_callback, port);
221 210
222 status = usb_submit_urb(urb, GFP_ATOMIC); 211 status = usb_submit_urb(urb, GFP_ATOMIC);
223 if (status) { 212 if (status) {
224 dev_err(&port->dev, "%s - error submitting urb: %d\n", 213 dev_err(&port->dev, "%s - error submitting urb: %d\n",
225 __func__, status); 214 __func__, status);
226 goto error; 215 goto err;
227 }
228
229 /* This urb is the responsibility of the host driver now */
230 usb_free_urb(urb);
231 dbg("%s write: %d", __func__, towrite);
232 count -= towrite;
233 bwrite += towrite;
234 } 216 }
235 return bwrite; 217 spin_lock_irqsave(&port->lock, flags);
218 port->tx_bytes += urb->transfer_buffer_length;
219 spin_unlock_irqrestore(&port->lock, flags);
236 220
237error:
238 usb_free_urb(urb); 221 usb_free_urb(urb);
239error_no_urb: 222
223 return count;
224err:
240 kfree(buffer); 225 kfree(buffer);
241error_no_buffer: 226err_buf:
227 usb_free_urb(urb);
228err_urb:
242 spin_lock_irqsave(&port->lock, flags); 229 spin_lock_irqsave(&port->lock, flags);
243 port->urbs_in_flight--; 230 port->tx_urbs--;
244 port->tx_bytes_flight -= towrite;
245 spin_unlock_irqrestore(&port->lock, flags); 231 spin_unlock_irqrestore(&port->lock, flags);
246 return bwrite; 232
233 return status;
247} 234}
248 235
249/** 236/**
@@ -286,7 +273,7 @@ static int usb_serial_generic_write_start(struct usb_serial_port *port)
286 } 273 }
287 274
288 spin_lock_irqsave(&port->lock, flags); 275 spin_lock_irqsave(&port->lock, flags);
289 port->tx_bytes_flight += count; 276 port->tx_bytes += count;
290 spin_unlock_irqrestore(&port->lock, flags); 277 spin_unlock_irqrestore(&port->lock, flags);
291 278
292 return count; 279 return count;
@@ -318,9 +305,8 @@ int usb_serial_generic_write(struct tty_struct *tty,
318 if (!count) 305 if (!count)
319 return 0; 306 return 0;
320 307
321 if (serial->type->max_in_flight_urbs) 308 if (serial->type->multi_urb_write)
322 return usb_serial_multi_urb_write(tty, port, 309 return usb_serial_multi_urb_write(tty, port, buf, count);
323 buf, count);
324 310
325 count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock); 311 count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock);
326 result = usb_serial_generic_write_start(port); 312 result = usb_serial_generic_write_start(port);
@@ -337,7 +323,7 @@ int usb_serial_generic_write_room(struct tty_struct *tty)
337 struct usb_serial_port *port = tty->driver_data; 323 struct usb_serial_port *port = tty->driver_data;
338 struct usb_serial *serial = port->serial; 324 struct usb_serial *serial = port->serial;
339 unsigned long flags; 325 unsigned long flags;
340 int room = 0; 326 int room;
341 327
342 dbg("%s - port %d", __func__, port->number); 328 dbg("%s - port %d", __func__, port->number);
343 329
@@ -345,14 +331,10 @@ int usb_serial_generic_write_room(struct tty_struct *tty)
345 return 0; 331 return 0;
346 332
347 spin_lock_irqsave(&port->lock, flags); 333 spin_lock_irqsave(&port->lock, flags);
348 if (serial->type->max_in_flight_urbs) { 334 if (serial->type->multi_urb_write)
349 if (port->urbs_in_flight < serial->type->max_in_flight_urbs) 335 room = (MAX_TX_URBS - port->tx_urbs) * PAGE_SIZE;
350 room = port->bulk_out_size * 336 else
351 (serial->type->max_in_flight_urbs -
352 port->urbs_in_flight);
353 } else {
354 room = kfifo_avail(&port->write_fifo); 337 room = kfifo_avail(&port->write_fifo);
355 }
356 spin_unlock_irqrestore(&port->lock, flags); 338 spin_unlock_irqrestore(&port->lock, flags);
357 339
358 dbg("%s - returns %d", __func__, room); 340 dbg("%s - returns %d", __func__, room);
@@ -372,10 +354,10 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
372 return 0; 354 return 0;
373 355
374 spin_lock_irqsave(&port->lock, flags); 356 spin_lock_irqsave(&port->lock, flags);
375 if (serial->type->max_in_flight_urbs) 357 if (serial->type->multi_urb_write)
376 chars = port->tx_bytes_flight; 358 chars = port->tx_bytes;
377 else 359 else
378 chars = kfifo_len(&port->write_fifo) + port->tx_bytes_flight; 360 chars = kfifo_len(&port->write_fifo) + port->tx_bytes;
379 spin_unlock_irqrestore(&port->lock, flags); 361 spin_unlock_irqrestore(&port->lock, flags);
380 362
381 dbg("%s - returns %d", __func__, chars); 363 dbg("%s - returns %d", __func__, chars);
@@ -461,18 +443,16 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb)
461 443
462 dbg("%s - port %d", __func__, port->number); 444 dbg("%s - port %d", __func__, port->number);
463 445
464 if (port->serial->type->max_in_flight_urbs) { 446 if (port->serial->type->multi_urb_write) {
465 kfree(urb->transfer_buffer); 447 kfree(urb->transfer_buffer);
466 448
467 spin_lock_irqsave(&port->lock, flags); 449 spin_lock_irqsave(&port->lock, flags);
468 --port->urbs_in_flight; 450 port->tx_bytes -= urb->transfer_buffer_length;
469 port->tx_bytes_flight -= urb->transfer_buffer_length; 451 port->tx_urbs--;
470 if (port->urbs_in_flight < 0)
471 port->urbs_in_flight = 0;
472 spin_unlock_irqrestore(&port->lock, flags); 452 spin_unlock_irqrestore(&port->lock, flags);
473 } else { 453 } else {
474 spin_lock_irqsave(&port->lock, flags); 454 spin_lock_irqsave(&port->lock, flags);
475 port->tx_bytes_flight -= urb->transfer_buffer_length; 455 port->tx_bytes -= urb->transfer_buffer_length;
476 port->write_urb_busy = 0; 456 port->write_urb_busy = 0;
477 spin_unlock_irqrestore(&port->lock, flags); 457 spin_unlock_irqrestore(&port->lock, flags);
478 458