Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntoskrnl.exe/ntoskrnl.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index d20b39efe15..b0ac64e8b51 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -1628,9 +1628,17 @@ void WINAPI IoDeleteDevice( DEVICE_OBJECT *device ) { struct wine_device *wine_device = CONTAINING_RECORD(device, struct wine_device, device_obj); DEVICE_OBJECT **prev = &device->DriverObject->DeviceObject; + DEVICE_RELATIONS *children; + unsigned int i; + while (*prev && *prev != device) prev = &(*prev)->NextDevice; if (*prev) *prev = (*prev)->NextDevice; - ExFreePool( wine_device->children ); + if ((children = wine_device->children)) + { + for (i = 0; i < children->Count; ++i) + ObDereferenceObject( children->Objects[i] ); + ExFreePool( children ); + } ObDereferenceObject( device ); } }
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntoskrnl.exe/pnp.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/dlls/ntoskrnl.exe/pnp.c b/dlls/ntoskrnl.exe/pnp.c index d8eb62bc17a..6d53d79267e 100644 --- a/dlls/ntoskrnl.exe/pnp.c +++ b/dlls/ntoskrnl.exe/pnp.c @@ -366,6 +366,12 @@ static void send_remove_device_irp( DEVICE_OBJECT *device, UCHAR code ) send_pnp_irp( device, code ); }
+static void remove_device( DEVICE_OBJECT *device ) +{ + send_remove_device_irp( device, IRP_MN_SURPRISE_REMOVAL ); + send_remove_device_irp( device, IRP_MN_REMOVE_DEVICE ); +} + static BOOL device_in_list( const DEVICE_RELATIONS *list, const DEVICE_OBJECT *device ) { ULONG i; @@ -440,8 +446,7 @@ static void handle_bus_relations( DEVICE_OBJECT *parent ) if (!device_in_list( relations, child )) { TRACE("Removing device %p.\n", child); - send_remove_device_irp( child, IRP_MN_SURPRISE_REMOVAL ); - send_remove_device_irp( child, IRP_MN_REMOVE_DEVICE ); + remove_device( child ); } ObDereferenceObject( child ); } @@ -1105,10 +1110,7 @@ void pnp_manager_stop_driver( struct wine_driver *driver ) struct root_pnp_device *device, *next;
LIST_FOR_EACH_ENTRY_SAFE( device, next, &driver->root_pnp_devices, struct root_pnp_device, entry ) - { - send_remove_device_irp( device->device, IRP_MN_SURPRISE_REMOVAL ); - send_remove_device_irp( device->device, IRP_MN_REMOVE_DEVICE ); - } + remove_device( device->device ); }
void pnp_manager_stop(void) @@ -1181,9 +1183,7 @@ void CDECL wine_enumerate_root_devices( const WCHAR *driver_name ) LIST_FOR_EACH_ENTRY_SAFE( pnp_device, next, &driver->root_pnp_devices, struct root_pnp_device, entry ) { TRACE("Removing device %s.\n", debugstr_w(pnp_device->id)); - - send_remove_device_irp( pnp_device->device, IRP_MN_SURPRISE_REMOVAL ); - send_remove_device_irp( pnp_device->device, IRP_MN_REMOVE_DEVICE ); + remove_device( pnp_device->device ); }
list_move_head( &driver->root_pnp_devices, &new_list );
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/wineusb.sys/wineusb.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c index fae297915fc..a19da6df8f4 100644 --- a/dlls/wineusb.sys/wineusb.c +++ b/dlls/wineusb.sys/wineusb.c @@ -144,6 +144,7 @@ static void remove_usb_device(libusb_device *libusb_device) { if (device->libusb_device == libusb_device) { + device->removed = TRUE; list_remove(&device->entry); break; }
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51479 Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- 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);