Zebediah Figura : wineusb.sys: Unlink devices from the list in the PDO IRP_MN_SURPRISE_REMOVAL.
Alexandre Julliard
julliard at winehq.org
Mon Aug 23 16:24:13 CDT 2021
Module: wine
Branch: master
Commit: b6a20450f47807a162318ef63e50278488d146f5
URL: https://source.winehq.org/git/wine.git/?a=commit;h=b6a20450f47807a162318ef63e50278488d146f5
Author: Zebediah Figura <zfigura at codeweavers.com>
Date: Fri Aug 20 19:01:27 2021 -0500
wineusb.sys: Unlink devices from the list in the PDO IRP_MN_SURPRISE_REMOVAL.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51479
Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/wineusb.sys/wineusb.c | 30 +++++++++++++++++++++++++++---
1 file changed, 27 insertions(+), 3 deletions(-)
diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c
index a19da6df8f4..441ed338f1e 100644
--- a/dlls/wineusb.sys/wineusb.c
+++ b/dlls/wineusb.sys/wineusb.c
@@ -144,8 +144,11 @@ static void remove_usb_device(libusb_device *libusb_device)
{
if (device->libusb_device == libusb_device)
{
- device->removed = TRUE;
- list_remove(&device->entry);
+ if (!device->removed)
+ {
+ device->removed = TRUE;
+ list_remove(&device->entry);
+ }
break;
}
}
@@ -257,8 +260,24 @@ static NTSTATUS fdo_pnp(IRP *irp)
CloseHandle(event_thread);
EnterCriticalSection(&wineusb_cs);
+ /* Normally we unlink all devices either:
+ *
+ * - as a result of hot-unplug, which unlinks the device, and causes
+ * a subsequent IRP_MN_REMOVE_DEVICE which will free it;
+ *
+ * - if the parent is deleted (at shutdown time), in which case
+ * ntoskrnl will send us IRP_MN_SURPRISE_REMOVAL and
+ * IRP_MN_REMOVE_DEVICE unprompted.
+ *
+ * But we can get devices hotplugged between when shutdown starts
+ * and now, in which case they'll be stuck in this list and never
+ * freed.
+ *
+ * FIXME: This is still broken, though. If a device is hotplugged
+ * and then removed, it'll be unlinked and never freed. */
LIST_FOR_EACH_ENTRY_SAFE(device, cursor, &device_list, struct usb_device, entry)
{
+ assert(!device->removed);
libusb_unref_device(device->libusb_device);
libusb_close(device->handle);
list_remove(&device->entry);
@@ -408,12 +427,17 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp)
case IRP_MN_SURPRISE_REMOVAL:
EnterCriticalSection(&wineusb_cs);
remove_pending_irps(device);
- device->removed = TRUE;
+ if (!device->removed)
+ {
+ device->removed = TRUE;
+ list_remove(&device->entry);
+ }
LeaveCriticalSection(&wineusb_cs);
ret = STATUS_SUCCESS;
break;
case IRP_MN_REMOVE_DEVICE:
+ assert(device->removed);
remove_pending_irps(device);
libusb_unref_device(device->libusb_device);
More information about the wine-cvs
mailing list