diff options
author | Brandon Philips <brandon@ifup.org> | 2008-11-06 14:19:11 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-11-13 17:45:02 -0500 |
commit | ad0b65efd12d020b046cde8d6f474e37bb98dd73 (patch) | |
tree | 4006e270b2374817855c844c48cb4b7ed891ab35 /drivers/usb | |
parent | 881e3c9867c585e632dfa4ccb0848b62debc64c7 (diff) |
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: Brandon Philips <bphilips@suse.de>
Cc: Oliver Neukum <oliver@neukum.org>
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/class/cdc-acm.c | 9 |
1 files changed, 4 insertions, 5 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 20104443081a..d50a99f70aee 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
@@ -158,16 +158,12 @@ static int acm_wb_is_avail(struct acm *acm) | |||
158 | } | 158 | } |
159 | 159 | ||
160 | /* | 160 | /* |
161 | * Finish write. | 161 | * Finish write. Caller must hold acm->write_lock |
162 | */ | 162 | */ |
163 | static void acm_write_done(struct acm *acm, struct acm_wb *wb) | 163 | static void acm_write_done(struct acm *acm, struct acm_wb *wb) |
164 | { | 164 | { |
165 | unsigned long flags; | ||
166 | |||
167 | spin_lock_irqsave(&acm->write_lock, flags); | ||
168 | wb->use = 0; | 165 | wb->use = 0; |
169 | acm->transmitting--; | 166 | acm->transmitting--; |
170 | spin_unlock_irqrestore(&acm->write_lock, flags); | ||
171 | } | 167 | } |
172 | 168 | ||
173 | /* | 169 | /* |
@@ -482,6 +478,7 @@ static void acm_write_bulk(struct urb *urb) | |||
482 | { | 478 | { |
483 | struct acm_wb *wb = urb->context; | 479 | struct acm_wb *wb = urb->context; |
484 | struct acm *acm = wb->instance; | 480 | struct acm *acm = wb->instance; |
481 | unsigned long flags; | ||
485 | 482 | ||
486 | if (verbose || urb->status | 483 | if (verbose || urb->status |
487 | || (urb->actual_length != urb->transfer_buffer_length)) | 484 | || (urb->actual_length != urb->transfer_buffer_length)) |
@@ -490,7 +487,9 @@ static void acm_write_bulk(struct urb *urb) | |||
490 | urb->transfer_buffer_length, | 487 | urb->transfer_buffer_length, |
491 | urb->status); | 488 | urb->status); |
492 | 489 | ||
490 | spin_lock_irqsave(&acm->write_lock, flags); | ||
493 | acm_write_done(acm, wb); | 491 | acm_write_done(acm, wb); |
492 | spin_unlock_irqrestore(&acm->write_lock, flags); | ||
494 | if (ACM_READY(acm)) | 493 | if (ACM_READY(acm)) |
495 | schedule_work(&acm->work); | 494 | schedule_work(&acm->work); |
496 | else | 495 | else |