diff options
author | Oliver Neukum <oliver@neukum.org> | 2010-02-03 11:10:22 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-03-02 17:54:54 -0500 |
commit | 2b626dc134d38d0001b98acf8c7293b6bc5ee86d (patch) | |
tree | 7ebdb76b970f985c210d78dbd25f71ea9d957250 /drivers/usb/class/cdc-acm.c | |
parent | d7e18a9f2c506467ec7a9c066da45a0f60c6f5a6 (diff) |
USB: cdc-acm: fix possible deadlock with multiple openers
The lock must be dropped before usb_autopm_interface_put() is called
Signed-off-by: Oliver Neukum <oliver@neukum.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
-rw-r--r-- | drivers/usb/class/cdc-acm.c | 11 |
1 files changed, 6 insertions, 5 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 5155ff2b2282..b97f9309c827 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
@@ -553,7 +553,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
553 | 553 | ||
554 | acm = acm_table[tty->index]; | 554 | acm = acm_table[tty->index]; |
555 | if (!acm || !acm->dev) | 555 | if (!acm || !acm->dev) |
556 | goto err_out; | 556 | goto out; |
557 | else | 557 | else |
558 | rv = 0; | 558 | rv = 0; |
559 | 559 | ||
@@ -569,8 +569,9 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
569 | 569 | ||
570 | mutex_lock(&acm->mutex); | 570 | mutex_lock(&acm->mutex); |
571 | if (acm->port.count++) { | 571 | if (acm->port.count++) { |
572 | mutex_unlock(&acm->mutex); | ||
572 | usb_autopm_put_interface(acm->control); | 573 | usb_autopm_put_interface(acm->control); |
573 | goto done; | 574 | goto out; |
574 | } | 575 | } |
575 | 576 | ||
576 | acm->ctrlurb->dev = acm->dev; | 577 | acm->ctrlurb->dev = acm->dev; |
@@ -599,18 +600,18 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
599 | set_bit(ASYNCB_INITIALIZED, &acm->port.flags); | 600 | set_bit(ASYNCB_INITIALIZED, &acm->port.flags); |
600 | rv = tty_port_block_til_ready(&acm->port, tty, filp); | 601 | rv = tty_port_block_til_ready(&acm->port, tty, filp); |
601 | tasklet_schedule(&acm->urb_task); | 602 | tasklet_schedule(&acm->urb_task); |
602 | done: | 603 | |
603 | mutex_unlock(&acm->mutex); | 604 | mutex_unlock(&acm->mutex); |
604 | err_out: | 605 | out: |
605 | mutex_unlock(&open_mutex); | 606 | mutex_unlock(&open_mutex); |
606 | return rv; | 607 | return rv; |
607 | 608 | ||
608 | full_bailout: | 609 | full_bailout: |
609 | usb_kill_urb(acm->ctrlurb); | 610 | usb_kill_urb(acm->ctrlurb); |
610 | bail_out: | 611 | bail_out: |
611 | usb_autopm_put_interface(acm->control); | ||
612 | acm->port.count--; | 612 | acm->port.count--; |
613 | mutex_unlock(&acm->mutex); | 613 | mutex_unlock(&acm->mutex); |
614 | usb_autopm_put_interface(acm->control); | ||
614 | early_bail: | 615 | early_bail: |
615 | mutex_unlock(&open_mutex); | 616 | mutex_unlock(&open_mutex); |
616 | tty_port_tty_set(&acm->port, NULL); | 617 | tty_port_tty_set(&acm->port, NULL); |