[PATCH v3 2/7] ntoskrnl: Store root PnP devices per driver.

Zebediah Figura z.figura12 at gmail.com
Thu Apr 1 23:23:39 CDT 2021


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/ntoskrnl.exe/ntoskrnl.c         | 52 +++++++++++++++-------------
 dlls/ntoskrnl.exe/ntoskrnl_private.h | 26 ++++++++++++++
 dlls/ntoskrnl.exe/pnp.c              | 37 ++++++++------------
 dlls/ntoskrnl.exe/sync.c             | 19 +++-------
 4 files changed, 71 insertions(+), 63 deletions(-)

diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 685f7d4345b..1ddd3f4d4f0 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -21,34 +21,20 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#include <stdarg.h>
 #include <assert.h>
 
 #define NONAMELESSUNION
 #define NONAMELESSSTRUCT
 
-#include "ntstatus.h"
-#define WIN32_NO_STATUS
-#include "windef.h"
-#include "winsvc.h"
-#include "winternl.h"
+#include "ntoskrnl_private.h"
 #include "excpt.h"
-#include "winioctl.h"
-#include "winbase.h"
 #include "winreg.h"
 #include "ntsecapi.h"
 #include "ddk/csq.h"
-#include "ddk/ntddk.h"
-#include "ddk/ntifs.h"
-#include "ddk/wdm.h"
 #include "wine/server.h"
-#include "wine/debug.h"
 #include "wine/heap.h"
-#include "wine/rbtree.h"
 #include "wine/svcctl.h"
 
-#include "ntoskrnl_private.h"
-
 WINE_DEFAULT_DEBUG_CHANNEL(ntoskrnl);
 WINE_DECLARE_DEBUG_CHANNEL(relay);
 
@@ -90,14 +76,6 @@ static void *ldr_notify_cookie;
 static PLOAD_IMAGE_NOTIFY_ROUTINE load_image_notify_routines[8];
 static unsigned int load_image_notify_routine_count;
 
-struct wine_driver
-{
-    DRIVER_OBJECT driver_obj;
-    DRIVER_EXTENSION driver_extension;
-    SERVICE_STATUS_HANDLE service_handle;
-    struct wine_rb_entry entry;
-};
-
 static int wine_drivers_rb_compare( const void *key, const struct wine_rb_entry *entry )
 {
     const struct wine_driver *driver = WINE_RB_ENTRY_VALUE( entry, const struct wine_driver, entry );
@@ -110,6 +88,24 @@ static struct wine_rb_tree wine_drivers = { wine_drivers_rb_compare };
 
 DECLARE_CRITICAL_SECTION(drivers_cs);
 
+struct wine_driver *get_driver( const WCHAR *name )
+{
+    static const WCHAR driverW[] = L"\\Driver\\";
+    struct wine_rb_entry *entry;
+    UNICODE_STRING drv_name;
+
+    drv_name.Length = (wcslen( driverW ) + wcslen( name )) * sizeof(WCHAR);
+    if (!(drv_name.Buffer = malloc( drv_name.Length + sizeof(WCHAR) )))
+        return NULL;
+    wcscpy( drv_name.Buffer, driverW );
+    wcscat( drv_name.Buffer, name );
+    entry = wine_rb_get( &wine_drivers, &drv_name );
+    free( drv_name.Buffer );
+
+    if (entry) return WINE_RB_ENTRY_VALUE( entry, struct wine_driver, entry );
+    return NULL;
+}
+
 static HANDLE get_device_manager(void)
 {
     static HANDLE device_manager;
@@ -902,6 +898,7 @@ NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event )
     HANDLE manager = get_device_manager();
     struct dispatch_context context;
     NTSTATUS status = STATUS_SUCCESS;
+    struct wine_driver *driver;
     HANDLE handles[2];
 
     context.handle  = NULL;
@@ -983,9 +980,13 @@ NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event )
 
 done:
     /* Native PnP drivers expect that all of their devices will be removed when
-     * their unload routine is called, so we must stop the PnP manager first. */
-    pnp_manager_stop();
+     * their unload routine is called. Moreover, we cannot unload a module
+     * until we have removed devices for all lower drivers, so we have to stop
+     * all devices first, and then unload all drivers. */
+    WINE_RB_FOR_EACH_ENTRY( driver, &wine_drivers, struct wine_driver, entry )
+        pnp_manager_stop_driver( driver );
     wine_rb_destroy( &wine_drivers, unload_driver, NULL );
+    pnp_manager_stop();
     return status;
 }
 
@@ -1486,6 +1487,7 @@ NTSTATUS WINAPI IoCreateDriver( UNICODE_STRING *name, PDRIVER_INITIALIZE init )
     build_driver_keypath( driver->driver_obj.DriverName.Buffer, &driver->driver_extension.ServiceKeyName );
     for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
         driver->driver_obj.MajorFunction[i] = unhandled_irp;
+    list_init( &driver->root_pnp_devices );
 
     EnterCriticalSection( &drivers_cs );
     if (wine_rb_put( &wine_drivers, &driver->driver_obj.DriverName, &driver->entry ))
diff --git a/dlls/ntoskrnl.exe/ntoskrnl_private.h b/dlls/ntoskrnl.exe/ntoskrnl_private.h
index a1e1b892e8c..c0b588f3135 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl_private.h
+++ b/dlls/ntoskrnl.exe/ntoskrnl_private.h
@@ -21,7 +21,21 @@
 #ifndef __WINE_NTOSKRNL_PRIVATE_H
 #define __WINE_NTOSKRNL_PRIVATE_H
 
+#include <stdarg.h>
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winioctl.h"
+#include "winbase.h"
+#include "winsvc.h"
+#include "winternl.h"
+#include "ddk/ntifs.h"
+#include "ddk/wdm.h"
+
 #include "wine/asm.h"
+#include "wine/debug.h"
+#include "wine/list.h"
+#include "wine/rbtree.h"
 
 static inline LPCSTR debugstr_us( const UNICODE_STRING *us )
 {
@@ -76,12 +90,24 @@ extern POBJECT_TYPE SeTokenObjectType;
       0, 0, { (DWORD_PTR)(__FILE__ ": " # cs) }}; \
     static CRITICAL_SECTION cs = { &cs##_debug, -1, 0, 0, 0, 0 };
 
+struct wine_driver
+{
+    DRIVER_OBJECT driver_obj;
+    DRIVER_EXTENSION driver_extension;
+    SERVICE_STATUS_HANDLE service_handle;
+    struct wine_rb_entry entry;
+    struct list root_pnp_devices;
+};
+
 void ObReferenceObject( void *obj ) DECLSPEC_HIDDEN;
 
 void pnp_manager_enumerate_root_devices( const WCHAR *driver_name ) DECLSPEC_HIDDEN;
 void pnp_manager_start(void) DECLSPEC_HIDDEN;
+void pnp_manager_stop_driver( struct wine_driver *driver ) DECLSPEC_HIDDEN;
 void pnp_manager_stop(void) DECLSPEC_HIDDEN;
 
+struct wine_driver *get_driver( const WCHAR *name ) DECLSPEC_HIDDEN;
+
 static const WCHAR servicesW[] = {'\\','R','e','g','i','s','t','r','y',
                                   '\\','M','a','c','h','i','n','e',
                                   '\\','S','y','s','t','e','m',
diff --git a/dlls/ntoskrnl.exe/pnp.c b/dlls/ntoskrnl.exe/pnp.c
index 913a63e8f0d..dce6bb90c68 100644
--- a/dlls/ntoskrnl.exe/pnp.c
+++ b/dlls/ntoskrnl.exe/pnp.c
@@ -20,31 +20,17 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#include <stdarg.h>
-
 #define NONAMELESSUNION
 
-#include "ntstatus.h"
-#define WIN32_NO_STATUS
-#include "windef.h"
-#include "winbase.h"
-#include "winioctl.h"
+#include "ntoskrnl_private.h"
 #include "winreg.h"
 #include "winuser.h"
-#include "winsvc.h"
-#include "winternl.h"
 #include "setupapi.h"
 #include "cfgmgr32.h"
 #include "dbt.h"
-#include "ddk/wdm.h"
-#include "ddk/ntifs.h"
-#include "wine/debug.h"
 #include "wine/exception.h"
 #include "wine/heap.h"
-#include "wine/rbtree.h"
-#include "wine/list.h"
 
-#include "ntoskrnl_private.h"
 #include "plugplay.h"
 
 #include "initguid.h"
@@ -928,13 +914,11 @@ struct root_pnp_device
     DEVICE_OBJECT *device;
 };
 
-static struct list root_pnp_devices = LIST_INIT(root_pnp_devices);
-
-static struct root_pnp_device *find_root_pnp_device( const WCHAR *id )
+static struct root_pnp_device *find_root_pnp_device( struct wine_driver *driver, const WCHAR *id )
 {
     struct root_pnp_device *device;
 
-    LIST_FOR_EACH_ENTRY( device, &root_pnp_devices, struct root_pnp_device, entry )
+    LIST_FOR_EACH_ENTRY( device, &driver->root_pnp_devices, struct root_pnp_device, entry )
     {
         if (!wcsicmp( id, device->id ))
             return device;
@@ -1049,12 +1033,16 @@ void pnp_manager_start(void)
         ERR("RpcBindingFromStringBinding() failed, error %#x\n", err);
 }
 
-void pnp_manager_stop(void)
+void pnp_manager_stop_driver( struct wine_driver *driver )
 {
     struct root_pnp_device *device, *next;
 
-    LIST_FOR_EACH_ENTRY_SAFE( device, next, &root_pnp_devices, struct root_pnp_device, entry )
+    LIST_FOR_EACH_ENTRY_SAFE( device, next, &driver->root_pnp_devices, struct root_pnp_device, entry )
         remove_device( device->device );
+}
+
+void pnp_manager_stop(void)
+{
     IoDeleteDriver( pnp_manager );
     RpcBindingFree( &plugplay_binding_handle );
 }
@@ -1066,6 +1054,7 @@ void pnp_manager_enumerate_root_devices( const WCHAR *driver_name )
     WCHAR buffer[MAX_SERVICE_NAME + ARRAY_SIZE(driverW)], id[MAX_DEVICE_ID_LEN];
     SP_DEVINFO_DATA sp_device = {sizeof(sp_device)};
     struct root_pnp_device *pnp_device;
+    struct wine_driver *driver;
     DEVICE_OBJECT *device;
     NTSTATUS status;
     unsigned int i;
@@ -1073,6 +1062,8 @@ void pnp_manager_enumerate_root_devices( const WCHAR *driver_name )
 
     TRACE("Searching for new root-enumerated devices for driver %s.\n", debugstr_w(driver_name));
 
+    driver = get_driver( driver_name );
+
     set = SetupDiGetClassDevsW( NULL, rootW, NULL, DIGCF_ALLCLASSES );
     if (set == INVALID_HANDLE_VALUE)
     {
@@ -1091,7 +1082,7 @@ void pnp_manager_enumerate_root_devices( const WCHAR *driver_name )
 
         SetupDiGetDeviceInstanceIdW( set, &sp_device, id, ARRAY_SIZE(id), NULL );
 
-        if (find_root_pnp_device( id ))
+        if (find_root_pnp_device( driver, id ))
             continue;
 
         TRACE("Adding new root-enumerated device %s.\n", debugstr_w(id));
@@ -1106,7 +1097,7 @@ void pnp_manager_enumerate_root_devices( const WCHAR *driver_name )
         pnp_device = device->DeviceExtension;
         wcscpy( pnp_device->id, id );
         pnp_device->device = device;
-        list_add_tail( &root_pnp_devices, &pnp_device->entry );
+        list_add_tail( &driver->root_pnp_devices, &pnp_device->entry );
 
         start_device( device, set, &sp_device );
     }
diff --git a/dlls/ntoskrnl.exe/sync.c b/dlls/ntoskrnl.exe/sync.c
index 2aa60a0f2a0..445c8d890ab 100644
--- a/dlls/ntoskrnl.exe/sync.c
+++ b/dlls/ntoskrnl.exe/sync.c
@@ -19,23 +19,12 @@
  */
 
 #include <limits.h>
-#include <stdarg.h>
-
-#include "ntstatus.h"
-#define WIN32_NO_STATUS
-#include "windef.h"
-#include "winbase.h"
-#include "winternl.h"
-#include "ddk/ntddk.h"
-#include "ddk/wdm.h"
-#include "ddk/ntifs.h"
-
-#include "wine/asm.h"
-#include "wine/debug.h"
-#include "wine/heap.h"
-#include "wine/server.h"
 
 #include "ntoskrnl_private.h"
+#include "ddk/ntddk.h"
+
+#include "wine/heap.h"
+#include "wine/server.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(ntoskrnl);
 
-- 
2.30.2




More information about the wine-devel mailing list