Commit e8537bd2 authored by Bjørn Mork's avatar Bjørn Mork Committed by Greg Kroah-Hartman

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: default avatarBjørn Mork <bjorn@mork.no>
Cc: stable <stable@vger.kernel.org>
Cc: Oliver Neukum <oneukum@suse.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent c428b70c
...@@ -88,7 +88,8 @@ struct wdm_device { ...@@ -88,7 +88,8 @@ struct wdm_device {
int count; int count;
dma_addr_t shandle; dma_addr_t shandle;
dma_addr_t ihandle; dma_addr_t ihandle;
struct mutex lock; struct mutex wlock;
struct mutex rlock;
wait_queue_head_t wait; wait_queue_head_t wait;
struct work_struct rxwork; struct work_struct rxwork;
int werr; int werr;
...@@ -323,7 +324,7 @@ static ssize_t wdm_write ...@@ -323,7 +324,7 @@ static ssize_t wdm_write
} }
/* concurrent writes and disconnect */ /* concurrent writes and disconnect */
r = mutex_lock_interruptible(&desc->lock); r = mutex_lock_interruptible(&desc->wlock);
rv = -ERESTARTSYS; rv = -ERESTARTSYS;
if (r) { if (r) {
kfree(buf); kfree(buf);
...@@ -386,7 +387,7 @@ static ssize_t wdm_write ...@@ -386,7 +387,7 @@ static ssize_t wdm_write
out: out:
usb_autopm_put_interface(desc->intf); usb_autopm_put_interface(desc->intf);
outnp: outnp:
mutex_unlock(&desc->lock); mutex_unlock(&desc->wlock);
outnl: outnl:
return rv < 0 ? rv : count; return rv < 0 ? rv : count;
} }
...@@ -399,7 +400,7 @@ static ssize_t wdm_read ...@@ -399,7 +400,7 @@ static ssize_t wdm_read
struct wdm_device *desc = file->private_data; struct wdm_device *desc = file->private_data;
rv = mutex_lock_interruptible(&desc->lock); /*concurrent reads */ rv = mutex_lock_interruptible(&desc->rlock); /*concurrent reads */
if (rv < 0) if (rv < 0)
return -ERESTARTSYS; return -ERESTARTSYS;
...@@ -476,7 +477,7 @@ static ssize_t wdm_read ...@@ -476,7 +477,7 @@ static ssize_t wdm_read
rv = cntr; rv = cntr;
err: err:
mutex_unlock(&desc->lock); mutex_unlock(&desc->rlock);
return rv; return rv;
} }
...@@ -542,7 +543,8 @@ static int wdm_open(struct inode *inode, struct file *file) ...@@ -542,7 +543,8 @@ static int wdm_open(struct inode *inode, struct file *file)
} }
intf->needs_remote_wakeup = 1; intf->needs_remote_wakeup = 1;
mutex_lock(&desc->lock); /* using write lock to protect desc->count */
mutex_lock(&desc->wlock);
if (!desc->count++) { if (!desc->count++) {
desc->werr = 0; desc->werr = 0;
desc->rerr = 0; desc->rerr = 0;
...@@ -555,7 +557,7 @@ static int wdm_open(struct inode *inode, struct file *file) ...@@ -555,7 +557,7 @@ static int wdm_open(struct inode *inode, struct file *file)
} else { } else {
rv = 0; rv = 0;
} }
mutex_unlock(&desc->lock); mutex_unlock(&desc->wlock);
usb_autopm_put_interface(desc->intf); usb_autopm_put_interface(desc->intf);
out: out:
mutex_unlock(&wdm_mutex); mutex_unlock(&wdm_mutex);
...@@ -567,9 +569,11 @@ static int wdm_release(struct inode *inode, struct file *file) ...@@ -567,9 +569,11 @@ static int wdm_release(struct inode *inode, struct file *file)
struct wdm_device *desc = file->private_data; struct wdm_device *desc = file->private_data;
mutex_lock(&wdm_mutex); mutex_lock(&wdm_mutex);
mutex_lock(&desc->lock);
/* using write lock to protect desc->count */
mutex_lock(&desc->wlock);
desc->count--; desc->count--;
mutex_unlock(&desc->lock); mutex_unlock(&desc->wlock);
if (!desc->count) { if (!desc->count) {
dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
...@@ -667,7 +671,8 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -667,7 +671,8 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL); desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL);
if (!desc) if (!desc)
goto out; goto out;
mutex_init(&desc->lock); mutex_init(&desc->rlock);
mutex_init(&desc->wlock);
spin_lock_init(&desc->iuspin); spin_lock_init(&desc->iuspin);
init_waitqueue_head(&desc->wait); init_waitqueue_head(&desc->wait);
desc->wMaxCommand = maxcom; desc->wMaxCommand = maxcom;
...@@ -781,10 +786,12 @@ static void wdm_disconnect(struct usb_interface *intf) ...@@ -781,10 +786,12 @@ static void wdm_disconnect(struct usb_interface *intf)
/* to terminate pending flushes */ /* to terminate pending flushes */
clear_bit(WDM_IN_USE, &desc->flags); clear_bit(WDM_IN_USE, &desc->flags);
spin_unlock_irqrestore(&desc->iuspin, flags); spin_unlock_irqrestore(&desc->iuspin, flags);
mutex_lock(&desc->lock); mutex_lock(&desc->rlock);
mutex_lock(&desc->wlock);
kill_urbs(desc); kill_urbs(desc);
cancel_work_sync(&desc->rxwork); cancel_work_sync(&desc->rxwork);
mutex_unlock(&desc->lock); mutex_unlock(&desc->wlock);
mutex_unlock(&desc->rlock);
wake_up_all(&desc->wait); wake_up_all(&desc->wait);
if (!desc->count) if (!desc->count)
cleanup(desc); cleanup(desc);
...@@ -800,8 +807,10 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message) ...@@ -800,8 +807,10 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor); dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor);
/* if this is an autosuspend the caller does the locking */ /* if this is an autosuspend the caller does the locking */
if (!PMSG_IS_AUTO(message)) if (!PMSG_IS_AUTO(message)) {
mutex_lock(&desc->lock); mutex_lock(&desc->rlock);
mutex_lock(&desc->wlock);
}
spin_lock_irq(&desc->iuspin); spin_lock_irq(&desc->iuspin);
if (PMSG_IS_AUTO(message) && if (PMSG_IS_AUTO(message) &&
...@@ -817,8 +826,10 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message) ...@@ -817,8 +826,10 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
kill_urbs(desc); kill_urbs(desc);
cancel_work_sync(&desc->rxwork); cancel_work_sync(&desc->rxwork);
} }
if (!PMSG_IS_AUTO(message)) if (!PMSG_IS_AUTO(message)) {
mutex_unlock(&desc->lock); mutex_unlock(&desc->wlock);
mutex_unlock(&desc->rlock);
}
return rv; return rv;
} }
...@@ -856,7 +867,8 @@ static int wdm_pre_reset(struct usb_interface *intf) ...@@ -856,7 +867,8 @@ static int wdm_pre_reset(struct usb_interface *intf)
{ {
struct wdm_device *desc = usb_get_intfdata(intf); struct wdm_device *desc = usb_get_intfdata(intf);
mutex_lock(&desc->lock); mutex_lock(&desc->rlock);
mutex_lock(&desc->wlock);
kill_urbs(desc); kill_urbs(desc);
/* /*
...@@ -878,7 +890,8 @@ static int wdm_post_reset(struct usb_interface *intf) ...@@ -878,7 +890,8 @@ static int wdm_post_reset(struct usb_interface *intf)
int rv; int rv;
rv = recover_from_urb_loss(desc); rv = recover_from_urb_loss(desc);
mutex_unlock(&desc->lock); mutex_unlock(&desc->wlock);
mutex_unlock(&desc->rlock);
return 0; return 0;
} }
......
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