[PATCH] wip: USB: lsusb: fix ring-buffer locking

From: Johan Hovold
Date: Thu Oct 17 2019 - 05:53:04 EST


Signed-off-by: Johan Hovold <johan@xxxxxxxxxx>
---
drivers/usb/misc/ldusb.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index f3108d85e768..c8d09ac7ade9 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -467,7 +467,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,

/* wait for data */
spin_lock_irq(&dev->rbsl);
- if (dev->ring_head == dev->ring_tail) {
+ while (dev->ring_head == dev->ring_tail) {
dev->interrupt_in_done = 0;
spin_unlock_irq(&dev->rbsl);
if (file->f_flags & O_NONBLOCK) {
@@ -477,8 +477,8 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done);
if (retval < 0)
goto unlock_exit;
- } else {
- spin_unlock_irq(&dev->rbsl);
+
+ spin_lock_irq(&dev->rbsl);
}

/* actual_buffer contains actual_length + interrupt_in_buffer */
@@ -487,17 +487,19 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
if (bytes_to_read < *actual_buffer)
dev_warn(&dev->intf->dev, "Read buffer overflow, %zd bytes dropped\n",
*actual_buffer-bytes_to_read);
+ spin_unlock_irq(&dev->rbsl);

/* copy one interrupt_in_buffer from ring_buffer into userspace */
if (copy_to_user(buffer, actual_buffer+1, bytes_to_read)) {
retval = -EFAULT;
goto unlock_exit;
}
- dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size;
-
retval = bytes_to_read;

spin_lock_irq(&dev->rbsl);
+
+ dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size;
+
if (dev->buffer_overflow) {
dev->buffer_overflow = 0;
spin_unlock_irq(&dev->rbsl);
@@ -693,12 +695,17 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n");

dev->interrupt_in_endpoint_size = usb_endpoint_maxp(dev->interrupt_in_endpoint);
+ dev_info(&intf->dev, "%s - interrupt_in_endpoint_size = %zu\n",
+ __func__, dev->interrupt_in_endpoint_size);
dev->ring_buffer =
kmalloc_array(ring_buffer_size,
sizeof(size_t) + dev->interrupt_in_endpoint_size,
GFP_KERNEL);
if (!dev->ring_buffer)
goto error;
+ dev_info(&intf->dev, "%s - ring_buffer = %px\n", __func__,
+ dev->ring_buffer);
+
dev->interrupt_in_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL);
if (!dev->interrupt_in_buffer)
goto error;
--
2.23.0