linux: Take hotplug_lock for scan_devices, hotplug_enumerate and _disconnect
authorHans de Goede <hdegoede@redhat.com>
Thu, 16 May 2013 14:21:23 +0000 (16:21 +0200)
committerHans de Goede <hdegoede@redhat.com>
Thu, 16 May 2013 15:18:32 +0000 (17:18 +0200)
As soon as we've started listening for hp events, hotplug_enumerate and
_disconnect can run, they do test then add / remove operations on the
device list. This can race with scan_devices adding devices, so take
the lock around all 3 to avoid the race.

Also fix the lock not being released in case of linux_start_event_monitor
failure.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
libusb/os/linux_usbfs.c
libusb/version_nano.h

index 3ff5a9a..6a22f7d 100644 (file)
@@ -432,18 +432,18 @@ static int op_init(struct libusb_context *ctx)
        }
 
        pthread_mutex_lock(&hotplug_lock);
+       r = LIBUSB_SUCCESS;
        if (!init_count++) {
                /* start up hotplug event handler */
                r = linux_start_event_monitor();
                if (LIBUSB_SUCCESS != r) {
                        usbi_err(ctx, "error starting hotplug event monitor");
-                       return r;
                }
        }
+       if (r == LIBUSB_SUCCESS)
+               r = linux_scan_devices(ctx);
        pthread_mutex_unlock(&hotplug_lock);
 
-       r = linux_scan_devices(ctx);
-
        return r;
 }
 
@@ -1184,6 +1184,7 @@ void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_na
 {
        struct libusb_context *ctx;
 
+       pthread_mutex_lock(&hotplug_lock);
        list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
                if (usbi_get_device_by_session_id(ctx, busnum << 8 | devaddr)) {
                        /* device already exists in the context */
@@ -1193,6 +1194,7 @@ void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_na
 
                linux_enumerate_device(ctx, busnum, devaddr, sys_name);
        }
+       pthread_mutex_unlock(&hotplug_lock);
 }
 
 void linux_hotplug_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys_name)
@@ -1200,6 +1202,7 @@ void linux_hotplug_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys
        struct libusb_context *ctx;
        struct libusb_device *dev;
 
+       pthread_mutex_lock(&hotplug_lock);
        list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
                dev = usbi_get_device_by_session_id (ctx, busnum << 8 | devaddr);
                if (NULL != dev) {
@@ -1208,6 +1211,7 @@ void linux_hotplug_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys
                        usbi_err(ctx, "device not found for session %x", busnum << 8 | devaddr);
                }
        }
+       pthread_mutex_unlock(&hotplug_lock);
 }
 
 #if !defined(USE_UDEV)
index ddcceda..fce37d3 100644 (file)
@@ -1 +1 @@
-#define LIBUSB_NANO 10675
+#define LIBUSB_NANO 10676