Commit 445e09e7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'usb-5.12-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB/Thunderbolt fixes from Greg KH:
 "Here are a few small USB and Thunderbolt driver fixes for 5.12-rc7 for
  reported issues:

   - thunderbolt leaks and off-by-one fix

   - cdnsp deque fix

   - usbip fixes for syzbot-reported issues

  All have been in linux-next with no reported problems"

* tag 'usb-5.12-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb:
  usbip: synchronize event handler with sysfs code paths
  usbip: vudc synchronize sysfs code paths
  usbip: stub-dev synchronize sysfs code paths
  usbip: add sysfs_lock to synchronize sysfs code paths
  thunderbolt: Fix off by one in tb_port_find_retimer()
  thunderbolt: Fix a leak in tb_retimer_add()
  usb: cdnsp: Fixes issue with dequeuing requests after disabling endpoint
parents 12a0cf72 bc2f3e4c
...@@ -347,7 +347,7 @@ static int tb_retimer_add(struct tb_port *port, u8 index, u32 auth_status) ...@@ -347,7 +347,7 @@ static int tb_retimer_add(struct tb_port *port, u8 index, u32 auth_status)
ret = tb_retimer_nvm_add(rt); ret = tb_retimer_nvm_add(rt);
if (ret) { if (ret) {
dev_err(&rt->dev, "failed to add NVM devices: %d\n", ret); dev_err(&rt->dev, "failed to add NVM devices: %d\n", ret);
device_del(&rt->dev); device_unregister(&rt->dev);
return ret; return ret;
} }
...@@ -406,7 +406,7 @@ static struct tb_retimer *tb_port_find_retimer(struct tb_port *port, u8 index) ...@@ -406,7 +406,7 @@ static struct tb_retimer *tb_port_find_retimer(struct tb_port *port, u8 index)
*/ */
int tb_retimer_scan(struct tb_port *port) int tb_retimer_scan(struct tb_port *port)
{ {
u32 status[TB_MAX_RETIMER_INDEX] = {}; u32 status[TB_MAX_RETIMER_INDEX + 1] = {};
int ret, i, last_idx = 0; int ret, i, last_idx = 0;
if (!port->cap_usb4) if (!port->cap_usb4)
......
...@@ -1128,6 +1128,10 @@ static int cdnsp_gadget_ep_dequeue(struct usb_ep *ep, ...@@ -1128,6 +1128,10 @@ static int cdnsp_gadget_ep_dequeue(struct usb_ep *ep,
return -ESHUTDOWN; return -ESHUTDOWN;
} }
/* Requests has been dequeued during disabling endpoint. */
if (!(pep->ep_state & EP_ENABLED))
return 0;
spin_lock_irqsave(&pdev->lock, flags); spin_lock_irqsave(&pdev->lock, flags);
ret = cdnsp_ep_dequeue(pep, to_cdnsp_request(request)); ret = cdnsp_ep_dequeue(pep, to_cdnsp_request(request));
spin_unlock_irqrestore(&pdev->lock, flags); spin_unlock_irqrestore(&pdev->lock, flags);
......
...@@ -63,6 +63,7 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a ...@@ -63,6 +63,7 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
dev_info(dev, "stub up\n"); dev_info(dev, "stub up\n");
mutex_lock(&sdev->ud.sysfs_lock);
spin_lock_irq(&sdev->ud.lock); spin_lock_irq(&sdev->ud.lock);
if (sdev->ud.status != SDEV_ST_AVAILABLE) { if (sdev->ud.status != SDEV_ST_AVAILABLE) {
...@@ -87,13 +88,13 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a ...@@ -87,13 +88,13 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
tcp_rx = kthread_create(stub_rx_loop, &sdev->ud, "stub_rx"); tcp_rx = kthread_create(stub_rx_loop, &sdev->ud, "stub_rx");
if (IS_ERR(tcp_rx)) { if (IS_ERR(tcp_rx)) {
sockfd_put(socket); sockfd_put(socket);
return -EINVAL; goto unlock_mutex;
} }
tcp_tx = kthread_create(stub_tx_loop, &sdev->ud, "stub_tx"); tcp_tx = kthread_create(stub_tx_loop, &sdev->ud, "stub_tx");
if (IS_ERR(tcp_tx)) { if (IS_ERR(tcp_tx)) {
kthread_stop(tcp_rx); kthread_stop(tcp_rx);
sockfd_put(socket); sockfd_put(socket);
return -EINVAL; goto unlock_mutex;
} }
/* get task structs now */ /* get task structs now */
...@@ -112,6 +113,8 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a ...@@ -112,6 +113,8 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
wake_up_process(sdev->ud.tcp_rx); wake_up_process(sdev->ud.tcp_rx);
wake_up_process(sdev->ud.tcp_tx); wake_up_process(sdev->ud.tcp_tx);
mutex_unlock(&sdev->ud.sysfs_lock);
} else { } else {
dev_info(dev, "stub down\n"); dev_info(dev, "stub down\n");
...@@ -122,6 +125,7 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a ...@@ -122,6 +125,7 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
spin_unlock_irq(&sdev->ud.lock); spin_unlock_irq(&sdev->ud.lock);
usbip_event_add(&sdev->ud, SDEV_EVENT_DOWN); usbip_event_add(&sdev->ud, SDEV_EVENT_DOWN);
mutex_unlock(&sdev->ud.sysfs_lock);
} }
return count; return count;
...@@ -130,6 +134,8 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a ...@@ -130,6 +134,8 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
sockfd_put(socket); sockfd_put(socket);
err: err:
spin_unlock_irq(&sdev->ud.lock); spin_unlock_irq(&sdev->ud.lock);
unlock_mutex:
mutex_unlock(&sdev->ud.sysfs_lock);
return -EINVAL; return -EINVAL;
} }
static DEVICE_ATTR_WO(usbip_sockfd); static DEVICE_ATTR_WO(usbip_sockfd);
...@@ -270,6 +276,7 @@ static struct stub_device *stub_device_alloc(struct usb_device *udev) ...@@ -270,6 +276,7 @@ static struct stub_device *stub_device_alloc(struct usb_device *udev)
sdev->ud.side = USBIP_STUB; sdev->ud.side = USBIP_STUB;
sdev->ud.status = SDEV_ST_AVAILABLE; sdev->ud.status = SDEV_ST_AVAILABLE;
spin_lock_init(&sdev->ud.lock); spin_lock_init(&sdev->ud.lock);
mutex_init(&sdev->ud.sysfs_lock);
sdev->ud.tcp_socket = NULL; sdev->ud.tcp_socket = NULL;
sdev->ud.sockfd = -1; sdev->ud.sockfd = -1;
......
...@@ -263,6 +263,9 @@ struct usbip_device { ...@@ -263,6 +263,9 @@ struct usbip_device {
/* lock for status */ /* lock for status */
spinlock_t lock; spinlock_t lock;
/* mutex for synchronizing sysfs store paths */
struct mutex sysfs_lock;
int sockfd; int sockfd;
struct socket *tcp_socket; struct socket *tcp_socket;
......
...@@ -70,6 +70,7 @@ static void event_handler(struct work_struct *work) ...@@ -70,6 +70,7 @@ static void event_handler(struct work_struct *work)
while ((ud = get_event()) != NULL) { while ((ud = get_event()) != NULL) {
usbip_dbg_eh("pending event %lx\n", ud->event); usbip_dbg_eh("pending event %lx\n", ud->event);
mutex_lock(&ud->sysfs_lock);
/* /*
* NOTE: shutdown must come first. * NOTE: shutdown must come first.
* Shutdown the device. * Shutdown the device.
...@@ -90,6 +91,7 @@ static void event_handler(struct work_struct *work) ...@@ -90,6 +91,7 @@ static void event_handler(struct work_struct *work)
ud->eh_ops.unusable(ud); ud->eh_ops.unusable(ud);
unset_event(ud, USBIP_EH_UNUSABLE); unset_event(ud, USBIP_EH_UNUSABLE);
} }
mutex_unlock(&ud->sysfs_lock);
wake_up(&ud->eh_waitq); wake_up(&ud->eh_waitq);
} }
......
...@@ -1101,6 +1101,7 @@ static void vhci_device_init(struct vhci_device *vdev) ...@@ -1101,6 +1101,7 @@ static void vhci_device_init(struct vhci_device *vdev)
vdev->ud.side = USBIP_VHCI; vdev->ud.side = USBIP_VHCI;
vdev->ud.status = VDEV_ST_NULL; vdev->ud.status = VDEV_ST_NULL;
spin_lock_init(&vdev->ud.lock); spin_lock_init(&vdev->ud.lock);
mutex_init(&vdev->ud.sysfs_lock);
INIT_LIST_HEAD(&vdev->priv_rx); INIT_LIST_HEAD(&vdev->priv_rx);
INIT_LIST_HEAD(&vdev->priv_tx); INIT_LIST_HEAD(&vdev->priv_tx);
......
...@@ -185,6 +185,8 @@ static int vhci_port_disconnect(struct vhci_hcd *vhci_hcd, __u32 rhport) ...@@ -185,6 +185,8 @@ static int vhci_port_disconnect(struct vhci_hcd *vhci_hcd, __u32 rhport)
usbip_dbg_vhci_sysfs("enter\n"); usbip_dbg_vhci_sysfs("enter\n");
mutex_lock(&vdev->ud.sysfs_lock);
/* lock */ /* lock */
spin_lock_irqsave(&vhci->lock, flags); spin_lock_irqsave(&vhci->lock, flags);
spin_lock(&vdev->ud.lock); spin_lock(&vdev->ud.lock);
...@@ -195,6 +197,7 @@ static int vhci_port_disconnect(struct vhci_hcd *vhci_hcd, __u32 rhport) ...@@ -195,6 +197,7 @@ static int vhci_port_disconnect(struct vhci_hcd *vhci_hcd, __u32 rhport)
/* unlock */ /* unlock */
spin_unlock(&vdev->ud.lock); spin_unlock(&vdev->ud.lock);
spin_unlock_irqrestore(&vhci->lock, flags); spin_unlock_irqrestore(&vhci->lock, flags);
mutex_unlock(&vdev->ud.sysfs_lock);
return -EINVAL; return -EINVAL;
} }
...@@ -205,6 +208,8 @@ static int vhci_port_disconnect(struct vhci_hcd *vhci_hcd, __u32 rhport) ...@@ -205,6 +208,8 @@ static int vhci_port_disconnect(struct vhci_hcd *vhci_hcd, __u32 rhport)
usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN); usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN);
mutex_unlock(&vdev->ud.sysfs_lock);
return 0; return 0;
} }
...@@ -349,30 +354,36 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr, ...@@ -349,30 +354,36 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,
else else
vdev = &vhci->vhci_hcd_hs->vdev[rhport]; vdev = &vhci->vhci_hcd_hs->vdev[rhport];
mutex_lock(&vdev->ud.sysfs_lock);
/* Extract socket from fd. */ /* Extract socket from fd. */
socket = sockfd_lookup(sockfd, &err); socket = sockfd_lookup(sockfd, &err);
if (!socket) { if (!socket) {
dev_err(dev, "failed to lookup sock"); dev_err(dev, "failed to lookup sock");
return -EINVAL; err = -EINVAL;
goto unlock_mutex;
} }
if (socket->type != SOCK_STREAM) { if (socket->type != SOCK_STREAM) {
dev_err(dev, "Expecting SOCK_STREAM - found %d", dev_err(dev, "Expecting SOCK_STREAM - found %d",
socket->type); socket->type);
sockfd_put(socket); sockfd_put(socket);
return -EINVAL; err = -EINVAL;
goto unlock_mutex;
} }
/* create threads before locking */ /* create threads before locking */
tcp_rx = kthread_create(vhci_rx_loop, &vdev->ud, "vhci_rx"); tcp_rx = kthread_create(vhci_rx_loop, &vdev->ud, "vhci_rx");
if (IS_ERR(tcp_rx)) { if (IS_ERR(tcp_rx)) {
sockfd_put(socket); sockfd_put(socket);
return -EINVAL; err = -EINVAL;
goto unlock_mutex;
} }
tcp_tx = kthread_create(vhci_tx_loop, &vdev->ud, "vhci_tx"); tcp_tx = kthread_create(vhci_tx_loop, &vdev->ud, "vhci_tx");
if (IS_ERR(tcp_tx)) { if (IS_ERR(tcp_tx)) {
kthread_stop(tcp_rx); kthread_stop(tcp_rx);
sockfd_put(socket); sockfd_put(socket);
return -EINVAL; err = -EINVAL;
goto unlock_mutex;
} }
/* get task structs now */ /* get task structs now */
...@@ -397,7 +408,8 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr, ...@@ -397,7 +408,8 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,
* Will be retried from userspace * Will be retried from userspace
* if there's another free port. * if there's another free port.
*/ */
return -EBUSY; err = -EBUSY;
goto unlock_mutex;
} }
dev_info(dev, "pdev(%u) rhport(%u) sockfd(%d)\n", dev_info(dev, "pdev(%u) rhport(%u) sockfd(%d)\n",
...@@ -423,7 +435,15 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr, ...@@ -423,7 +435,15 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,
rh_port_connect(vdev, speed); rh_port_connect(vdev, speed);
dev_info(dev, "Device attached\n");
mutex_unlock(&vdev->ud.sysfs_lock);
return count; return count;
unlock_mutex:
mutex_unlock(&vdev->ud.sysfs_lock);
return err;
} }
static DEVICE_ATTR_WO(attach); static DEVICE_ATTR_WO(attach);
......
...@@ -572,6 +572,7 @@ static int init_vudc_hw(struct vudc *udc) ...@@ -572,6 +572,7 @@ static int init_vudc_hw(struct vudc *udc)
init_waitqueue_head(&udc->tx_waitq); init_waitqueue_head(&udc->tx_waitq);
spin_lock_init(&ud->lock); spin_lock_init(&ud->lock);
mutex_init(&ud->sysfs_lock);
ud->status = SDEV_ST_AVAILABLE; ud->status = SDEV_ST_AVAILABLE;
ud->side = USBIP_VUDC; ud->side = USBIP_VUDC;
......
...@@ -112,6 +112,7 @@ static ssize_t usbip_sockfd_store(struct device *dev, ...@@ -112,6 +112,7 @@ static ssize_t usbip_sockfd_store(struct device *dev,
dev_err(dev, "no device"); dev_err(dev, "no device");
return -ENODEV; return -ENODEV;
} }
mutex_lock(&udc->ud.sysfs_lock);
spin_lock_irqsave(&udc->lock, flags); spin_lock_irqsave(&udc->lock, flags);
/* Don't export what we don't have */ /* Don't export what we don't have */
if (!udc->driver || !udc->pullup) { if (!udc->driver || !udc->pullup) {
...@@ -187,6 +188,8 @@ static ssize_t usbip_sockfd_store(struct device *dev, ...@@ -187,6 +188,8 @@ static ssize_t usbip_sockfd_store(struct device *dev,
wake_up_process(udc->ud.tcp_rx); wake_up_process(udc->ud.tcp_rx);
wake_up_process(udc->ud.tcp_tx); wake_up_process(udc->ud.tcp_tx);
mutex_unlock(&udc->ud.sysfs_lock);
return count; return count;
} else { } else {
...@@ -207,6 +210,7 @@ static ssize_t usbip_sockfd_store(struct device *dev, ...@@ -207,6 +210,7 @@ static ssize_t usbip_sockfd_store(struct device *dev,
} }
spin_unlock_irqrestore(&udc->lock, flags); spin_unlock_irqrestore(&udc->lock, flags);
mutex_unlock(&udc->ud.sysfs_lock);
return count; return count;
...@@ -216,6 +220,7 @@ static ssize_t usbip_sockfd_store(struct device *dev, ...@@ -216,6 +220,7 @@ static ssize_t usbip_sockfd_store(struct device *dev,
spin_unlock_irq(&udc->ud.lock); spin_unlock_irq(&udc->ud.lock);
unlock: unlock:
spin_unlock_irqrestore(&udc->lock, flags); spin_unlock_irqrestore(&udc->lock, flags);
mutex_unlock(&udc->ud.sysfs_lock);
return ret; return ret;
} }
......
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