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

staging: gdm72xx: Fix spinlock recursion on gdm_usb_send_complete

This patch fixes a spinlock recursion bug on several call sites of
gdm_usb_send_complete by not calling spin_lock_irqsave on
urb->context->tx_cxt->lock when the lock has already been acquired.

Signed-off-by: Ben Chan <benchan@chromium.org>
Cc: Sage Ahn <syahn@gctsemi.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Ben Chan and committed by
Greg Kroah-Hartman
dd13c86b 7dd80eb9

+18 -6
+18 -6
drivers/staging/gdm72xx/gdm_usb.c
··· 270 270 } 271 271 } 272 272 273 - static void gdm_usb_send_complete(struct urb *urb) 273 + static void gdm_usb_send_complete_impl(struct urb *urb, bool need_lock) 274 274 { 275 275 struct usb_tx *t = urb->context; 276 276 struct tx_cxt *tx = t->tx_cxt; ··· 282 282 if (urb->status == -ECONNRESET) 283 283 return; 284 284 285 - spin_lock_irqsave(&tx->lock, flags); 285 + if (need_lock) 286 + spin_lock_irqsave(&tx->lock, flags); 286 287 287 288 if (t->callback) 288 289 t->callback(t->cb_data); ··· 297 296 else 298 297 free_tx_struct(t); 299 298 300 - spin_unlock_irqrestore(&tx->lock, flags); 299 + if (need_lock) 300 + spin_unlock_irqrestore(&tx->lock, flags); 301 + } 302 + 303 + static void gdm_usb_send_complete(struct urb *urb) 304 + { 305 + gdm_usb_send_complete_impl(urb, true); 306 + } 307 + 308 + static void gdm_usb_send_complete_no_lock(struct urb *urb) 309 + { 310 + gdm_usb_send_complete_impl(urb, false); 301 311 } 302 312 303 313 static int gdm_usb_send(void *priv_dev, void *data, int len, ··· 423 411 424 412 send_fail: 425 413 t->callback = NULL; 426 - gdm_usb_send_complete(t->urb); 414 + gdm_usb_send_complete_no_lock(t->urb); 427 415 spin_unlock_irqrestore(&tx->lock, flags); 428 416 return ret; 429 417 } ··· 552 540 553 541 if (ret) { 554 542 t->callback = NULL; 555 - gdm_usb_send_complete(t->urb); 543 + gdm_usb_send_complete_no_lock(t->urb); 556 544 } 557 545 } 558 546 } ··· 754 742 755 743 if (ret) { 756 744 t->callback = NULL; 757 - gdm_usb_send_complete(t->urb); 745 + gdm_usb_send_complete_no_lock(t->urb); 758 746 } 759 747 } 760 748