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>
This commit is contained in:
Bjørn Mork 2012-01-16 12:41:48 +01:00 коммит произвёл Greg Kroah-Hartman
Родитель c428b70c1e
Коммит e8537bd2c4
1 изменённых файлов: 31 добавлений и 18 удалений

Просмотреть файл

@ -88,7 +88,8 @@ struct wdm_device {
int count;
dma_addr_t shandle;
dma_addr_t ihandle;
struct mutex lock;
struct mutex wlock;
struct mutex rlock;
wait_queue_head_t wait;
struct work_struct rxwork;
int werr;
@ -323,7 +324,7 @@ static ssize_t wdm_write
}
/* concurrent writes and disconnect */
r = mutex_lock_interruptible(&desc->lock);
r = mutex_lock_interruptible(&desc->wlock);
rv = -ERESTARTSYS;
if (r) {
kfree(buf);
@ -386,7 +387,7 @@ static ssize_t wdm_write
out:
usb_autopm_put_interface(desc->intf);
outnp:
mutex_unlock(&desc->lock);
mutex_unlock(&desc->wlock);
outnl:
return rv < 0 ? rv : count;
}
@ -399,7 +400,7 @@ static ssize_t wdm_read
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)
return -ERESTARTSYS;
@ -476,7 +477,7 @@ retry:
rv = cntr;
err:
mutex_unlock(&desc->lock);
mutex_unlock(&desc->rlock);
return rv;
}
@ -542,7 +543,8 @@ static int wdm_open(struct inode *inode, struct file *file)
}
intf->needs_remote_wakeup = 1;
mutex_lock(&desc->lock);
/* using write lock to protect desc->count */
mutex_lock(&desc->wlock);
if (!desc->count++) {
desc->werr = 0;
desc->rerr = 0;
@ -555,7 +557,7 @@ static int wdm_open(struct inode *inode, struct file *file)
} else {
rv = 0;
}
mutex_unlock(&desc->lock);
mutex_unlock(&desc->wlock);
usb_autopm_put_interface(desc->intf);
out:
mutex_unlock(&wdm_mutex);
@ -567,9 +569,11 @@ static int wdm_release(struct inode *inode, struct file *file)
struct wdm_device *desc = file->private_data;
mutex_lock(&wdm_mutex);
mutex_lock(&desc->lock);
/* using write lock to protect desc->count */
mutex_lock(&desc->wlock);
desc->count--;
mutex_unlock(&desc->lock);
mutex_unlock(&desc->wlock);
if (!desc->count) {
dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
@ -667,7 +671,8 @@ next_desc:
desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL);
if (!desc)
goto out;
mutex_init(&desc->lock);
mutex_init(&desc->rlock);
mutex_init(&desc->wlock);
spin_lock_init(&desc->iuspin);
init_waitqueue_head(&desc->wait);
desc->wMaxCommand = maxcom;
@ -781,10 +786,12 @@ static void wdm_disconnect(struct usb_interface *intf)
/* to terminate pending flushes */
clear_bit(WDM_IN_USE, &desc->flags);
spin_unlock_irqrestore(&desc->iuspin, flags);
mutex_lock(&desc->lock);
mutex_lock(&desc->rlock);
mutex_lock(&desc->wlock);
kill_urbs(desc);
cancel_work_sync(&desc->rxwork);
mutex_unlock(&desc->lock);
mutex_unlock(&desc->wlock);
mutex_unlock(&desc->rlock);
wake_up_all(&desc->wait);
if (!desc->count)
cleanup(desc);
@ -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);
/* if this is an autosuspend the caller does the locking */
if (!PMSG_IS_AUTO(message))
mutex_lock(&desc->lock);
if (!PMSG_IS_AUTO(message)) {
mutex_lock(&desc->rlock);
mutex_lock(&desc->wlock);
}
spin_lock_irq(&desc->iuspin);
if (PMSG_IS_AUTO(message) &&
@ -817,8 +826,10 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
kill_urbs(desc);
cancel_work_sync(&desc->rxwork);
}
if (!PMSG_IS_AUTO(message))
mutex_unlock(&desc->lock);
if (!PMSG_IS_AUTO(message)) {
mutex_unlock(&desc->wlock);
mutex_unlock(&desc->rlock);
}
return rv;
}
@ -856,7 +867,8 @@ static int wdm_pre_reset(struct usb_interface *intf)
{
struct wdm_device *desc = usb_get_intfdata(intf);
mutex_lock(&desc->lock);
mutex_lock(&desc->rlock);
mutex_lock(&desc->wlock);
kill_urbs(desc);
/*
@ -878,7 +890,8 @@ static int wdm_post_reset(struct usb_interface *intf)
int rv;
rv = recover_from_urb_loss(desc);
mutex_unlock(&desc->lock);
mutex_unlock(&desc->wlock);
mutex_unlock(&desc->rlock);
return 0;
}