diff options
author | Max Vozeler <max@vozeler.com> | 2011-01-12 08:02:04 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-01-20 19:01:49 -0500 |
commit | bd65f6233f6bc3233e7910752689fe3a45dc2e0c (patch) | |
tree | 40cf7fc453f735f006ab4d2a97549abfe1d9e9e0 | |
parent | 7e249c8b0737429bbf534515f81aded93504f449 (diff) |
staging: usbip: vhci: handle EAGAIN from SO_RCVTIMEO
If there is a receive timeout without any active
requests, we can tell the connection was idle and
ignore the timeout.
If there are active requests for which we expect
to receive a reply we close the connection.
This makes it possible to set an upper bound on
the time a usbip device may be unresponsive.
This is a workaround for the lack of heart-beat
messages in the USBIP protocol.
Extending the protocol would break compatibility
with all previous stub versions, so this seems like
the lesser evil.
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_rx.c | 21 |
1 files changed, 20 insertions, 1 deletions
diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c index ac15cea75396..bf6991470941 100644 --- a/drivers/staging/usbip/vhci_rx.c +++ b/drivers/staging/usbip/vhci_rx.c | |||
@@ -193,6 +193,19 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev, | |||
193 | return; | 193 | return; |
194 | } | 194 | } |
195 | 195 | ||
196 | static int vhci_priv_tx_empty(struct vhci_device *vdev) | ||
197 | { | ||
198 | int empty = 0; | ||
199 | |||
200 | spin_lock(&vdev->priv_lock); | ||
201 | |||
202 | empty = list_empty(&vdev->priv_rx); | ||
203 | |||
204 | spin_unlock(&vdev->priv_lock); | ||
205 | |||
206 | return empty; | ||
207 | } | ||
208 | |||
196 | /* recv a pdu */ | 209 | /* recv a pdu */ |
197 | static void vhci_rx_pdu(struct usbip_device *ud) | 210 | static void vhci_rx_pdu(struct usbip_device *ud) |
198 | { | 211 | { |
@@ -210,8 +223,14 @@ static void vhci_rx_pdu(struct usbip_device *ud) | |||
210 | if (ret < 0) { | 223 | if (ret < 0) { |
211 | if (ret == -ECONNRESET) | 224 | if (ret == -ECONNRESET) |
212 | usbip_uinfo("connection reset by peer\n"); | 225 | usbip_uinfo("connection reset by peer\n"); |
213 | else if (ret != -ERESTARTSYS) | 226 | else if (ret == -EAGAIN) { |
227 | /* ignore if connection was idle */ | ||
228 | if (vhci_priv_tx_empty(vdev)) | ||
229 | return; | ||
230 | usbip_uinfo("connection timed out with pending urbs\n"); | ||
231 | } else if (ret != -ERESTARTSYS) | ||
214 | usbip_uinfo("xmit failed %d\n", ret); | 232 | usbip_uinfo("xmit failed %d\n", ret); |
233 | |||
215 | usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); | 234 | usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); |
216 | return; | 235 | return; |
217 | } | 236 | } |