aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Vozeler <max@vozeler.com>2011-01-12 08:02:01 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-01-20 19:01:49 -0500
commitb92a5e23737172c52656a090977408a80d7f06d1 (patch)
tree1232bd42923d3cc4e31bafb8fa92c5d1d214be55
parent7606ee8aa33287dd3e6eb44c78541b87a413a325 (diff)
staging: usbip: vhci: give back URBs from in-flight unlink requests
If we never received a RET_UNLINK because the TCP connection broke the pending URBs still need to be unlinked and given back. Previously processes would be stuck trying to kill the URB even after the device was detached. Signed-off-by: Max Vozeler <max@vozeler.com> Tested-by: Mark Wehby <MWehby@luxotticaRetail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/staging/usbip/vhci.h3
-rw-r--r--drivers/staging/usbip/vhci_hcd.c24
-rw-r--r--drivers/staging/usbip/vhci_rx.c15
3 files changed, 35 insertions, 7 deletions
diff --git a/drivers/staging/usbip/vhci.h b/drivers/staging/usbip/vhci.h
index 41a1fe5138f4..2cfd00ec1164 100644
--- a/drivers/staging/usbip/vhci.h
+++ b/drivers/staging/usbip/vhci.h
@@ -119,6 +119,9 @@ void rh_port_disconnect(int rhport);
119void vhci_rx_loop(struct usbip_task *ut); 119void vhci_rx_loop(struct usbip_task *ut);
120void vhci_tx_loop(struct usbip_task *ut); 120void vhci_tx_loop(struct usbip_task *ut);
121 121
122struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev,
123 __u32 seqnum);
124
122#define hardware (&the_controller->pdev.dev) 125#define hardware (&the_controller->pdev.dev)
123 126
124static inline struct vhci_device *port_to_vdev(__u32 port) 127static inline struct vhci_device *port_to_vdev(__u32 port)
diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c
index 5f1e2b0a628a..3a22f65b66d0 100644
--- a/drivers/staging/usbip/vhci_hcd.c
+++ b/drivers/staging/usbip/vhci_hcd.c
@@ -808,7 +808,6 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
808 return 0; 808 return 0;
809} 809}
810 810
811
812static void vhci_device_unlink_cleanup(struct vhci_device *vdev) 811static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
813{ 812{
814 struct vhci_unlink *unlink, *tmp; 813 struct vhci_unlink *unlink, *tmp;
@@ -816,11 +815,34 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
816 spin_lock(&vdev->priv_lock); 815 spin_lock(&vdev->priv_lock);
817 816
818 list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) { 817 list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
818 usbip_uinfo("unlink cleanup tx %lu\n", unlink->unlink_seqnum);
819 list_del(&unlink->list); 819 list_del(&unlink->list);
820 kfree(unlink); 820 kfree(unlink);
821 } 821 }
822 822
823 list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) { 823 list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) {
824 struct urb *urb;
825
826 /* give back URB of unanswered unlink request */
827 usbip_uinfo("unlink cleanup rx %lu\n", unlink->unlink_seqnum);
828
829 urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);
830 if (!urb) {
831 usbip_uinfo("the urb (seqnum %lu) was already given back\n",
832 unlink->unlink_seqnum);
833 list_del(&unlink->list);
834 kfree(unlink);
835 continue;
836 }
837
838 urb->status = -ENODEV;
839
840 spin_lock(&the_controller->lock);
841 usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
842 spin_unlock(&the_controller->lock);
843
844 usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status);
845
824 list_del(&unlink->list); 846 list_del(&unlink->list);
825 kfree(unlink); 847 kfree(unlink);
826 } 848 }
diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c
index 8147d7202b2d..bdbedd256903 100644
--- a/drivers/staging/usbip/vhci_rx.c
+++ b/drivers/staging/usbip/vhci_rx.c
@@ -23,16 +23,14 @@
23#include "vhci.h" 23#include "vhci.h"
24 24
25 25
26/* get URB from transmitted urb queue */ 26/* get URB from transmitted urb queue. caller must hold vdev->priv_lock */
27static struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, 27struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev,
28 __u32 seqnum) 28 __u32 seqnum)
29{ 29{
30 struct vhci_priv *priv, *tmp; 30 struct vhci_priv *priv, *tmp;
31 struct urb *urb = NULL; 31 struct urb *urb = NULL;
32 int status; 32 int status;
33 33
34 spin_lock(&vdev->priv_lock);
35
36 list_for_each_entry_safe(priv, tmp, &vdev->priv_rx, list) { 34 list_for_each_entry_safe(priv, tmp, &vdev->priv_rx, list) {
37 if (priv->seqnum == seqnum) { 35 if (priv->seqnum == seqnum) {
38 urb = priv->urb; 36 urb = priv->urb;
@@ -63,8 +61,6 @@ static struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev,
63 } 61 }
64 } 62 }
65 63
66 spin_unlock(&vdev->priv_lock);
67
68 return urb; 64 return urb;
69} 65}
70 66
@@ -74,9 +70,11 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev,
74 struct usbip_device *ud = &vdev->ud; 70 struct usbip_device *ud = &vdev->ud;
75 struct urb *urb; 71 struct urb *urb;
76 72
73 spin_lock(&vdev->priv_lock);
77 74
78 urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum); 75 urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum);
79 76
77 spin_unlock(&vdev->priv_lock);
80 78
81 if (!urb) { 79 if (!urb) {
82 usbip_uerr("cannot find a urb of seqnum %u\n", 80 usbip_uerr("cannot find a urb of seqnum %u\n",
@@ -161,7 +159,12 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
161 return; 159 return;
162 } 160 }
163 161
162 spin_lock(&vdev->priv_lock);
163
164 urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum); 164 urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);
165
166 spin_unlock(&vdev->priv_lock);
167
165 if (!urb) { 168 if (!urb) {
166 /* 169 /*
167 * I get the result of a unlink request. But, it seems that I 170 * I get the result of a unlink request. But, it seems that I