diff options
| author | Bjørn Mork <bjorn@mork.no> | 2012-01-16 06:41:48 -0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2012-01-24 15:17:29 -0500 |
| commit | e8537bd2c4f325a4796da33564ddcef9489b7feb (patch) | |
| tree | 50d5d643591ed620197c0d7bba8263acb1afba7f | |
| parent | c428b70c1e115c5649707a602742e34130d19428 (diff) | |
USB: cdc-wdm: use two mutexes to allow simultaneous read and write
using a separate read and write mutex for locking is sufficient to make the
driver accept simultaneous read and write. This improves useability a lot.
Signed-off-by: Bjørn Mork <bjorn@mork.no>
Cc: stable <stable@vger.kernel.org>
Cc: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
| -rw-r--r-- | drivers/usb/class/cdc-wdm.c | 49 |
1 files changed, 31 insertions, 18 deletions
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 1f6b5c8394b4..023d271c2614 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c | |||
| @@ -88,7 +88,8 @@ struct wdm_device { | |||
| 88 | int count; | 88 | int count; |
| 89 | dma_addr_t shandle; | 89 | dma_addr_t shandle; |
| 90 | dma_addr_t ihandle; | 90 | dma_addr_t ihandle; |
| 91 | struct mutex lock; | 91 | struct mutex wlock; |
| 92 | struct mutex rlock; | ||
| 92 | wait_queue_head_t wait; | 93 | wait_queue_head_t wait; |
| 93 | struct work_struct rxwork; | 94 | struct work_struct rxwork; |
| 94 | int werr; | 95 | int werr; |
| @@ -323,7 +324,7 @@ static ssize_t wdm_write | |||
| 323 | } | 324 | } |
| 324 | 325 | ||
| 325 | /* concurrent writes and disconnect */ | 326 | /* concurrent writes and disconnect */ |
| 326 | r = mutex_lock_interruptible(&desc->lock); | 327 | r = mutex_lock_interruptible(&desc->wlock); |
| 327 | rv = -ERESTARTSYS; | 328 | rv = -ERESTARTSYS; |
| 328 | if (r) { | 329 | if (r) { |
| 329 | kfree(buf); | 330 | kfree(buf); |
| @@ -386,7 +387,7 @@ static ssize_t wdm_write | |||
| 386 | out: | 387 | out: |
| 387 | usb_autopm_put_interface(desc->intf); | 388 | usb_autopm_put_interface(desc->intf); |
| 388 | outnp: | 389 | outnp: |
| 389 | mutex_unlock(&desc->lock); | 390 | mutex_unlock(&desc->wlock); |
| 390 | outnl: | 391 | outnl: |
| 391 | return rv < 0 ? rv : count; | 392 | return rv < 0 ? rv : count; |
| 392 | } | 393 | } |
| @@ -399,7 +400,7 @@ static ssize_t wdm_read | |||
| 399 | struct wdm_device *desc = file->private_data; | 400 | struct wdm_device *desc = file->private_data; |
| 400 | 401 | ||
| 401 | 402 | ||
| 402 | rv = mutex_lock_interruptible(&desc->lock); /*concurrent reads */ | 403 | rv = mutex_lock_interruptible(&desc->rlock); /*concurrent reads */ |
| 403 | if (rv < 0) | 404 | if (rv < 0) |
| 404 | return -ERESTARTSYS; | 405 | return -ERESTARTSYS; |
| 405 | 406 | ||
| @@ -476,7 +477,7 @@ retry: | |||
| 476 | rv = cntr; | 477 | rv = cntr; |
| 477 | 478 | ||
| 478 | err: | 479 | err: |
| 479 | mutex_unlock(&desc->lock); | 480 | mutex_unlock(&desc->rlock); |
| 480 | return rv; | 481 | return rv; |
| 481 | } | 482 | } |
| 482 | 483 | ||
| @@ -542,7 +543,8 @@ static int wdm_open(struct inode *inode, struct file *file) | |||
| 542 | } | 543 | } |
| 543 | intf->needs_remote_wakeup = 1; | 544 | intf->needs_remote_wakeup = 1; |
| 544 | 545 | ||
| 545 | mutex_lock(&desc->lock); | 546 | /* using write lock to protect desc->count */ |
| 547 | mutex_lock(&desc->wlock); | ||
| 546 | if (!desc->count++) { | 548 | if (!desc->count++) { |
| 547 | desc->werr = 0; | 549 | desc->werr = 0; |
| 548 | desc->rerr = 0; | 550 | desc->rerr = 0; |
| @@ -555,7 +557,7 @@ static int wdm_open(struct inode *inode, struct file *file) | |||
| 555 | } else { | 557 | } else { |
| 556 | rv = 0; | 558 | rv = 0; |
| 557 | } | 559 | } |
| 558 | mutex_unlock(&desc->lock); | 560 | mutex_unlock(&desc->wlock); |
| 559 | usb_autopm_put_interface(desc->intf); | 561 | usb_autopm_put_interface(desc->intf); |
| 560 | out: | 562 | out: |
| 561 | mutex_unlock(&wdm_mutex); | 563 | mutex_unlock(&wdm_mutex); |
| @@ -567,9 +569,11 @@ static int wdm_release(struct inode *inode, struct file *file) | |||
| 567 | struct wdm_device *desc = file->private_data; | 569 | struct wdm_device *desc = file->private_data; |
| 568 | 570 | ||
| 569 | mutex_lock(&wdm_mutex); | 571 | mutex_lock(&wdm_mutex); |
| 570 | mutex_lock(&desc->lock); | 572 | |
| 573 | /* using write lock to protect desc->count */ | ||
| 574 | mutex_lock(&desc->wlock); | ||
| 571 | desc->count--; | 575 | desc->count--; |
| 572 | mutex_unlock(&desc->lock); | 576 | mutex_unlock(&desc->wlock); |
| 573 | 577 | ||
| 574 | if (!desc->count) { | 578 | if (!desc->count) { |
| 575 | dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); | 579 | dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); |
| @@ -667,7 +671,8 @@ next_desc: | |||
| 667 | desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL); | 671 | desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL); |
| 668 | if (!desc) | 672 | if (!desc) |
| 669 | goto out; | 673 | goto out; |
| 670 | mutex_init(&desc->lock); | 674 | mutex_init(&desc->rlock); |
| 675 | mutex_init(&desc->wlock); | ||
| 671 | spin_lock_init(&desc->iuspin); | 676 | spin_lock_init(&desc->iuspin); |
| 672 | init_waitqueue_head(&desc->wait); | 677 | init_waitqueue_head(&desc->wait); |
| 673 | desc->wMaxCommand = maxcom; | 678 | desc->wMaxCommand = maxcom; |
| @@ -781,10 +786,12 @@ static void wdm_disconnect(struct usb_interface *intf) | |||
| 781 | /* to terminate pending flushes */ | 786 | /* to terminate pending flushes */ |
| 782 | clear_bit(WDM_IN_USE, &desc->flags); | 787 | clear_bit(WDM_IN_USE, &desc->flags); |
| 783 | spin_unlock_irqrestore(&desc->iuspin, flags); | 788 | spin_unlock_irqrestore(&desc->iuspin, flags); |
| 784 | mutex_lock(&desc->lock); | 789 | mutex_lock(&desc->rlock); |
| 790 | mutex_lock(&desc->wlock); | ||
| 785 | kill_urbs(desc); | 791 | kill_urbs(desc); |
| 786 | cancel_work_sync(&desc->rxwork); | 792 | cancel_work_sync(&desc->rxwork); |
| 787 | mutex_unlock(&desc->lock); | 793 | mutex_unlock(&desc->wlock); |
| 794 | mutex_unlock(&desc->rlock); | ||
| 788 | wake_up_all(&desc->wait); | 795 | wake_up_all(&desc->wait); |
| 789 | if (!desc->count) | 796 | if (!desc->count) |
| 790 | cleanup(desc); | 797 | cleanup(desc); |
| @@ -800,8 +807,10 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message) | |||
| 800 | dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor); | 807 | dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor); |
| 801 | 808 | ||
| 802 | /* if this is an autosuspend the caller does the locking */ | 809 | /* if this is an autosuspend the caller does the locking */ |
| 803 | if (!PMSG_IS_AUTO(message)) | 810 | if (!PMSG_IS_AUTO(message)) { |
| 804 | mutex_lock(&desc->lock); | 811 | mutex_lock(&desc->rlock); |
| 812 | mutex_lock(&desc->wlock); | ||
| 813 | } | ||
| 805 | spin_lock_irq(&desc->iuspin); | 814 | spin_lock_irq(&desc->iuspin); |
| 806 | 815 | ||
| 807 | if (PMSG_IS_AUTO(message) && | 816 | if (PMSG_IS_AUTO(message) && |
| @@ -817,8 +826,10 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message) | |||
| 817 | kill_urbs(desc); | 826 | kill_urbs(desc); |
| 818 | cancel_work_sync(&desc->rxwork); | 827 | cancel_work_sync(&desc->rxwork); |
| 819 | } | 828 | } |
| 820 | if (!PMSG_IS_AUTO(message)) | 829 | if (!PMSG_IS_AUTO(message)) { |
| 821 | mutex_unlock(&desc->lock); | 830 | mutex_unlock(&desc->wlock); |
| 831 | mutex_unlock(&desc->rlock); | ||
| 832 | } | ||
| 822 | 833 | ||
| 823 | return rv; | 834 | return rv; |
| 824 | } | 835 | } |
| @@ -856,7 +867,8 @@ static int wdm_pre_reset(struct usb_interface *intf) | |||
| 856 | { | 867 | { |
| 857 | struct wdm_device *desc = usb_get_intfdata(intf); | 868 | struct wdm_device *desc = usb_get_intfdata(intf); |
| 858 | 869 | ||
| 859 | mutex_lock(&desc->lock); | 870 | mutex_lock(&desc->rlock); |
| 871 | mutex_lock(&desc->wlock); | ||
| 860 | kill_urbs(desc); | 872 | kill_urbs(desc); |
| 861 | 873 | ||
| 862 | /* | 874 | /* |
| @@ -878,7 +890,8 @@ static int wdm_post_reset(struct usb_interface *intf) | |||
| 878 | int rv; | 890 | int rv; |
| 879 | 891 | ||
| 880 | rv = recover_from_urb_loss(desc); | 892 | rv = recover_from_urb_loss(desc); |
| 881 | mutex_unlock(&desc->lock); | 893 | mutex_unlock(&desc->wlock); |
| 894 | mutex_unlock(&desc->rlock); | ||
| 882 | return 0; | 895 | return 0; |
| 883 | } | 896 | } |
| 884 | 897 | ||
