Commit ad0b65ef authored by Brandon Philips's avatar Brandon Philips Committed by Greg Kroah-Hartman

USB: cdc-acm.c: fix recursive lock in acm_start_wb error path

Fixes an obvious bug in cdc-acm by avoiding a recursive lock on
acm_start_wb()'s error path. Should apply towards 2.6.27 stable and
2.6.28.

=============================================
[ INFO: possible recursive locking detected ]
2.6.27-2-pae #109
---------------------------------------------
python/31449 is trying to acquire lock:
 (&acm->write_lock){++..}, at: [<f89a0348>] acm_start_wb+0x5c/0x7b [cdc_acm]

but task is already holding lock:
 (&acm->write_lock){++..}, at: [<f89a04fb>] acm_tty_write+0xe1/0x167 [cdc_acm]

other info that might help us debug this:
2 locks held by python/31449:
 #0:  (&tty->atomic_write_lock){--..}, at: [<c0260fae>] tty_write_lock+0x14/0x3b
 #1:  (&acm->write_lock){++..}, at: [<f89a04fb>] acm_tty_write+0xe1/0x167 [cdc_acm]

stack backtrace:
Pid: 31449, comm: python Not tainted 2.6.27-2-pae #109
 [<c030f42f>] ? printk+0xf/0x18
 [<c0149f33>] __lock_acquire+0xc7b/0x1316
 [<c014a63e>] lock_acquire+0x70/0x97
 [<f89a0348>] ? acm_start_wb+0x5c/0x7b [cdc_acm]
 [<c0312109>] _spin_lock_irqsave+0x37/0x47
 [<f89a0348>] ? acm_start_wb+0x5c/0x7b [cdc_acm]
 [<f89a0348>] acm_start_wb+0x5c/0x7b [cdc_acm]
 [<f89a055d>] acm_tty_write+0x143/0x167 [cdc_acm]
 [<c0262a98>] write_chan+0x1cd/0x297
 [<c012527e>] ? default_wake_function+0x0/0xd
 [<c026111e>] tty_write+0x149/0x1b9
 [<c02628cb>] ? write_chan+0x0/0x297
 [<c01912c5>] ? rw_verify_area+0x76/0x98
 [<c0260fd5>] ? tty_write+0x0/0x1b9
 [<c01919ba>] vfs_write+0x8c/0x136
 [<c0191afd>] sys_write+0x3b/0x60
 [<c0103beb>] sysenter_do_call+0x12/0x3f
 =======================
Signed-off-by: default avatarBrandon Philips <bphilips@suse.de>
Cc: Oliver Neukum <oliver@neukum.org>
Cc: stable <stable@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 881e3c98
...@@ -158,16 +158,12 @@ static int acm_wb_is_avail(struct acm *acm) ...@@ -158,16 +158,12 @@ static int acm_wb_is_avail(struct acm *acm)
} }
/* /*
* Finish write. * Finish write. Caller must hold acm->write_lock
*/ */
static void acm_write_done(struct acm *acm, struct acm_wb *wb) static void acm_write_done(struct acm *acm, struct acm_wb *wb)
{ {
unsigned long flags;
spin_lock_irqsave(&acm->write_lock, flags);
wb->use = 0; wb->use = 0;
acm->transmitting--; acm->transmitting--;
spin_unlock_irqrestore(&acm->write_lock, flags);
} }
/* /*
...@@ -482,6 +478,7 @@ static void acm_write_bulk(struct urb *urb) ...@@ -482,6 +478,7 @@ static void acm_write_bulk(struct urb *urb)
{ {
struct acm_wb *wb = urb->context; struct acm_wb *wb = urb->context;
struct acm *acm = wb->instance; struct acm *acm = wb->instance;
unsigned long flags;
if (verbose || urb->status if (verbose || urb->status
|| (urb->actual_length != urb->transfer_buffer_length)) || (urb->actual_length != urb->transfer_buffer_length))
...@@ -490,7 +487,9 @@ static void acm_write_bulk(struct urb *urb) ...@@ -490,7 +487,9 @@ static void acm_write_bulk(struct urb *urb)
urb->transfer_buffer_length, urb->transfer_buffer_length,
urb->status); urb->status);
spin_lock_irqsave(&acm->write_lock, flags);
acm_write_done(acm, wb); acm_write_done(acm, wb);
spin_unlock_irqrestore(&acm->write_lock, flags);
if (ACM_READY(acm)) if (ACM_READY(acm))
schedule_work(&acm->work); schedule_work(&acm->work);
else else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment