Index: include/internal/io.h =================================================================== --- ntoskrnl/include/internal/io.h (revision 71090) +++ ntoskrnl/include/internal/io.h (working copy) @@ -1288,7 +1288,13 @@ // extern POBJECT_TYPE IoCompletionType; extern PDEVICE_NODE IopRootDeviceNode; +#define OLD_PNP_LOCKING 0 +#if OLD_PNP_LOCKING extern KSPIN_LOCK IopDeviceTreeLock; +#else +extern ERESOURCE IopDeviceTreeLock; +extern ERESOURCE IopDeviceTreeTraverseLock; +#endif extern ULONG IopTraceLevel; extern GENERAL_LOOKASIDE IopMdlLookasideList; extern GENERIC_MAPPING IopCompletionMapping; Index: io/pnpmgr/pnpinit.c =================================================================== --- ntoskrnl/io/pnpmgr/pnpinit.c (revision 71090) +++ ntoskrnl/io/pnpmgr/pnpinit.c (working copy) @@ -386,7 +386,12 @@ PDEVICE_OBJECT Pdo; /* Initialize locks and such */ +#if OLD_PNP_LOCKING KeInitializeSpinLock(&IopDeviceTreeLock); +#else + ExInitializeResourceLite(&IopDeviceTreeLock); + ExInitializeResourceLite(&IopDeviceTreeTraverseLock); +#endif KeInitializeSpinLock(&IopDeviceRelationsSpinLock); InitializeListHead(&IopDeviceRelationsRequestList); Index: io/pnpmgr/pnpmgr.c =================================================================== --- ntoskrnl/io/pnpmgr/pnpmgr.c (revision 71090) +++ ntoskrnl/io/pnpmgr/pnpmgr.c (working copy) @@ -12,11 +12,16 @@ #include #define NDEBUG #include - +#define DNF_INVALID (DNF_HAS_PROBLEM | DNF_BOOT_CONFIG_RESERVED | DNF_LOCKED | DNF_BEEING_ENUMERATED | DNF_VISITED | DNF_NEED_RESTART | DNF_RESTART_OK | DNF_RESOURCE_REQUIREMENTS_NEED_FILTERED | DNF_REINSTALL | DNF_NOT_CONFIGURED | DNF_ADD_FAILED | DNF_HAL_NODE | DNF_INSUFFICIENT_RESOURCES | DNF_DELETED) /* GLOBALS *******************************************************************/ PDEVICE_NODE IopRootDeviceNode; +#if OLD_PNP_LOCKING KSPIN_LOCK IopDeviceTreeLock; +#else +ERESOURCE IopDeviceTreeLock; +ERESOURCE IopDeviceTreeTraverseLock; +#endif ERESOURCE PpRegistryDeviceResource; KGUARDED_MUTEX PpDeviceReferenceTableLock; RTL_AVL_TABLE PpDeviceReferenceTable; @@ -58,11 +63,130 @@ PDEVICE_OBJECT IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance); +#if !OLD_PNP_LOCKING +typedef enum _DEVICE_TREE_LOCK_LEVEL +{ + DeviceTreeLockRead, + DeviceTreeLockTraverse, + DeviceTreeLockWrite, + DeviceTreeLockConvertTraverseToWrite +} DEVICE_TREE_LOCK_LEVEL; + +VOID +IopAssertDeviceTreeLocked( + _In_ DEVICE_TREE_LOCK_LEVEL LockLevel, + _In_ BOOLEAN Exact) +{ + ASSERT(KeAreApcsDisabled()); + if (LockLevel == DeviceTreeLockRead) + { + ASSERT(ExIsResourceAcquiredSharedLite(&IopDeviceTreeLock)); + if (Exact) + ASSERT(!ExIsResourceAcquiredExclusiveLite(&IopDeviceTreeLock)); + } + else if (LockLevel == DeviceTreeLockTraverse) + { + ASSERT(ExIsResourceAcquiredSharedLite(&IopDeviceTreeLock)); + if (Exact) + ASSERT(!ExIsResourceAcquiredExclusiveLite(&IopDeviceTreeLock)); + ASSERT(ExIsResourceAcquiredExclusiveLite(&IopDeviceTreeTraverseLock)); + } + else if (LockLevel == DeviceTreeLockWrite || + LockLevel == DeviceTreeLockConvertTraverseToWrite) + { + ASSERT(ExIsResourceAcquiredExclusiveLite(&IopDeviceTreeLock)); + ASSERT(ExIsResourceAcquiredExclusiveLite(&IopDeviceTreeTraverseLock)); + } + else + { + ASSERT(FALSE); + } +} + +VOID +IopLockDeviceTree( + _In_ DEVICE_TREE_LOCK_LEVEL LockLevel) +{ + ULONG SharedCount; + ULONG i; + + KeEnterCriticalRegion(); + if (LockLevel == DeviceTreeLockRead) + { + ExAcquireResourceSharedLite(&IopDeviceTreeLock, TRUE); + } + else if (LockLevel == DeviceTreeLockTraverse) + { + ExAcquireResourceExclusiveLite(&IopDeviceTreeTraverseLock, TRUE); + ExAcquireResourceSharedLite(&IopDeviceTreeLock, TRUE); + } + else if (LockLevel == DeviceTreeLockWrite) + { + ASSERT(!ExIsResourceAcquiredSharedLite(&IopDeviceTreeLock) || + ExIsResourceAcquiredExclusiveLite(&IopDeviceTreeLock)); + ExAcquireResourceExclusiveLite(&IopDeviceTreeTraverseLock, TRUE); + ExAcquireResourceExclusiveLite(&IopDeviceTreeLock, TRUE); + } + else if (LockLevel == DeviceTreeLockConvertTraverseToWrite) + { + IopAssertDeviceTreeLocked(DeviceTreeLockTraverse, TRUE); + SharedCount = ExIsResourceAcquiredSharedLite(&IopDeviceTreeLock); + for (i = 0; i < SharedCount; i++) + { + ExReleaseResourceLite(&IopDeviceTreeLock); + } + for (i = 0; i < SharedCount; i++) + { + ExAcquireResourceExclusiveLite(&IopDeviceTreeLock, TRUE); + } + } + else + { + ASSERT(FALSE); + } + IopAssertDeviceTreeLocked(LockLevel, TRUE); +} + +VOID +IopUnlockDeviceTree( + _In_ DEVICE_TREE_LOCK_LEVEL LockLevel) +{ + if (LockLevel == DeviceTreeLockRead) + { + ExReleaseResourceLite(&IopDeviceTreeLock); + } + else if (LockLevel == DeviceTreeLockTraverse) + { + ExReleaseResourceLite(&IopDeviceTreeLock); + ExReleaseResourceLite(&IopDeviceTreeTraverseLock); + } + else if (LockLevel == DeviceTreeLockWrite) + { + ExReleaseResourceLite(&IopDeviceTreeLock); + ExReleaseResourceLite(&IopDeviceTreeTraverseLock); + } + else if (LockLevel == DeviceTreeLockConvertTraverseToWrite) + { + IopAssertDeviceTreeLocked(DeviceTreeLockWrite, TRUE); + ExConvertExclusiveToSharedLite(&IopDeviceTreeLock); + IopAssertDeviceTreeLocked(DeviceTreeLockTraverse, TRUE); + } + else + { + ASSERT(FALSE); + } + KeLeaveCriticalRegion(); +} +#endif + PDEVICE_NODE FASTCALL IopGetDeviceNode(PDEVICE_OBJECT DeviceObject) { - return ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode; + PDEVICE_NODE DeviceNode = ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode; + if (DeviceNode) + ASSERT((DeviceNode->Flags & DNF_INVALID) == 0); + return DeviceNode; } VOID @@ -434,6 +558,7 @@ PDEVICE_OBJECT Fdo; NTSTATUS Status; + ASSERT((DeviceNode->Flags & DNF_INVALID) == 0); if (!DriverObject) { /* Special case for bus driven devices */ @@ -491,6 +616,7 @@ ObDereferenceObject(Fdo); IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED); + ASSERT((DeviceNode->Flags & DNF_INVALID) == 0); return STATUS_SUCCESS; } @@ -586,6 +712,7 @@ IO_STACK_LOCATION Stack; PVOID Dummy; PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); + NTSTATUS Status; /* Drop all our state for this device in case it isn't really going away */ DeviceNode->Flags &= DNF_ENUMERATED | DNF_PROCESSED; @@ -595,7 +722,11 @@ Stack.MinorFunction = IRP_MN_REMOVE_DEVICE; /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */ - IopSynchronousCall(DeviceObject, &Stack, &Dummy); + Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Broken device %p failed IRP_MN_REMOVE_DEVICE %lx\n", DeviceObject, Status); + } IopNotifyPlugPlayNotification(DeviceObject, EventCategoryTargetDeviceChange, @@ -700,6 +831,7 @@ /* We now need enumeration */ DeviceNode->Flags |= DNF_NEED_ENUMERATION_ONLY; + ASSERT((DeviceNode->Flags & DNF_INVALID) == 0); } NTSTATUS @@ -708,9 +840,12 @@ { PDEVICE_OBJECT DeviceObject; NTSTATUS Status; + ULONG InitialFlags = DeviceNode->Flags; + PAGED_CODE(); /* Sanity check */ + ASSERT((DeviceNode->Flags & DNF_INVALID) == 0); ASSERT((DeviceNode->Flags & DNF_ADDED)); ASSERT((DeviceNode->Flags & (DNF_RESOURCE_ASSIGNED | DNF_RESOURCE_REPORTED | @@ -749,6 +884,7 @@ /* Nothing to do */ Status = STATUS_SUCCESS; } + ASSERT((DeviceNode->Flags & DNF_INVALID) == 0); /* Return */ return Status; @@ -785,6 +921,7 @@ UNICODE_STRING KeyName; OBJECT_ATTRIBUTES ObjectAttributes; + ASSERT((DeviceNode->Flags & DNF_INVALID) == 0); if (DeviceNode->Flags & DNF_DISABLED) return STATUS_SUCCESS; @@ -793,7 +930,11 @@ goto ByeBye; /* New PnP ABI */ + ASSERT((DeviceNode->Flags & DNF_INVALID) == 0); + ASSERT((DeviceNode->Flags & DNF_ADDED)); + ASSERT(!(DeviceNode->Flags & DNF_STARTED) || (DeviceNode->Flags & DNF_LEGACY_DRIVER)); IopStartAndEnumerateDevice(DeviceNode); + ASSERT((DeviceNode->Flags & DNF_INVALID) == 0); /* FIX: Should be done in new device instance code */ Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceHandle); @@ -817,6 +958,7 @@ // } ByeBye: + ASSERT((DeviceNode->Flags & DNF_INVALID) == 0); if (ControlHandle != NULL) ZwClose(ControlHandle); @@ -927,13 +1069,23 @@ NTSTATUS IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject) { +#if OLD_PNP_LOCKING KIRQL OldIrql; +#endif if (PopSystemPowerDeviceNode) { +#if OLD_PNP_LOCKING KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); +#else + IopLockDeviceTree(DeviceTreeLockRead); +#endif *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject; +#if OLD_PNP_LOCKING KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); +#else + IopUnlockDeviceTree(DeviceTreeLockRead); +#endif return STATUS_SUCCESS; } @@ -1030,7 +1182,9 @@ { PDEVICE_NODE Node; NTSTATUS Status; +#if OLD_PNP_LOCKING KIRQL OldIrql; +#endif UNICODE_STRING FullServiceName; UNICODE_STRING LegacyPrefix = RTL_CONSTANT_STRING(L"LEGACY_"); UNICODE_STRING UnknownDeviceName = RTL_CONSTANT_STRING(L"UNKNOWN"); @@ -1157,7 +1311,12 @@ if (ParentNode) { +#if OLD_PNP_LOCKING KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); +#else + IopLockDeviceTree(DeviceTreeLockTraverse); + IopLockDeviceTree(DeviceTreeLockConvertTraverseToWrite); +#endif Node->Parent = ParentNode; Node->Sibling = NULL; if (ParentNode->LastChild == NULL) @@ -1170,7 +1329,12 @@ ParentNode->LastChild->Sibling = Node; ParentNode->LastChild = Node; } +#if OLD_PNP_LOCKING KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); +#else + IopUnlockDeviceTree(DeviceTreeLockConvertTraverseToWrite); + IopUnlockDeviceTree(DeviceTreeLockTraverse); +#endif Node->Level = ParentNode->Level + 1; } @@ -1184,7 +1348,9 @@ NTSTATUS IopFreeDeviceNode(PDEVICE_NODE DeviceNode) { +#if OLD_PNP_LOCKING KIRQL OldIrql; +#endif PDEVICE_NODE PrevSibling = NULL; /* All children must be deleted before a parent is deleted */ @@ -1191,7 +1357,11 @@ ASSERT(!DeviceNode->Child); ASSERT(DeviceNode->PhysicalDeviceObject); +#if OLD_PNP_LOCKING KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); +#else + IopLockDeviceTree(DeviceTreeLockWrite); +#endif /* Get previous sibling */ if (DeviceNode->Parent && DeviceNode->Parent->Child != DeviceNode) @@ -1218,7 +1388,11 @@ if (PrevSibling) PrevSibling->Sibling = DeviceNode->Sibling; +#if OLD_PNP_LOCKING KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); +#else + IopUnlockDeviceTree(DeviceTreeLockWrite); +#endif RtlFreeUnicodeString(&DeviceNode->InstancePath); @@ -1393,6 +1567,9 @@ DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %p Context 0x%p)\n", Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context); +#if !OLD_PNP_LOCKING + IopLockDeviceTree(DeviceTreeLockTraverse); +#endif /* Start from the specified device node */ Context->DeviceNode = Context->FirstDeviceNode; @@ -1404,6 +1581,9 @@ code STATUS_SUCCESS */ Status = STATUS_SUCCESS; } +#if !OLD_PNP_LOCKING + IopUnlockDeviceTree(DeviceTreeLockTraverse); +#endif return Status; } @@ -2284,6 +2464,9 @@ DPRINT("DeviceObject 0x%p\n", DeviceObject); +#if !OLD_PNP_LOCKING + IopLockDeviceTree(DeviceTreeLockTraverse); +#endif if (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY) { DeviceNode->Flags &= ~DNF_NEED_ENUMERATION_ONLY; @@ -2305,7 +2488,7 @@ if (!NT_SUCCESS(Status) || Status == STATUS_PENDING) { DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); - return Status; + goto Exit; } DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; @@ -2321,7 +2504,8 @@ { /* We're all done */ DPRINT("No PDOs\n"); - return STATUS_SUCCESS; + Status = STATUS_SUCCESS; + goto Exit; } DPRINT("Got %u PDOs\n", DeviceRelations->Count); @@ -2380,7 +2564,7 @@ if (!NT_SUCCESS(Status)) { DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status); - return Status; + goto Exit; } /* @@ -2396,7 +2580,7 @@ if (!NT_SUCCESS(Status)) { DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status); - return Status; + goto Exit; } /* @@ -2406,9 +2590,13 @@ if (!NT_SUCCESS(Status)) { DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status); - return Status; + goto Exit; } +Exit: +#if !OLD_PNP_LOCKING + IopUnlockDeviceTree(DeviceTreeLockTraverse); +#endif DPRINT("IopEnumerateDevice() finished\n"); return STATUS_SUCCESS; } @@ -4316,36 +4504,55 @@ { PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice; NTSTATUS Status; +#if OLD_PNP_LOCKING KIRQL OldIrql; +#endif +#if OLD_PNP_LOCKING KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); +#else + IopAssertDeviceTreeLocked(DeviceTreeLockTraverse, TRUE); + IopLockDeviceTree(DeviceTreeLockTraverse); +#endif ChildDeviceNode = ParentDeviceNode->Child; while (ChildDeviceNode != NULL) { NextDeviceNode = ChildDeviceNode->Sibling; +#if OLD_PNP_LOCKING KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); +#endif Status = IopPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject, Force); if (!NT_SUCCESS(Status)) { + DPRINT1("IopPrepareDeviceForRemoval failed for devnode %p PDO %p with %lx\n", ChildDeviceNode, ChildDeviceNode->PhysicalDeviceObject, Status); FailedRemoveDevice = ChildDeviceNode; goto cleanup; } +#if OLD_PNP_LOCKING KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); +#endif ChildDeviceNode = NextDeviceNode; } +#if OLD_PNP_LOCKING KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); - +#else + IopUnlockDeviceTree(DeviceTreeLockTraverse); +#endif return STATUS_SUCCESS; cleanup: +#if OLD_PNP_LOCKING KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); +#endif ChildDeviceNode = ParentDeviceNode->Child; while (ChildDeviceNode != NULL) { NextDeviceNode = ChildDeviceNode->Sibling; +#if OLD_PNP_LOCKING KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); +#endif IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject); @@ -4352,13 +4559,23 @@ /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */ if (ChildDeviceNode == FailedRemoveDevice) +#if OLD_PNP_LOCKING return Status; +#else + break; +#endif ChildDeviceNode = NextDeviceNode; +#if OLD_PNP_LOCKING KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); +#endif } +#if OLD_PNP_LOCKING KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); +#else + IopUnlockDeviceTree(DeviceTreeLockTraverse); +#endif return Status; } @@ -4368,22 +4585,37 @@ IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode) { PDEVICE_NODE ChildDeviceNode, NextDeviceNode; +#if OLD_PNP_LOCKING KIRQL OldIrql; +#endif +#if OLD_PNP_LOCKING KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); +#else + IopAssertDeviceTreeLocked(DeviceTreeLockTraverse, TRUE); + IopLockDeviceTree(DeviceTreeLockTraverse); +#endif ChildDeviceNode = ParentDeviceNode->Child; while (ChildDeviceNode != NULL) { NextDeviceNode = ChildDeviceNode->Sibling; +#if OLD_PNP_LOCKING KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); +#endif IopSendRemoveDevice(ChildDeviceNode->PhysicalDeviceObject); ChildDeviceNode = NextDeviceNode; +#if OLD_PNP_LOCKING KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); +#endif } +#if OLD_PNP_LOCKING KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); +#else + IopUnlockDeviceTree(DeviceTreeLockTraverse); +#endif } static @@ -4391,22 +4623,37 @@ IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode) { PDEVICE_NODE ChildDeviceNode, NextDeviceNode; +#if OLD_PNP_LOCKING KIRQL OldIrql; +#endif +#if OLD_PNP_LOCKING KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); +#else + IopAssertDeviceTreeLocked(DeviceTreeLockTraverse, TRUE); + IopLockDeviceTree(DeviceTreeLockTraverse); +#endif ChildDeviceNode = ParentDeviceNode->Child; while (ChildDeviceNode != NULL) { NextDeviceNode = ChildDeviceNode->Sibling; +#if OLD_PNP_LOCKING KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); +#endif IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject); ChildDeviceNode = NextDeviceNode; +#if OLD_PNP_LOCKING KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); +#endif } +#if OLD_PNP_LOCKING KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); +#else + IopUnlockDeviceTree(DeviceTreeLockTraverse); +#endif } static @@ -4547,7 +4794,7 @@ &Stack); if (!NT_SUCCESS(Status)) { - DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); + DPRINT1("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); DeviceRelations = NULL; } else @@ -4559,12 +4806,16 @@ { Status = IopQueryRemoveDeviceRelations(DeviceRelations, Force); if (!NT_SUCCESS(Status)) + { + DPRINT1("IopQueryRemoveDeviceRelations() failed with status 0x%08lx\n", Status); return Status; + } } Status = IopQueryRemoveChildDevices(DeviceNode, Force); if (!NT_SUCCESS(Status)) { + DPRINT1("IopQueryRemoveChildDevices failed with %lx\n", Status); if (DeviceRelations) IopCancelRemoveDeviceRelations(DeviceRelations); return Status;