Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+31 −18
Original line number Diff line number Diff line
@@ -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 @@ static ssize_t wdm_read
	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 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
	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;
}