https://git.reactos.org/?p=reactos.git;a=commitdiff;h=582ca686965e51629df88…
commit 582ca686965e51629df88cdb340a2480060cd638
Author: Victor Perevertkin <victor.perevertkin(a)reactos.org>
AuthorDate: Sun Nov 29 16:41:58 2020 +0300
Commit: Victor Perevertkin <victor.perevertkin(a)reactos.org>
CommitDate: Sat Dec 5 22:25:40 2020 +0300
[NTOS:PNP] Improve and refactor PnP notifications
- BUGFIX: do not call IoGetRelatedTargetDevice while guarded mutex is acquired
(the function issues an APC, but they are disabled inside a critical section)
- BUGFIX: only the beginning of a structure for GUID_PNP_CUSTOM_NOTIFICATION was
copied and queued.
Just pass it as-is to a subscriber, without copying
- Don't convert event GUID to string, store and compare GUID struct itself
- Split IopNotifyPlugPlayNotification into 3 functions for each type of notification
(less stack usage and for future changes)
- Move initialization code for notifications into a separate routine
- Use separate lists and locks for every type of notification
- Put "TargetDeviceChange" notifications into their place inside
DEVICE_NODE
---
ntoskrnl/include/internal/io.h | 43 ++-
ntoskrnl/io/iomgr/deviface.c | 8 +-
ntoskrnl/io/iomgr/iomgr.c | 7 +-
ntoskrnl/io/pnpmgr/devaction.c | 18 +-
ntoskrnl/io/pnpmgr/devnode.c | 3 +
ntoskrnl/io/pnpmgr/pnpnotify.c | 660 ++++++++++++++++++++++++-----------------
ntoskrnl/io/pnpmgr/pnpreport.c | 6 +-
7 files changed, 435 insertions(+), 310 deletions(-)
diff --git a/ntoskrnl/include/internal/io.h b/ntoskrnl/include/internal/io.h
index d0e0bb5e94e..628929f1cff 100644
--- a/ntoskrnl/include/internal/io.h
+++ b/ntoskrnl/include/internal/io.h
@@ -609,20 +609,6 @@ IopInitDriverImplementation(
VOID
);
-VOID
-IopInitPnpNotificationImplementation(
- VOID
-);
-
-VOID
-IopNotifyPlugPlayNotification(
- IN PDEVICE_OBJECT DeviceObject,
- IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory,
- IN LPCGUID Event,
- IN PVOID EventCategoryData1,
- IN PVOID EventCategoryData2
-);
-
NTSTATUS
IopGetSystemPowerDeviceObject(
IN PDEVICE_OBJECT *DeviceObject
@@ -828,6 +814,10 @@ IoInitializeCrashDump(
IN HANDLE PageFileHandle
);
+VOID
+PiInitializeNotifications(
+ VOID);
+
//
// Device/Volume Routines
//
@@ -926,6 +916,12 @@ IopDereferenceDeviceObject(
IN BOOLEAN ForceUnload
);
+NTSTATUS
+NTAPI
+IopGetRelatedTargetDevice(
+ IN PFILE_OBJECT FileObject,
+ OUT PDEVICE_NODE *DeviceNode);
+
NTSTATUS
NTAPI
IoGetRelatedTargetDevice(
@@ -1412,6 +1408,25 @@ PiPerformSyncDeviceAction(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ DEVICE_ACTION Action);
+//
+// PnP notifications
+//
+VOID
+PiNotifyDeviceInterfaceChange(
+ _In_ LPCGUID Event,
+ _In_ LPCGUID InterfaceClassGuid,
+ _In_ PUNICODE_STRING SymbolicLinkName);
+
+VOID
+PiNotifyHardwareProfileChange(
+ _In_ LPCGUID Event);
+
+VOID
+PiNotifyTargetDeviceChange(
+ _In_ LPCGUID Event,
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_opt_ PTARGET_DEVICE_CUSTOM_NOTIFICATION CustomNotification);
+
//
// Global I/O Data
//
diff --git a/ntoskrnl/io/iomgr/deviface.c b/ntoskrnl/io/iomgr/deviface.c
index 34245027627..f909d536461 100644
--- a/ntoskrnl/io/iomgr/deviface.c
+++ b/ntoskrnl/io/iomgr/deviface.c
@@ -1463,12 +1463,8 @@ IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName,
ExFreePoolWithTag(DeviceInstance.Buffer, TAG_IO);
EventGuid = Enable ? &GUID_DEVICE_INTERFACE_ARRIVAL :
&GUID_DEVICE_INTERFACE_REMOVAL;
- IopNotifyPlugPlayNotification(
- PhysicalDeviceObject,
- EventCategoryDeviceInterfaceChange,
- EventGuid,
- &DeviceGuid,
- (PVOID)SymbolicLinkName);
+
+ PiNotifyDeviceInterfaceChange(EventGuid, &DeviceGuid, SymbolicLinkName);
ObDereferenceObject(PhysicalDeviceObject);
DPRINT("Status %x\n", Status);
diff --git a/ntoskrnl/io/iomgr/iomgr.c b/ntoskrnl/io/iomgr/iomgr.c
index 0173cf4911d..d7dc1bcb8c4 100644
--- a/ntoskrnl/io/iomgr/iomgr.c
+++ b/ntoskrnl/io/iomgr/iomgr.c
@@ -59,14 +59,12 @@ extern POBJECT_TYPE IoAdapterObjectType;
extern ERESOURCE IopDatabaseResource;
ERESOURCE IopSecurityResource;
extern ERESOURCE IopDriverLoadResource;
-extern KGUARDED_MUTEX PnpNotifyListLock;
extern LIST_ENTRY IopDiskFileSystemQueueHead;
extern LIST_ENTRY IopCdRomFileSystemQueueHead;
extern LIST_ENTRY IopTapeFileSystemQueueHead;
extern LIST_ENTRY IopNetworkFileSystemQueueHead;
extern LIST_ENTRY DriverBootReinitListHead;
extern LIST_ENTRY DriverReinitListHead;
-extern LIST_ENTRY PnpNotifyListHead;
extern LIST_ENTRY IopFsNotifyChangeQueueHead;
extern LIST_ENTRY IopErrorLogListHead;
extern LIST_ENTRY IopTimerQueueHead;
@@ -480,14 +478,12 @@ IoInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
ExInitializeResourceLite(&IopDatabaseResource);
ExInitializeResourceLite(&IopSecurityResource);
ExInitializeResourceLite(&IopDriverLoadResource);
- KeInitializeGuardedMutex(&PnpNotifyListLock);
InitializeListHead(&IopDiskFileSystemQueueHead);
InitializeListHead(&IopCdRomFileSystemQueueHead);
InitializeListHead(&IopTapeFileSystemQueueHead);
InitializeListHead(&IopNetworkFileSystemQueueHead);
InitializeListHead(&DriverBootReinitListHead);
InitializeListHead(&DriverReinitListHead);
- InitializeListHead(&PnpNotifyListHead);
InitializeListHead(&ShutdownListHead);
InitializeListHead(&LastChanceShutdownListHead);
InitializeListHead(&IopFsNotifyChangeQueueHead);
@@ -498,6 +494,9 @@ IoInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
KeInitializeSpinLock(&ShutdownListLock);
KeInitializeSpinLock(&IopLogListLock);
+ /* Initialize PnP notifications */
+ PiInitializeNotifications();
+
/* Initialize the reserve IRP */
if (!IopInitializeReserveIrp(&IopReserveIrpAllocator))
{
diff --git a/ntoskrnl/io/pnpmgr/devaction.c b/ntoskrnl/io/pnpmgr/devaction.c
index e6479074f32..4f5fb6b3884 100644
--- a/ntoskrnl/io/pnpmgr/devaction.c
+++ b/ntoskrnl/io/pnpmgr/devaction.c
@@ -1513,11 +1513,7 @@ IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
/* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */
IopSynchronousCall(DeviceObject, &Stack, &Dummy);
- IopNotifyPlugPlayNotification(DeviceObject,
- EventCategoryTargetDeviceChange,
- &GUID_TARGET_DEVICE_REMOVE_COMPLETE,
- NULL,
- NULL);
+ PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_REMOVE_COMPLETE, DeviceObject,
NULL);
ObDereferenceObject(DeviceObject);
}
@@ -1592,11 +1588,7 @@ IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
/* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */
IopSynchronousCall(DeviceObject, &Stack, &Dummy);
- IopNotifyPlugPlayNotification(DeviceObject,
- EventCategoryTargetDeviceChange,
- &GUID_TARGET_DEVICE_REMOVE_CANCELLED,
- NULL,
- NULL);
+ PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_REMOVE_CANCELLED, DeviceObject,
NULL);
}
static
@@ -1692,11 +1684,7 @@ IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy);
- IopNotifyPlugPlayNotification(DeviceObject,
- EventCategoryTargetDeviceChange,
- &GUID_TARGET_DEVICE_QUERY_REMOVE,
- NULL,
- NULL);
+ PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_QUERY_REMOVE, DeviceObject,
NULL);
if (!NT_SUCCESS(Status))
{
diff --git a/ntoskrnl/io/pnpmgr/devnode.c b/ntoskrnl/io/pnpmgr/devnode.c
index a068cd71ddb..230fcce100b 100644
--- a/ntoskrnl/io/pnpmgr/devnode.c
+++ b/ntoskrnl/io/pnpmgr/devnode.c
@@ -114,6 +114,7 @@ IopCreateDeviceNode(
}
RtlZeroMemory(Node, sizeof(DEVICE_NODE));
+ InitializeListHead(&Node->TargetDeviceNotify);
if (!ServiceName)
ServiceName1 = &UnknownDeviceName;
@@ -259,6 +260,8 @@ IopFreeDeviceNode(
/* All children must be deleted before a parent is deleted */
ASSERT(!DeviceNode->Child);
ASSERT(DeviceNode->PhysicalDeviceObject);
+ /* No notifications should be registered for this device */
+ ASSERT(IsListEmpty(&DeviceNode->TargetDeviceNotify));
KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
diff --git a/ntoskrnl/io/pnpmgr/pnpnotify.c b/ntoskrnl/io/pnpmgr/pnpnotify.c
index 089215071fd..cc169aba171 100644
--- a/ntoskrnl/io/pnpmgr/pnpnotify.c
+++ b/ntoskrnl/io/pnpmgr/pnpnotify.c
@@ -1,11 +1,11 @@
/*
- * PROJECT: ReactOS Kernel
- * COPYRIGHT: GPL - See COPYING in the top level directory
- * FILE: ntoskrnl/io/pnpmgr/pnpnotify.c
- * PURPOSE: Plug & Play notification functions
- * PROGRAMMERS: Filip Navara (xnavara(a)volny.cz)
- * Herv� Poussineau (hpoussin(a)reactos.org)
- * Pierre Schweitzer
+ * PROJECT: ReactOS Kernel
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Plug & Play notification functions
+ * COPYRIGHT: Copyright 2003 Filip Navara <xnavara(a)volny.cz>
+ * Copyright 2005-2006 Hervé Poussineau <hpoussin(a)reactos.org>
+ * Copyright 2010 Pierre Schweitzer <pierre(a)reactos.org>
+ * Copyright 2020 Victor Perevertkin <victor.perevertkin(a)reactos.org>
*/
/* INCLUDES ******************************************************************/
@@ -14,215 +14,309 @@
#define NDEBUG
#include <debug.h>
-/* TYPES *******************************************************************/
+/* DATA **********************************************************************/
+
+KGUARDED_MUTEX PiNotifyTargetDeviceLock;
+KGUARDED_MUTEX PiNotifyHwProfileLock;
+KGUARDED_MUTEX PiNotifyDeviceInterfaceLock;
+
+_Guarded_by_(PiNotifyHwProfileLock)
+LIST_ENTRY PiNotifyHwProfileListHead;
+
+_Guarded_by_(PiNotifyDeviceInterfaceLock)
+LIST_ENTRY PiNotifyDeviceInterfaceListHead;
+
+/* TYPES *********************************************************************/
typedef struct _PNP_NOTIFY_ENTRY
{
LIST_ENTRY PnpNotifyList;
- IO_NOTIFICATION_EVENT_CATEGORY EventCategory;
PVOID Context;
- UNICODE_STRING Guid;
- PFILE_OBJECT FileObject;
PDRIVER_OBJECT DriverObject;
PDRIVER_NOTIFICATION_CALLBACK_ROUTINE PnpNotificationProc;
+ union
+ {
+ GUID Guid; // for EventCategoryDeviceInterfaceChange
+ struct
+ {
+ PFILE_OBJECT FileObject; // for EventCategoryTargetDeviceChange
+ PDEVICE_OBJECT DeviceObject;
+ };
+ };
+ IO_NOTIFICATION_EVENT_CATEGORY EventCategory;
+ UINT8 RefCount;
+ BOOLEAN Deleted;
} PNP_NOTIFY_ENTRY, *PPNP_NOTIFY_ENTRY;
-KGUARDED_MUTEX PnpNotifyListLock;
-LIST_ENTRY PnpNotifyListHead;
-
/* FUNCTIONS *****************************************************************/
+CODE_SEG("INIT")
VOID
-IopNotifyPlugPlayNotification(
- IN PDEVICE_OBJECT DeviceObject,
- IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory,
- IN LPCGUID Event,
- IN PVOID EventCategoryData1,
- IN PVOID EventCategoryData2)
+PiInitializeNotifications(VOID)
{
- PPNP_NOTIFY_ENTRY ChangeEntry;
- PLIST_ENTRY ListEntry;
- PVOID NotificationStructure;
- BOOLEAN CallCurrentEntry;
- UNICODE_STRING GuidString;
- NTSTATUS Status;
- PDEVICE_OBJECT EntryDeviceObject = NULL;
+ KeInitializeGuardedMutex(&PiNotifyTargetDeviceLock);
+ KeInitializeGuardedMutex(&PiNotifyHwProfileLock);
+ KeInitializeGuardedMutex(&PiNotifyDeviceInterfaceLock);
+ InitializeListHead(&PiNotifyHwProfileListHead);
+ InitializeListHead(&PiNotifyDeviceInterfaceListHead);
+}
- ASSERT(DeviceObject);
+static
+CODE_SEG("PAGE")
+VOID
+PiDereferencePnpNotifyEntry(
+ _In_ PPNP_NOTIFY_ENTRY Entry)
+{
+ PAGED_CODE();
+ ASSERT(Entry->RefCount > 0);
- KeAcquireGuardedMutex(&PnpNotifyListLock);
- if (IsListEmpty(&PnpNotifyListHead))
+ ObDereferenceObject(Entry->DriverObject);
+ Entry->RefCount--;
+ if (Entry->RefCount == 0)
{
- KeReleaseGuardedMutex(&PnpNotifyListLock);
- return;
- }
+ ASSERT(Entry->Deleted);
- switch (EventCategory)
- {
- case EventCategoryDeviceInterfaceChange:
- {
- PDEVICE_INTERFACE_CHANGE_NOTIFICATION NotificationInfos;
- NotificationStructure = NotificationInfos = ExAllocatePoolWithTag(
- PagedPool,
- sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION),
- TAG_PNP_NOTIFY);
- if (!NotificationInfos)
- {
- KeReleaseGuardedMutex(&PnpNotifyListLock);
- return;
- }
- NotificationInfos->Version = 1;
- NotificationInfos->Size = sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION);
- RtlCopyMemory(&NotificationInfos->Event, Event, sizeof(GUID));
- RtlCopyMemory(&NotificationInfos->InterfaceClassGuid,
EventCategoryData1, sizeof(GUID));
- NotificationInfos->SymbolicLinkName =
(PUNICODE_STRING)EventCategoryData2;
- Status = RtlStringFromGUID(&NotificationInfos->InterfaceClassGuid,
&GuidString);
- if (!NT_SUCCESS(Status))
- {
- KeReleaseGuardedMutex(&PnpNotifyListLock);
- ExFreePoolWithTag(NotificationStructure, TAG_PNP_NOTIFY);
- return;
- }
- break;
- }
- case EventCategoryHardwareProfileChange:
- {
- PHWPROFILE_CHANGE_NOTIFICATION NotificationInfos;
- NotificationStructure = NotificationInfos = ExAllocatePoolWithTag(
- PagedPool,
- sizeof(HWPROFILE_CHANGE_NOTIFICATION),
- TAG_PNP_NOTIFY);
- if (!NotificationInfos)
- {
- KeReleaseGuardedMutex(&PnpNotifyListLock);
- return;
- }
- NotificationInfos->Version = 1;
- NotificationInfos->Size = sizeof(HWPROFILE_CHANGE_NOTIFICATION);
- RtlCopyMemory(&NotificationInfos->Event, Event, sizeof(GUID));
- break;
- }
- case EventCategoryTargetDeviceChange:
- {
- if (Event != &GUID_PNP_CUSTOM_NOTIFICATION)
- {
- PTARGET_DEVICE_REMOVAL_NOTIFICATION NotificationInfos;
- NotificationStructure = NotificationInfos = ExAllocatePoolWithTag(
- PagedPool,
- sizeof(TARGET_DEVICE_REMOVAL_NOTIFICATION),
- TAG_PNP_NOTIFY);
- if (!NotificationInfos)
- {
- KeReleaseGuardedMutex(&PnpNotifyListLock);
- return;
- }
- NotificationInfos->Version = 1;
- NotificationInfos->Size = sizeof(TARGET_DEVICE_REMOVAL_NOTIFICATION);
- RtlCopyMemory(&NotificationInfos->Event, Event, sizeof(GUID));
- }
- else
- {
- PTARGET_DEVICE_CUSTOM_NOTIFICATION NotificationInfos;
- NotificationStructure = NotificationInfos = ExAllocatePoolWithTag(
- PagedPool,
- sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION),
- TAG_PNP_NOTIFY);
- if (!NotificationInfos)
- {
- KeReleaseGuardedMutex(&PnpNotifyListLock);
- return;
- }
- RtlCopyMemory(NotificationInfos, EventCategoryData1,
sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION));
- }
- break;
- }
- default:
+ RemoveEntryList(&Entry->PnpNotifyList);
+ if (Entry->EventCategory == EventCategoryTargetDeviceChange)
{
- DPRINT1("IopNotifyPlugPlayNotification(): unknown EventCategory 0x%x
UNIMPLEMENTED\n", EventCategory);
- KeReleaseGuardedMutex(&PnpNotifyListLock);
- return;
+ // IopGetRelatedTargetDevice referenced the device upon the notification
registration
+ ObDereferenceObject(Entry->DeviceObject);
}
+ ExFreePoolWithTag(Entry, TAG_PNP_NOTIFY);
}
+}
+
+static
+CODE_SEG("PAGE")
+VOID
+PiReferencePnpNotifyEntry(
+ _In_ PPNP_NOTIFY_ENTRY Entry)
+{
+ PAGED_CODE();
+ ObReferenceObject(Entry->DriverObject);
+ Entry->RefCount++;
+}
+
+/**
+ * @brief Calls PnP notification routine and makes some checks to detect faulty drivers
+ */
+static
+CODE_SEG("PAGE")
+VOID
+PiCallNotifyProc(
+ _In_ PDRIVER_NOTIFICATION_CALLBACK_ROUTINE Proc,
+ _In_ PVOID NotificationStructure,
+ _In_ PVOID Context)
+{
+ PAGED_CODE();
+#if DBG
+ KIRQL oldIrql = KeGetCurrentIrql();
+ ULONG oldApcDisable = KeGetCurrentThread()->CombinedApcDisable;
+#endif
+
+ Proc(NotificationStructure, Context);
+
+ ASSERT(oldIrql == KeGetCurrentIrql() &&
+ oldApcDisable == KeGetCurrentThread()->CombinedApcDisable);
+}
+
+static
+CODE_SEG("PAGE")
+_Requires_lock_held_(Lock)
+VOID
+PiProcessSingleNotification(
+ _In_ PPNP_NOTIFY_ENTRY Entry,
+ _In_ PVOID NotificationStructure,
+ _In_ PKGUARDED_MUTEX Lock,
+ _Out_ PLIST_ENTRY *NextEntry)
+{
+ PAGED_CODE();
+
+ // the notification may be unregistered inside the procedure
+ // thus reference the entry so we may proceed
+ PiReferencePnpNotifyEntry(Entry);
+
+ // release the lock because the notification routine has to be called without any
+ // limitations regarding APCs
+ KeReleaseGuardedMutex(Lock);
+ PiCallNotifyProc(Entry->PnpNotificationProc, NotificationStructure,
Entry->Context);
+ KeAcquireGuardedMutex(Lock);
+
+ // take the next entry link only after the callback finishes
+ // the lock is not held there, so Entry may have changed at this point
+ *NextEntry = Entry->PnpNotifyList.Flink;
+ PiDereferencePnpNotifyEntry(Entry);
+}
+
+/**
+ * @brief Delivers the event to all drivers subscribed to
+ * EventCategoryDeviceInterfaceChange
+ *
+ * @param[in] Event The PnP event GUID
+ * @param[in] InterfaceClassGuid The GUID of an interface class
+ * @param[in] SymbolicLinkName Pointer to a string identifying the device interface
name
+ */
+CODE_SEG("PAGE")
+VOID
+PiNotifyDeviceInterfaceChange(
+ _In_ LPCGUID Event,
+ _In_ LPCGUID InterfaceClassGuid,
+ _In_ PUNICODE_STRING SymbolicLinkName)
+{
+ PAGED_CODE();
+
+ PDEVICE_INTERFACE_CHANGE_NOTIFICATION notifyStruct;
+ notifyStruct = ExAllocatePoolWithTag(PagedPool, sizeof(*notifyStruct),
TAG_PNP_NOTIFY);
+ if (!notifyStruct)
+ {
+ return;
+ }
+
+ *notifyStruct = (DEVICE_INTERFACE_CHANGE_NOTIFICATION) {
+ .Version = 1,
+ .Size = sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION),
+ .Event = *Event,
+ .InterfaceClassGuid = *InterfaceClassGuid,
+ .SymbolicLinkName = SymbolicLinkName
+ };
+
+ DPRINT("Delivering a DeviceInterfaceChange PnP event\n");
- /* Loop through procedures registred in PnpNotifyListHead
- * list to find those that meet some criteria.
- */
- ListEntry = PnpNotifyListHead.Flink;
- while (ListEntry != &PnpNotifyListHead)
+ KeAcquireGuardedMutex(&PiNotifyDeviceInterfaceLock);
+
+ PLIST_ENTRY entry = PiNotifyDeviceInterfaceListHead.Flink;
+ while (entry != &PiNotifyDeviceInterfaceListHead)
{
- ChangeEntry = CONTAINING_RECORD(ListEntry, PNP_NOTIFY_ENTRY, PnpNotifyList);
- CallCurrentEntry = FALSE;
+ PPNP_NOTIFY_ENTRY nEntry = CONTAINING_RECORD(entry, PNP_NOTIFY_ENTRY,
PnpNotifyList);
- if (ChangeEntry->EventCategory != EventCategory)
+ if (!IsEqualGUID(¬ifyStruct->InterfaceClassGuid,
&nEntry->Guid))
{
- ListEntry = ListEntry->Flink;
+ entry = entry->Flink;
continue;
}
- switch (EventCategory)
- {
- case EventCategoryDeviceInterfaceChange:
- {
- if (RtlCompareUnicodeString(&ChangeEntry->Guid, &GuidString,
FALSE) == 0)
- {
- CallCurrentEntry = TRUE;
- }
- break;
- }
- case EventCategoryHardwareProfileChange:
- {
- CallCurrentEntry = TRUE;
- break;
- }
- case EventCategoryTargetDeviceChange:
- {
- Status = IoGetRelatedTargetDevice(ChangeEntry->FileObject,
&EntryDeviceObject);
- if (NT_SUCCESS(Status))
- {
- if (DeviceObject == EntryDeviceObject)
- {
- if (Event == &GUID_PNP_CUSTOM_NOTIFICATION)
- {
-
((PTARGET_DEVICE_CUSTOM_NOTIFICATION)NotificationStructure)->FileObject =
ChangeEntry->FileObject;
- }
- else
- {
-
((PTARGET_DEVICE_REMOVAL_NOTIFICATION)NotificationStructure)->FileObject =
ChangeEntry->FileObject;
- }
- CallCurrentEntry = TRUE;
- }
- }
- break;
- }
- default:
- {
- DPRINT1("IopNotifyPlugPlayNotification(): unknown EventCategory 0x%x
UNIMPLEMENTED\n", EventCategory);
- break;
- }
- }
+ PiProcessSingleNotification(nEntry, notifyStruct,
&PiNotifyDeviceInterfaceLock, &entry);
+ }
+
+ KeReleaseGuardedMutex(&PiNotifyDeviceInterfaceLock);
+ ExFreePoolWithTag(notifyStruct, TAG_PNP_NOTIFY);
+}
+
+
+/**
+ * @brief Delivers the event to all drivers subscribed to
+ * EventCategoryHardwareProfileChange PnP event
+ *
+ * @param[in] Event The PnP event GUID
+ */
+CODE_SEG("PAGE")
+VOID
+PiNotifyHardwareProfileChange(
+ _In_ LPCGUID Event)
+{
+ PAGED_CODE();
+
+ PHWPROFILE_CHANGE_NOTIFICATION notifyStruct;
+ notifyStruct = ExAllocatePoolWithTag(PagedPool, sizeof(*notifyStruct),
TAG_PNP_NOTIFY);
+ if (!notifyStruct)
+ {
+ return;
+ }
+
+ *notifyStruct = (HWPROFILE_CHANGE_NOTIFICATION) {
+ .Version = 1,
+ .Size = sizeof(HWPROFILE_CHANGE_NOTIFICATION),
+ .Event = *Event
+ };
+
+ DPRINT("Delivering a HardwareProfileChange PnP event\n");
+
+ KeAcquireGuardedMutex(&PiNotifyHwProfileLock);
+
+ PLIST_ENTRY entry = PiNotifyHwProfileListHead.Flink;
+ while (entry != &PiNotifyHwProfileListHead)
+ {
+ PPNP_NOTIFY_ENTRY nEntry = CONTAINING_RECORD(entry, PNP_NOTIFY_ENTRY,
PnpNotifyList);
+
+ PiProcessSingleNotification(nEntry, notifyStruct, &PiNotifyHwProfileLock,
&entry);
+ }
+
+ KeReleaseGuardedMutex(&PiNotifyHwProfileLock);
+ ExFreePoolWithTag(notifyStruct, TAG_PNP_NOTIFY);
+}
+
+/**
+ * @brief Delivers the event to all drivers subscribed to
+ * EventCategoryTargetDeviceChange PnP event
+ *
+ * @param[in] Event The PnP event GUID
+ * @param[in] DeviceObject The (target) device object
+ * @param[in] CustomNotification Pointer to a custom notification for
GUID_PNP_CUSTOM_NOTIFICATION
+ */
+CODE_SEG("PAGE")
+VOID
+PiNotifyTargetDeviceChange(
+ _In_ LPCGUID Event,
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_opt_ PTARGET_DEVICE_CUSTOM_NOTIFICATION CustomNotification)
+{
+ PAGED_CODE();
- /* Move to the next element now, as callback may unregister itself */
- ListEntry = ListEntry->Flink;
- /* FIXME: If ListEntry was the last element and that callback registers
- * new notifications, those won't be checked... */
+ PVOID notificationStruct;
+ // just in case our device is removed during the operation
+ ObReferenceObject(DeviceObject);
- if (CallCurrentEntry)
+ PDEVICE_NODE deviceNode = IopGetDeviceNode(DeviceObject);
+ ASSERT(deviceNode);
+
+ if (!IsEqualGUID(Event, &GUID_PNP_CUSTOM_NOTIFICATION))
+ {
+ PTARGET_DEVICE_REMOVAL_NOTIFICATION notifStruct;
+ notifStruct = ExAllocatePoolWithTag(PagedPool, sizeof(*notifStruct),
TAG_PNP_NOTIFY);
+ if (!notifStruct)
{
- /* Call entry into new allocated memory */
- DPRINT("IopNotifyPlugPlayNotification(): found suitable callback
%p\n",
- ChangeEntry);
-
- KeReleaseGuardedMutex(&PnpNotifyListLock);
- (ChangeEntry->PnpNotificationProc)(NotificationStructure,
- ChangeEntry->Context);
- KeAcquireGuardedMutex(&PnpNotifyListLock);
+ return;
}
+ *notifStruct = (TARGET_DEVICE_REMOVAL_NOTIFICATION) {
+ .Version = 1,
+ .Size = sizeof(TARGET_DEVICE_REMOVAL_NOTIFICATION),
+ .Event = *Event
+ };
+
+ notificationStruct = notifStruct;
+
+ DPRINT("Delivering a (non-custom) TargetDeviceChange PnP event\n");
+ }
+ else
+ {
+ ASSERT(CustomNotification);
+ // assuming everythng else is correct
+
+ notificationStruct = CustomNotification;
+
+ DPRINT("Delivering a (custom) TargetDeviceChange PnP event\n");
+ }
+
+ KeAcquireGuardedMutex(&PiNotifyTargetDeviceLock);
+
+ PLIST_ENTRY entry = deviceNode->TargetDeviceNotify.Flink;
+ while (entry != &deviceNode->TargetDeviceNotify)
+ {
+ PPNP_NOTIFY_ENTRY nEntry = CONTAINING_RECORD(entry, PNP_NOTIFY_ENTRY,
PnpNotifyList);
+
+ // put the file object from our saved entry to this particular notification's
struct
+ ((PTARGET_DEVICE_REMOVAL_NOTIFICATION)notificationStruct)->FileObject =
nEntry->FileObject;
+ // so you don't need to look at the definition ;)
+ C_ASSERT(FIELD_OFFSET(TARGET_DEVICE_REMOVAL_NOTIFICATION, FileObject)
+ == FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, FileObject));
+
+ PiProcessSingleNotification(nEntry, notificationStruct,
&PiNotifyTargetDeviceLock, &entry);
}
- KeReleaseGuardedMutex(&PnpNotifyListLock);
- ExFreePoolWithTag(NotificationStructure, TAG_PNP_NOTIFY);
- if (EventCategory == EventCategoryDeviceInterfaceChange)
- RtlFreeUnicodeString(&GuidString);
+
+ KeReleaseGuardedMutex(&PiNotifyTargetDeviceLock);
+ ExFreePoolWithTag(notificationStruct, TAG_PNP_NOTIFY);
+ ObDereferenceObject(DeviceObject);
}
/* PUBLIC FUNCTIONS **********************************************************/
@@ -232,10 +326,11 @@ IopNotifyPlugPlayNotification(
*/
ULONG
NTAPI
-IoPnPDeliverServicePowerNotification(ULONG VetoedPowerOperation OPTIONAL,
- ULONG PowerNotification,
- ULONG Unknown OPTIONAL,
- BOOLEAN Synchronous)
+IoPnPDeliverServicePowerNotification(
+ _In_ ULONG VetoedPowerOperation,
+ _In_ ULONG PowerNotificationCode,
+ _In_ ULONG PowerNotificationData,
+ _In_ BOOLEAN Synchronous)
{
UNIMPLEMENTED;
return 0;
@@ -244,15 +339,17 @@ IoPnPDeliverServicePowerNotification(ULONG VetoedPowerOperation
OPTIONAL,
/*
* @implemented
*/
+CODE_SEG("PAGE")
NTSTATUS
NTAPI
-IoRegisterPlugPlayNotification(IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory,
- IN ULONG EventCategoryFlags,
- IN PVOID EventCategoryData OPTIONAL,
- IN PDRIVER_OBJECT DriverObject,
- IN PDRIVER_NOTIFICATION_CALLBACK_ROUTINE CallbackRoutine,
- IN PVOID Context,
- OUT PVOID *NotificationEntry)
+IoRegisterPlugPlayNotification(
+ _In_ IO_NOTIFICATION_EVENT_CATEGORY EventCategory,
+ _In_ ULONG EventCategoryFlags,
+ _In_opt_ PVOID EventCategoryData,
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PDRIVER_NOTIFICATION_CALLBACK_ROUTINE CallbackRoutine,
+ _Inout_opt_ PVOID Context,
+ _Out_ PVOID *NotificationEntry)
{
PPNP_NOTIFY_ENTRY Entry;
PWSTR SymbolicLinkList;
@@ -260,18 +357,12 @@ IoRegisterPlugPlayNotification(IN IO_NOTIFICATION_EVENT_CATEGORY
EventCategory,
PAGED_CODE();
DPRINT("%s(EventCategory 0x%x, EventCategoryFlags 0x%lx, DriverObject %p)
called.\n",
- __FUNCTION__,
- EventCategory,
- EventCategoryFlags,
- DriverObject);
+ __FUNCTION__, EventCategory, EventCategoryFlags, DriverObject);
ObReferenceObject(DriverObject);
/* Try to allocate entry for notification before sending any notification */
- Entry = ExAllocatePoolWithTag(NonPagedPool,
- sizeof(PNP_NOTIFY_ENTRY),
- TAG_PNP_NOTIFY);
-
+ Entry = ExAllocatePoolWithTag(PagedPool, sizeof(PNP_NOTIFY_ENTRY), TAG_PNP_NOTIFY);
if (!Entry)
{
DPRINT("ExAllocatePool() failed\n");
@@ -279,83 +370,99 @@ IoRegisterPlugPlayNotification(IN IO_NOTIFICATION_EVENT_CATEGORY
EventCategory,
return STATUS_INSUFFICIENT_RESOURCES;
}
- if (EventCategory == EventCategoryDeviceInterfaceChange &&
- EventCategoryFlags & PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES)
- {
- DEVICE_INTERFACE_CHANGE_NOTIFICATION NotificationInfos;
- UNICODE_STRING SymbolicLinkU;
- PWSTR SymbolicLink;
-
- Status = IoGetDeviceInterfaces((LPGUID)EventCategoryData,
- NULL, /* PhysicalDeviceObject OPTIONAL */
- 0, /* Flags */
- &SymbolicLinkList);
- if (NT_SUCCESS(Status))
- {
- /* Enumerate SymbolicLinkList */
- NotificationInfos.Version = 1;
- NotificationInfos.Size = sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION);
- RtlCopyMemory(&NotificationInfos.Event,
- &GUID_DEVICE_INTERFACE_ARRIVAL,
- sizeof(GUID));
- RtlCopyMemory(&NotificationInfos.InterfaceClassGuid,
- EventCategoryData,
- sizeof(GUID));
- NotificationInfos.SymbolicLinkName = &SymbolicLinkU;
-
- for (SymbolicLink = SymbolicLinkList;
- *SymbolicLink;
- SymbolicLink += wcslen(SymbolicLink) + 1)
- {
- RtlInitUnicodeString(&SymbolicLinkU, SymbolicLink);
- DPRINT("Calling callback routine for %S\n", SymbolicLink);
- (*CallbackRoutine)(&NotificationInfos, Context);
- }
-
- ExFreePool(SymbolicLinkList);
- }
- }
+ *Entry = (PNP_NOTIFY_ENTRY) {
+ .PnpNotificationProc = CallbackRoutine,
+ .Context = Context,
+ .DriverObject = DriverObject,
+ .EventCategory = EventCategory,
+ .RefCount = 1
+ };
- Entry->PnpNotificationProc = CallbackRoutine;
- Entry->EventCategory = EventCategory;
- Entry->Context = Context;
- Entry->DriverObject = DriverObject;
switch (EventCategory)
{
case EventCategoryDeviceInterfaceChange:
{
- Status = RtlStringFromGUID(EventCategoryData, &Entry->Guid);
- if (!NT_SUCCESS(Status))
+ Entry->Guid = *(LPGUID)EventCategoryData;
+
+ // first register the notification
+ KeAcquireGuardedMutex(&PiNotifyDeviceInterfaceLock);
+ InsertTailList(&PiNotifyDeviceInterfaceListHead,
&Entry->PnpNotifyList);
+ KeReleaseGuardedMutex(&PiNotifyDeviceInterfaceLock);
+
+ // then process existing interfaces if asked
+ if (EventCategoryFlags &
PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES)
{
- ExFreePoolWithTag(Entry, TAG_PNP_NOTIFY);
- ObDereferenceObject(DriverObject);
- return Status;
+ DEVICE_INTERFACE_CHANGE_NOTIFICATION NotificationInfos;
+ UNICODE_STRING SymbolicLinkU;
+ PWSTR SymbolicLink;
+
+ Status = IoGetDeviceInterfaces((LPGUID)EventCategoryData,
+ NULL, /* PhysicalDeviceObject OPTIONAL */
+ 0, /* Flags */
+ &SymbolicLinkList);
+ if (NT_SUCCESS(Status))
+ {
+ /* Enumerate SymbolicLinkList */
+ NotificationInfos.Version = 1;
+ NotificationInfos.Size =
sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION);
+ NotificationInfos.Event = GUID_DEVICE_INTERFACE_ARRIVAL;
+ NotificationInfos.InterfaceClassGuid = *(LPGUID)EventCategoryData;
+ NotificationInfos.SymbolicLinkName = &SymbolicLinkU;
+
+ for (SymbolicLink = SymbolicLinkList;
+ *SymbolicLink;
+ SymbolicLink += (SymbolicLinkU.Length / sizeof(WCHAR)) + 1)
+ {
+ RtlInitUnicodeString(&SymbolicLinkU, SymbolicLink);
+ DPRINT("Calling callback routine for %S\n",
SymbolicLink);
+ PiCallNotifyProc(CallbackRoutine, &NotificationInfos,
Context);
+ }
+
+ ExFreePool(SymbolicLinkList);
+ }
}
break;
}
case EventCategoryHardwareProfileChange:
{
- /* nothing to do */
- break;
+ KeAcquireGuardedMutex(&PiNotifyHwProfileLock);
+ InsertTailList(&PiNotifyHwProfileListHead,
&Entry->PnpNotifyList);
+ KeReleaseGuardedMutex(&PiNotifyHwProfileLock);
+ break;
}
case EventCategoryTargetDeviceChange:
{
+ PDEVICE_NODE deviceNode;
Entry->FileObject = (PFILE_OBJECT)EventCategoryData;
+
+ // NOTE: the device node's PDO is referenced here
+ Status = IopGetRelatedTargetDevice(Entry->FileObject, &deviceNode);
+ if (!NT_SUCCESS(Status))
+ {
+ ObDereferenceObject(DriverObject);
+ ExFreePoolWithTag(Entry, TAG_PNP_NOTIFY);
+ return Status;
+ }
+ // save it so we can dereference it later
+ Entry->DeviceObject = deviceNode->PhysicalDeviceObject;
+
+ // each DEVICE_NODE has its own registered notifications list
+ KeAcquireGuardedMutex(&PiNotifyTargetDeviceLock);
+ InsertTailList(&deviceNode->TargetDeviceNotify,
&Entry->PnpNotifyList);
+ KeReleaseGuardedMutex(&PiNotifyTargetDeviceLock);
break;
}
default:
{
DPRINT1("%s: unknown EventCategory 0x%x UNIMPLEMENTED\n",
__FUNCTION__, EventCategory);
- break;
+
+ ObDereferenceObject(DriverObject);
+ ExFreePoolWithTag(Entry, TAG_PNP_NOTIFY);
+ return STATUS_NOT_SUPPORTED;
}
}
- KeAcquireGuardedMutex(&PnpNotifyListLock);
- InsertHeadList(&PnpNotifyListHead,
- &Entry->PnpNotifyList);
- KeReleaseGuardedMutex(&PnpNotifyListLock);
-
DPRINT("%s returns NotificationEntry %p\n", __FUNCTION__, Entry);
*NotificationEntry = Entry;
@@ -366,25 +473,46 @@ IoRegisterPlugPlayNotification(IN IO_NOTIFICATION_EVENT_CATEGORY
EventCategory,
/*
* @implemented
*/
+CODE_SEG("PAGE")
NTSTATUS
NTAPI
-IoUnregisterPlugPlayNotification(IN PVOID NotificationEntry)
+IoUnregisterPlugPlayNotification(
+ _In_ PVOID NotificationEntry)
{
- PPNP_NOTIFY_ENTRY Entry;
+ PPNP_NOTIFY_ENTRY Entry = NotificationEntry;
+ PKGUARDED_MUTEX Lock;
+
PAGED_CODE();
- Entry = (PPNP_NOTIFY_ENTRY)NotificationEntry;
DPRINT("%s(NotificationEntry %p) called\n", __FUNCTION__, Entry);
- KeAcquireGuardedMutex(&PnpNotifyListLock);
- RemoveEntryList(&Entry->PnpNotifyList);
- KeReleaseGuardedMutex(&PnpNotifyListLock);
-
- RtlFreeUnicodeString(&Entry->Guid);
-
- ObDereferenceObject(Entry->DriverObject);
+ switch (Entry->EventCategory)
+ {
+ case EventCategoryDeviceInterfaceChange:
+ Lock = &PiNotifyDeviceInterfaceLock;
+ break;
+ case EventCategoryHardwareProfileChange:
+ Lock = &PiNotifyHwProfileLock;
+ break;
+ case EventCategoryTargetDeviceChange:
+ Lock = &PiNotifyTargetDeviceLock;
+ break;
+ default:
+ UNREACHABLE;
+ return STATUS_NOT_SUPPORTED;
+ }
- ExFreePoolWithTag(Entry, TAG_PNP_NOTIFY);
+ KeAcquireGuardedMutex(Lock);
+ if (!Entry->Deleted)
+ {
+ Entry->Deleted = TRUE; // so it can't be unregistered two times
+ PiDereferencePnpNotifyEntry(Entry);
+ }
+ else
+ {
+ DPRINT1("IoUnregisterPlugPlayNotification called two times for 0x%p\n",
NotificationEntry);
+ }
+ KeReleaseGuardedMutex(Lock);
return STATUS_SUCCESS;
}
diff --git a/ntoskrnl/io/pnpmgr/pnpreport.c b/ntoskrnl/io/pnpmgr/pnpreport.c
index cb60a133329..ae0ac9566d3 100644
--- a/ntoskrnl/io/pnpmgr/pnpreport.c
+++ b/ntoskrnl/io/pnpmgr/pnpreport.c
@@ -131,11 +131,7 @@ PpSetCustomTargetEvent(IN PDEVICE_OBJECT DeviceObject,
}
/* That call is totally wrong but notifications handler must be fixed first */
- IopNotifyPlugPlayNotification(DeviceObject,
- EventCategoryTargetDeviceChange,
- &GUID_PNP_CUSTOM_NOTIFICATION,
- NotificationStructure,
- NULL);
+ PiNotifyTargetDeviceChange(&GUID_PNP_CUSTOM_NOTIFICATION, DeviceObject,
NotificationStructure);
if (SyncEvent)
{