Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

staging: most: hdm-usb: fix mbo buffer leak

This patch fixes an MBO leak by replacing the proprietary
free_anchored_buffers() function with the usb_kill_anchored_urbs() function
of the USB subsystem and guarantees that the mbo->complete() completion
function is being called for each URB.

Signed-off-by: Andrey Shvetsov <andrey.shvetsov@k2l.de>
Signed-off-by: Christian Gromm <christian.gromm@microchip.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Andrey Shvetsov and committed by
Greg Kroah-Hartman
3a542007 02245b60

+25 -60
+25 -60
drivers/staging/most/hdm-usb/hdm_usb.c
··· 183 183 } 184 184 185 185 /** 186 - * free_anchored_buffers - free device's anchored items 187 - * @mdev: the device 188 - * @channel: channel ID 189 - * @status: status of MBO termination 190 - */ 191 - static void free_anchored_buffers(struct most_dev *mdev, unsigned int channel, 192 - enum mbo_status_flags status) 193 - { 194 - struct mbo *mbo; 195 - struct urb *urb; 196 - 197 - while ((urb = usb_get_from_anchor(&mdev->busy_urbs[channel]))) { 198 - mbo = urb->context; 199 - usb_kill_urb(urb); 200 - if (mbo && mbo->complete) { 201 - mbo->status = status; 202 - mbo->processed_length = 0; 203 - mbo->complete(mbo); 204 - } 205 - usb_free_urb(urb); 206 - } 207 - } 208 - 209 - /** 210 186 * get_stream_frame_size - calculate frame size of current configuration 211 187 * @cfg: channel configuration 212 188 */ ··· 250 274 cancel_work_sync(&mdev->clear_work[channel].ws); 251 275 252 276 mutex_lock(&mdev->io_mutex); 253 - free_anchored_buffers(mdev, channel, MBO_E_CLOSE); 277 + usb_kill_anchored_urbs(&mdev->busy_urbs[channel]); 254 278 if (mdev->padding_active[channel]) 255 279 mdev->padding_active[channel] = false; 256 280 ··· 349 373 unsigned long flags; 350 374 351 375 spin_lock_irqsave(lock, flags); 352 - if (urb->status == -ENOENT || urb->status == -ECONNRESET || 353 - !mdev->is_channel_healthy[channel]) { 354 - spin_unlock_irqrestore(lock, flags); 355 - return; 356 - } 357 376 358 - if (unlikely(urb->status && urb->status != -ESHUTDOWN)) { 359 - mbo->processed_length = 0; 377 + mbo->processed_length = 0; 378 + mbo->status = MBO_E_INVAL; 379 + if (likely(mdev->is_channel_healthy[channel])) { 360 380 switch (urb->status) { 381 + case 0: 382 + case -ESHUTDOWN: 383 + mbo->processed_length = urb->actual_length; 384 + mbo->status = MBO_SUCCESS; 385 + break; 361 386 case -EPIPE: 362 387 dev_warn(dev, "Broken OUT pipe detected\n"); 363 388 mdev->is_channel_healthy[channel] = false; 364 - spin_unlock_irqrestore(lock, flags); 365 389 mdev->clear_work[channel].pipe = urb->pipe; 366 390 schedule_work(&mdev->clear_work[channel].ws); 367 - return; 391 + break; 368 392 case -ENODEV: 369 393 case -EPROTO: 370 394 mbo->status = MBO_E_CLOSE; 371 395 break; 372 - default: 373 - mbo->status = MBO_E_INVAL; 374 - break; 375 396 } 376 - } else { 377 - mbo->status = MBO_SUCCESS; 378 - mbo->processed_length = urb->actual_length; 379 397 } 380 398 381 399 spin_unlock_irqrestore(lock, flags); ··· 497 527 unsigned long flags; 498 528 499 529 spin_lock_irqsave(lock, flags); 500 - if (urb->status == -ENOENT || urb->status == -ECONNRESET || 501 - !mdev->is_channel_healthy[channel]) { 502 - spin_unlock_irqrestore(lock, flags); 503 - return; 504 - } 505 530 506 - if (unlikely(urb->status && urb->status != -ESHUTDOWN)) { 507 - mbo->processed_length = 0; 531 + mbo->processed_length = 0; 532 + mbo->status = MBO_E_INVAL; 533 + if (likely(mdev->is_channel_healthy[channel])) { 508 534 switch (urb->status) { 535 + case 0: 536 + case -ESHUTDOWN: 537 + mbo->processed_length = urb->actual_length; 538 + mbo->status = MBO_SUCCESS; 539 + if (mdev->padding_active[channel] && 540 + hdm_remove_padding(mdev, channel, mbo)) { 541 + mbo->processed_length = 0; 542 + mbo->status = MBO_E_INVAL; 543 + } 544 + break; 509 545 case -EPIPE: 510 546 dev_warn(dev, "Broken IN pipe detected\n"); 511 547 mdev->is_channel_healthy[channel] = false; 512 - spin_unlock_irqrestore(lock, flags); 513 548 mdev->clear_work[channel].pipe = urb->pipe; 514 549 schedule_work(&mdev->clear_work[channel].ws); 515 - return; 550 + break; 516 551 case -ENODEV: 517 552 case -EPROTO: 518 553 mbo->status = MBO_E_CLOSE; 519 554 break; 520 555 case -EOVERFLOW: 521 556 dev_warn(dev, "Babble on IN pipe detected\n"); 522 - default: 523 - mbo->status = MBO_E_INVAL; 524 557 break; 525 - } 526 - } else { 527 - mbo->processed_length = urb->actual_length; 528 - mbo->status = MBO_SUCCESS; 529 - if (mdev->padding_active[channel] && 530 - hdm_remove_padding(mdev, channel, mbo)) { 531 - mbo->processed_length = 0; 532 - mbo->status = MBO_E_INVAL; 533 558 } 534 559 } 535 560 ··· 792 827 793 828 mutex_lock(&mdev->io_mutex); 794 829 most_stop_enqueue(&mdev->iface, channel); 795 - free_anchored_buffers(mdev, channel, MBO_E_INVAL); 830 + usb_kill_anchored_urbs(&mdev->busy_urbs[channel]); 796 831 if (usb_clear_halt(mdev->usb_device, pipe)) 797 832 dev_warn(&mdev->usb_device->dev, "Failed to reset endpoint.\n"); 798 833