diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 66cde5e5f796..3fdcb93b667d 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -997,14 +997,12 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev) spin_unlock_irqrestore(&vhci->lock, flags); } -/* - * The important thing is that only one context begins cleanup. - * This is why error handling and cleanup become simple. - * We do not want to consider race condition as possible. - */ static void vhci_shutdown_connection(struct usbip_device *ud) { struct vhci_device *vdev = container_of(ud, struct vhci_device, ud); + struct vhci_hcd *vhci_hcd = vdev_to_vhci_hcd(vdev); + struct vhci *vhci = vhci_hcd->vhci; + unsigned long flags; /* need this? see stub_dev.c */ if (ud->tcp_socket) { @@ -1012,6 +1010,10 @@ static void vhci_shutdown_connection(struct usbip_device *ud) kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR); } + /* avoid races during shutdown */ + spin_lock_irqsave(&vhci->lock, flags); + spin_lock(&vdev->priv_lock); + /* kill threads related to this sdev */ if (vdev->ud.tcp_rx) { kthread_stop_put(vdev->ud.tcp_rx); @@ -1031,6 +1033,10 @@ static void vhci_shutdown_connection(struct usbip_device *ud) } pr_info("release socket\n"); + /* unlock - vhci_device_unlink_cleanup() holds the locks */ + spin_unlock(&vdev->priv_lock); + spin_unlock_irqrestore(&vhci->lock, flags); + vhci_device_unlink_cleanup(vdev); /*