summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2016-06-07 12:12:38 +0200
committerNathan Hjelm <hjelmn@me.com>2016-08-17 12:52:40 -0600
commit00e36c829fe87a3d285d7a774eb8a1ca8797d0c0 (patch)
tree47ee07189a4136faae9a2e91590f922bf29c5fa5
parent9542c38cf2cbd911bd7e3ec161e564b3ae63d4fe (diff)
downloadlibusb-00e36c829fe87a3d285d7a774eb8a1ca8797d0c0.tar.gz
linux_usbfs: Deal with receiving POLLERR before all transfers have completed
The linux kernel will set its internal device state to USB_STATE_NOTATTACHED as soon as it detects the disconnect, and then start a worker thread to deal with the actual disconnection, kill outstanding urbs, etc. The usbfs poll implementation will return POLL_ERR as soon as ps->dev->state == USB_STATE_NOTATTACHED. The kernel will not wakeup the poll until it is done with processing the disconnection. But if we happen to call poll() between the state change and the disconnection being fully processed, we may not be able to reap all outstanding transfers, even on kernels with the USBFS_CAP_REAP_AFTER_DISCONNECT capability. This commit deals with this by trying to reap as many transfers as possible on disconnect on USBFS_CAP_REAP_AFTER_DISCONNECT capable kernels and then calling usbi_handle_disconnect(handle) to deal with any remaining ones. On USBFS_CAP_REAP_AFTER_DISCONNECT capable kernels this will be a no-op unless we hit the race. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r--libusb/os/linux_usbfs.c10
-rw-r--r--libusb/version_nano.h2
2 files changed, 8 insertions, 4 deletions
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index 0689894..9cbeb80 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -2638,10 +2638,14 @@ static int op_handle_events(struct libusb_context *ctx,
handle->dev->device_address);
usbi_mutex_static_unlock(&linux_hotplug_lock);
- if (!(hpriv->caps & USBFS_CAP_REAP_AFTER_DISCONNECT)) {
- usbi_handle_disconnect(handle);
- continue;
+ if (hpriv->caps & USBFS_CAP_REAP_AFTER_DISCONNECT) {
+ do {
+ r = reap_for_handle(handle);
+ } while (r == 0);
}
+
+ usbi_handle_disconnect(handle);
+ continue;
}
do {
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index bb7624f..b394a2e 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 11137
+#define LIBUSB_NANO 11138