diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c index 2305d425e6c9..3cd709fbbd79 100644 --- a/drivers/usb/usbip/stub_dev.c +++ b/drivers/usb/usbip/stub_dev.c @@ -131,10 +131,12 @@ static void stub_shutdown_connection(struct usbip_device *ud) /* 1. stop threads */ if (ud->tcp_rx) { + pr_info("%s: stop rx %p\n", __func__, ud->tcp_rx); kthread_stop_put(ud->tcp_rx); ud->tcp_rx = NULL; } if (ud->tcp_tx) { + pr_info("%s: stop tx %p\n", __func__, ud->tcp_tx); kthread_stop_put(ud->tcp_tx); ud->tcp_tx = NULL; } @@ -146,6 +148,7 @@ static void stub_shutdown_connection(struct usbip_device *ud) * not touch NULL socket. */ if (ud->tcp_socket) { + pr_info("%s: close sock %p\n", __func__, ud->tcp_socket); sockfd_put(ud->tcp_socket); ud->tcp_socket = NULL; ud->sockfd = -1; diff --git a/drivers/usb/usbip/vhci.h b/drivers/usb/usbip/vhci.h index 5659dce1526e..54df09f51b01 100644 --- a/drivers/usb/usbip/vhci.h +++ b/drivers/usb/usbip/vhci.h @@ -171,4 +171,6 @@ static inline struct vhci_hcd *vdev_to_vhci_hcd(struct vhci_device *vdev) return container_of((void *)(vdev - vdev->rhport), struct vhci_hcd, vdev); } +extern void dump_vdev(const struct vhci_device *vdev); + #endif /* __USBIP_VHCI_H */ diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 3209b5ddd30c..703c1773f8cd 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -1016,17 +1016,32 @@ static void vhci_shutdown_connection(struct usbip_device *ud) /* kill threads related to this sdev */ if (vdev->ud.tcp_rx) { - kthread_stop_put(vdev->ud.tcp_rx); + struct task_struct *rx; + + schedule_timeout_uninterruptible(1); + rx = READ_ONCE(vdev->ud.tcp_rx); + pr_info("%s: stop rx %p\n", __func__, rx); + if (!rx) + dump_vdev(vdev); + kthread_stop_put(rx); vdev->ud.tcp_rx = NULL; } if (vdev->ud.tcp_tx) { - kthread_stop_put(vdev->ud.tcp_tx); + struct task_struct *tx; + + schedule_timeout_uninterruptible(1); + tx = READ_ONCE(vdev->ud.tcp_tx); + pr_info("%s: stop tx %p\n", __func__, tx); + if (!tx) + dump_vdev(vdev); + kthread_stop_put(tx); vdev->ud.tcp_tx = NULL; } pr_info("stop threads\n"); /* active connection is closed */ if (vdev->ud.tcp_socket) { + pr_info("%s: close sock %p\n", __func__, ud->tcp_socket); sockfd_put(vdev->ud.tcp_socket); vdev->ud.tcp_socket = NULL; vdev->ud.sockfd = -1; @@ -1074,10 +1089,16 @@ static void vhci_device_reset(struct usbip_device *ud) vdev->udev = NULL; if (ud->tcp_socket) { + pr_info("%s: close sock %p\n", __func__, ud->tcp_socket); + if (vdev->ud.tcp_tx || vdev->ud.tcp_rx) { + dump_vdev(vdev); + BUG_ON(1); + } sockfd_put(ud->tcp_socket); ud->tcp_socket = NULL; ud->sockfd = -1; } + pr_info("%s: VDEV_ST_NULL ud=%p\n", __func__, ud); ud->status = VDEV_ST_NULL; spin_unlock_irqrestore(&ud->lock, flags); @@ -1094,6 +1115,7 @@ static void vhci_device_unusable(struct usbip_device *ud) static void vhci_device_init(struct vhci_device *vdev) { + pr_info("%s: VDEV_ST_NULL %p\n", __func__, vdev); memset(vdev, 0, sizeof(struct vhci_device)); vdev->ud.side = USBIP_VHCI; diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c index be37aec250c2..2b1191dea53b 100644 --- a/drivers/usb/usbip/vhci_sysfs.c +++ b/drivers/usb/usbip/vhci_sysfs.c @@ -312,6 +312,8 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr, struct vhci *vhci; int err; unsigned long flags; + struct task_struct *tx; + struct task_struct *rx; /* * @rhport: port number of vhci_hcd @@ -352,6 +354,14 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr, if (!socket) return -EINVAL; + /* Create threads now, for this can fail with -EINTR. */ + rx = kthread_create(vhci_rx_loop, &vdev->ud, "vhci_rx"); + tx = kthread_create(vhci_tx_loop, &vdev->ud, "vhci_tx"); + if (IS_ERR(rx) || IS_ERR(tx)) { + sockfd_put(socket); + goto thread_error; + } + /* now need lock until setting vdev status as used */ /* begin a lock */ @@ -370,7 +380,8 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr, * Will be retried from userspace * if there's another free port. */ - return -EBUSY; + err = -EBUSY; + goto thread_error; } dev_info(dev, "pdev(%u) rhport(%u) sockfd(%d)\n", @@ -388,12 +399,26 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr, spin_unlock_irqrestore(&vhci->lock, flags); /* end the lock */ - vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx"); - vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx"); + get_task_struct(rx); + vdev->ud.tcp_rx = rx; + wake_up_process(rx); + get_task_struct(tx); + vdev->ud.tcp_tx = tx; + wake_up_process(tx); rh_port_connect(vdev, speed); return count; + thread_error: + if (!IS_ERR(rx)) { + err = PTR_ERR(rx); + kthread_stop(rx); + } + if (!IS_ERR(tx)) { + err = PTR_ERR(tx); + kthread_stop(tx); + } + return err; } static DEVICE_ATTR_WO(attach); diff --git a/drivers/usb/usbip/vhci_tx.c b/drivers/usb/usbip/vhci_tx.c index 0ae40a13a9fe..ed21a423baa7 100644 --- a/drivers/usb/usbip/vhci_tx.c +++ b/drivers/usb/usbip/vhci_tx.c @@ -49,7 +49,18 @@ static struct vhci_priv *dequeue_from_priv_tx(struct vhci_device *vdev) return NULL; } -static int vhci_send_cmd_submit(struct vhci_device *vdev) +void dump_vdev(const struct vhci_device *vdev) +{ + pr_err("vdev: udev=%p devid=%u priv_tx.prev=%p priv_tx.next=%p priv_rx.prev=%p priv_rx.next=%p unlink_tx.prev=%p unlink_tx.next=%p unlink_rx.prev=%p unlink_rx.next=%p\n", + vdev->udev, vdev->devid, vdev->priv_tx.prev, vdev->priv_tx.next, vdev->priv_rx.prev, + vdev->priv_rx.next, vdev->unlink_tx.prev, vdev->unlink_tx.next, + vdev->unlink_rx.prev, vdev->unlink_rx.next); + pr_err("vdev->ud: side=%u status=%u sockfd=%d tcp_socket=%p tcp_rx=%p tcp_tx=%p event=%lu\n", + vdev->ud.side, vdev->ud.status, vdev->ud.sockfd, vdev->ud.tcp_socket, + vdev->ud.tcp_rx, vdev->ud.tcp_tx, vdev->ud.event); +} + +static int vhci_send_cmd_submit(struct vhci_device *vdev, struct socket *socket) { struct usbip_iso_packet_descriptor *iso_buffer = NULL; struct vhci_priv *priv = NULL; @@ -135,8 +146,13 @@ static int vhci_send_cmd_submit(struct vhci_device *vdev) iovnum++; txsize += len; } - - ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, iovnum, + if (!socket || socket != vdev->ud.tcp_socket) { + pr_err("%s: sock changed from %p to %p\n", __func__, socket, + vdev->ud.tcp_socket); + dump_vdev(vdev); + socket = vdev->ud.tcp_socket; + } + ret = kernel_sendmsg(socket, &msg, iov, iovnum, txsize); if (ret != txsize) { pr_err("sendmsg failed!, ret=%d for %zd\n", ret, @@ -184,7 +200,7 @@ static struct vhci_unlink *dequeue_from_unlink_tx(struct vhci_device *vdev) return NULL; } -static int vhci_send_cmd_unlink(struct vhci_device *vdev) +static int vhci_send_cmd_unlink(struct vhci_device *vdev, struct socket *socket) { struct vhci_unlink *unlink = NULL; @@ -216,7 +232,13 @@ static int vhci_send_cmd_unlink(struct vhci_device *vdev) iov.iov_len = sizeof(pdu_header); txsize = sizeof(pdu_header); - ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, &iov, 1, txsize); + if (!socket || socket != vdev->ud.tcp_socket) { + pr_err("%s: sock changed from %p to %p\n", __func__, socket, + vdev->ud.tcp_socket); + dump_vdev(vdev); + socket = vdev->ud.tcp_socket; + } + ret = kernel_sendmsg(socket, &msg, &iov, 1, txsize); if (ret != txsize) { pr_err("sendmsg failed!, ret=%d for %zd\n", ret, txsize); @@ -236,12 +258,15 @@ int vhci_tx_loop(void *data) { struct usbip_device *ud = data; struct vhci_device *vdev = container_of(ud, struct vhci_device, ud); + struct socket *socket = vdev->ud.tcp_socket; + pr_info("%s: thread starting %p with sock %p\n", __func__, vdev->ud.tcp_tx, + socket); while (!kthread_should_stop()) { - if (vhci_send_cmd_submit(vdev) < 0) + if (vhci_send_cmd_submit(vdev, socket) < 0) break; - if (vhci_send_cmd_unlink(vdev) < 0) + if (vhci_send_cmd_unlink(vdev, socket) < 0) break; wait_event_interruptible(vdev->waitq_tx, @@ -251,6 +276,8 @@ int vhci_tx_loop(void *data) usbip_dbg_vhci_tx("pending urbs ?, now wake up\n"); } + pr_info("%s: thread exiting %p with sock %p\n", __func__, vdev->ud.tcp_tx, + socket); return 0; } diff --git a/drivers/usb/usbip/vudc_dev.c b/drivers/usb/usbip/vudc_dev.c index c8eeabdd9b56..dbc08f7d53ae 100644 --- a/drivers/usb/usbip/vudc_dev.c +++ b/drivers/usb/usbip/vudc_dev.c @@ -437,15 +437,18 @@ static void vudc_shutdown(struct usbip_device *ud) kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR); if (ud->tcp_rx) { + pr_info("%s: stop rx %p\n", __func__, ud->tcp_rx); kthread_stop_put(ud->tcp_rx); ud->tcp_rx = NULL; } if (ud->tcp_tx) { + pr_info("%s: stop tx %p\n", __func__, ud->tcp_tx); kthread_stop_put(ud->tcp_tx); ud->tcp_tx = NULL; } if (ud->tcp_socket) { + pr_info("%s: close sock %p\n", __func__, ud->tcp_socket); sockfd_put(ud->tcp_socket); ud->tcp_socket = NULL; }