https://git.reactos.org/?p=reactos.git;a=commitdiff;h=cf0bc1c1321047b879edcd...
commit cf0bc1c1321047b879edcd19bfbf08138ba9c988 Author: Victor Perevertkin victor.perevertkin@reactos.org AuthorDate: Wed Oct 13 02:28:24 2021 +0300 Commit: Victor Perevertkin victor.perevertkin@reactos.org CommitDate: Wed Apr 27 02:42:20 2022 +0300
[NTOS:PNP] Halfplement IoInvalidateDeviceState
Implement the correct start-stop sequence for resource rebalancing without the actual rebalancing. Also move IoInvalidateDeviceState processing into the enumeration thread as it should be.
CORE-17519 --- ntoskrnl/include/internal/io.h | 13 ++- ntoskrnl/io/pnpmgr/devaction.c | 174 ++++++++++++++++++++++------------------- ntoskrnl/io/pnpmgr/pnpirp.c | 55 ++++++++++++- ntoskrnl/io/pnpmgr/pnpmgr.c | 8 ++ 4 files changed, 167 insertions(+), 83 deletions(-)
diff --git a/ntoskrnl/include/internal/io.h b/ntoskrnl/include/internal/io.h index ca18912a941..d877bd6fa97 100644 --- a/ntoskrnl/include/internal/io.h +++ b/ntoskrnl/include/internal/io.h @@ -527,7 +527,8 @@ typedef enum _DEVICE_ACTION PiActionEnumRootDevices, PiActionResetDevice, PiActionAddBootDevices, - PiActionStartDevice + PiActionStartDevice, + PiActionQueryState, } DEVICE_ACTION;
// @@ -1403,6 +1404,16 @@ PiIrpQueryDeviceRelations( _In_ PDEVICE_NODE DeviceNode, _In_ DEVICE_RELATION_TYPE Type);
+NTSTATUS +PiIrpQueryResources( + _In_ PDEVICE_NODE DeviceNode, + _Out_ PCM_RESOURCE_LIST *Resources); + +NTSTATUS +PiIrpQueryResourceRequirements( + _In_ PDEVICE_NODE DeviceNode, + _Out_ PIO_RESOURCE_REQUIREMENTS_LIST *Resources); + NTSTATUS PiIrpQueryDeviceText( _In_ PDEVICE_NODE DeviceNode, diff --git a/ntoskrnl/io/pnpmgr/devaction.c b/ntoskrnl/io/pnpmgr/devaction.c index 559fc087b0c..a3b03d5bd2c 100644 --- a/ntoskrnl/io/pnpmgr/devaction.c +++ b/ntoskrnl/io/pnpmgr/devaction.c @@ -1552,8 +1552,8 @@ PiStartDeviceFinal( DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status); }
- /* Invalidate device state so IRP_MN_QUERY_PNP_DEVICE_STATE is sent */ - IoInvalidateDeviceState(DeviceNode->PhysicalDeviceObject); + // Query the device state (IRP_MN_QUERY_PNP_DEVICE_STATE) + PiQueueDeviceAction(DeviceNode->PhysicalDeviceObject, PiActionQueryState, NULL, NULL);
DPRINT("Sending GUID_DEVICE_ARRIVAL %wZ\n", &DeviceNode->InstancePath); IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, &DeviceNode->InstancePath); @@ -2025,25 +2025,27 @@ IopRemoveDevice(PDEVICE_NODE DeviceNode) return Status; }
-/* - * @implemented +/** + * @brief Processes the IoInvalidateDeviceState request + * + * Sends IRP_MN_QUERY_PNP_DEVICE_STATE request and sets device node's flags + * according to the result. + * Tree reenumeration should be started upon a successful return of the function. + * + * @todo Do not return STATUS_SUCCESS if nothing is changed. */ -VOID -NTAPI -IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject) +static +NTSTATUS +PiUpdateDeviceState( + _In_ PDEVICE_NODE DeviceNode) { - PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject); PNP_DEVICE_STATE PnPFlags; NTSTATUS Status;
Status = PiIrpQueryPnPDeviceState(DeviceNode, &PnPFlags); if (!NT_SUCCESS(Status)) { - if (Status != STATUS_NOT_SUPPORTED) - { - DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%lx\n", Status); - } - return; + return Status; }
if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE) @@ -2056,83 +2058,37 @@ IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject) else DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
- if ((PnPFlags & PNP_DEVICE_REMOVED) || - ((PnPFlags & PNP_DEVICE_FAILED) && !(PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED))) + if (PnPFlags & PNP_DEVICE_REMOVED || PnPFlags & PNP_DEVICE_DISABLED) { - /* Flag it if it's failed */ - if (PnPFlags & PNP_DEVICE_FAILED) - { - PiSetDevNodeProblem(DeviceNode, CM_PROB_FAILED_POST_START); - } + PiSetDevNodeProblem(DeviceNode, + PnPFlags & PNP_DEVICE_DISABLED + ? CM_PROB_HARDWARE_DISABLED + : CM_PROB_DEVICE_NOT_THERE);
- DeviceNode->Flags |= DNF_DEVICE_GONE; PiSetDevNodeState(DeviceNode, DeviceNodeAwaitingQueuedRemoval); } - // it doesn't work anyway. A real resource rebalancing should be implemented -#if 0 - else if ((PnPFlags & PNP_DEVICE_FAILED) && (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)) - { - /* Stop for resource rebalance */ - Status = IopStopDevice(DeviceNode); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to stop device for rebalancing\n"); - - /* Stop failed so don't rebalance */ - PnPFlags &= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED; - } - } - - /* Resource rebalance */ - if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED) + else if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED) { - DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n"); + // Query resource rebalance
- Status = IopInitiatePnpIrp(PhysicalDeviceObject, - &IoStatusBlock, - IRP_MN_QUERY_RESOURCES, - NULL); - if (NT_SUCCESS(Status) && IoStatusBlock.Information) - { - DeviceNode->BootResources = - (PCM_RESOURCE_LIST)IoStatusBlock.Information; - IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG); - } - else - { - DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); - DeviceNode->BootResources = NULL; - } - - DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n"); - - Status = IopInitiatePnpIrp(PhysicalDeviceObject, - &IoStatusBlock, - IRP_MN_QUERY_RESOURCE_REQUIREMENTS, - NULL); - if (NT_SUCCESS(Status)) - { - DeviceNode->ResourceRequirements = - (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information; - } + if (PnPFlags & PNP_DEVICE_FAILED) + DeviceNode->Flags &= DNF_NON_STOPPED_REBALANCE; else - { - DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status); - DeviceNode->ResourceRequirements = NULL; - } - - /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */ - if (IopStartDevice(DeviceNode) != STATUS_SUCCESS) - { - DPRINT1("Restart after resource rebalance failed\n"); + DeviceNode->Flags |= DNF_NON_STOPPED_REBALANCE;
- DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING); - DeviceNode->Flags |= DNF_START_FAILED; + // Clear DNF_NO_RESOURCE_REQUIRED just in case (will be set back if needed) + DeviceNode->Flags &= ~DNF_NO_RESOURCE_REQUIRED;
- IopRemoveDevice(DeviceNode); - } + // This will be caught up later by enumeration + DeviceNode->Flags |= DNF_RESOURCE_REQUIREMENTS_CHANGED; } -#endif + else if (PnPFlags & PNP_DEVICE_FAILED) + { + PiSetDevNodeProblem(DeviceNode, CM_PROB_FAILED_POST_START); + PiSetDevNodeState(DeviceNode, DeviceNodeAwaitingQueuedRemoval); + } + + return STATUS_SUCCESS; }
static @@ -2327,6 +2283,30 @@ cleanup: &DeviceNode->InstancePath); }
+static +VOID +PiFakeResourceRebalance( + _In_ PDEVICE_NODE DeviceNode) +{ + ASSERT(DeviceNode->Flags & DNF_RESOURCE_REQUIREMENTS_CHANGED); + + PCM_RESOURCE_LIST bootConfig = NULL; + PIO_RESOURCE_REQUIREMENTS_LIST resourceRequirements = NULL; + + PiIrpQueryResources(DeviceNode, &bootConfig); + PiIrpQueryResourceRequirements(DeviceNode, &resourceRequirements); + + DeviceNode->BootResources = bootConfig; + DeviceNode->ResourceRequirements = resourceRequirements; + + if (bootConfig) + { + DeviceNode->Flags |= DNF_HAS_BOOT_CONFIG; + } + + DeviceNode->Flags &= ~DNF_RESOURCE_REQUIREMENTS_CHANGED; +} + static VOID PiDevNodeStateMachine( @@ -2420,12 +2400,28 @@ PiDevNodeStateMachine( PiSetDevNodeState(currentNode, DeviceNodeEnumerateCompletion); doProcessAgain = TRUE; } + else if (currentNode->Flags & DNF_RESOURCE_REQUIREMENTS_CHANGED) + { + if (currentNode->Flags & DNF_NON_STOPPED_REBALANCE) + { + PiFakeResourceRebalance(currentNode); + currentNode->Flags &= ~DNF_NON_STOPPED_REBALANCE; + } + else + { + PiIrpQueryStopDevice(currentNode); + PiSetDevNodeState(currentNode, DeviceNodeQueryStopped); + } + + doProcessAgain = TRUE; + } break; case DeviceNodeQueryStopped: // we're here after sending IRP_MN_QUERY_STOP_DEVICE status = currentNode->CompletionStatus; if (NT_SUCCESS(status)) { + PiIrpStopDevice(currentNode); PiSetDevNodeState(currentNode, DeviceNodeStopped); } else @@ -2433,10 +2429,14 @@ PiDevNodeStateMachine( PiIrpCancelStopDevice(currentNode); PiSetDevNodeState(currentNode, DeviceNodeStarted); } + doProcessAgain = TRUE; break; case DeviceNodeStopped: // TODO: do resource rebalance (not implemented) - ASSERT(FALSE); + PiFakeResourceRebalance(currentNode); + + PiSetDevNodeState(currentNode, DeviceNodeDriversAdded); + doProcessAgain = TRUE; break; case DeviceNodeRestartCompletion: break; @@ -2522,6 +2522,8 @@ ActionToStr( return "PiActionAddBootDevices"; case PiActionStartDevice: return "PiActionStartDevice"; + case PiActionQueryState: + return "PiActionQueryState"; default: return "(request unknown)"; } @@ -2596,6 +2598,16 @@ PipDeviceActionWorker( } break;
+ case PiActionQueryState: + // First, do a IRP_MN_QUERY_PNP_DEVICE_STATE request, + // it will update node's flags and then do enumeration if something changed + status = PiUpdateDeviceState(deviceNode); + if (NT_SUCCESS(status)) + { + PiDevNodeStateMachine(deviceNode); + } + break; + default: DPRINT1("Unimplemented device action %u\n", Request->Action); status = STATUS_NOT_IMPLEMENTED; diff --git a/ntoskrnl/io/pnpmgr/pnpirp.c b/ntoskrnl/io/pnpmgr/pnpirp.c index 66e4382bdc6..952150b2731 100644 --- a/ntoskrnl/io/pnpmgr/pnpirp.c +++ b/ntoskrnl/io/pnpmgr/pnpirp.c @@ -196,6 +196,58 @@ PiIrpQueryDeviceRelations( return status; }
+// IRP_MN_QUERY_RESOURCES (0x0A) +NTSTATUS +PiIrpQueryResources( + _In_ PDEVICE_NODE DeviceNode, + _Out_ PCM_RESOURCE_LIST *Resources) +{ + PAGED_CODE(); + + ASSERT(DeviceNode); + + ULONG_PTR longRes; + IO_STACK_LOCATION stack = { + .MajorFunction = IRP_MJ_PNP, + .MinorFunction = IRP_MN_QUERY_RESOURCES + }; + + NTSTATUS status; + status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack, (PVOID)&longRes); + if (NT_SUCCESS(status)) + { + *Resources = (PVOID)longRes; + } + + return status; +} + +// IRP_MN_QUERY_RESOURCE_REQUIREMENTS (0x0B) +NTSTATUS +PiIrpQueryResourceRequirements( + _In_ PDEVICE_NODE DeviceNode, + _Out_ PIO_RESOURCE_REQUIREMENTS_LIST *Resources) +{ + PAGED_CODE(); + + ASSERT(DeviceNode); + + ULONG_PTR longRes; + IO_STACK_LOCATION stack = { + .MajorFunction = IRP_MJ_PNP, + .MinorFunction = IRP_MN_QUERY_RESOURCE_REQUIREMENTS + }; + + NTSTATUS status; + status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack, (PVOID)&longRes); + if (NT_SUCCESS(status)) + { + *Resources = (PVOID)longRes; + } + + return status; +} + // IRP_MN_QUERY_DEVICE_TEXT (0x0C) NTSTATUS PiIrpQueryDeviceText( @@ -236,7 +288,8 @@ PiIrpQueryPnPDeviceState( PAGED_CODE();
ASSERT(DeviceNode); - ASSERT(DeviceNode->State == DeviceNodeStartPostWork || + ASSERT(DeviceNode->State == DeviceNodeResourcesAssigned || + DeviceNode->State == DeviceNodeStartPostWork || DeviceNode->State == DeviceNodeStarted);
ULONG_PTR longState; diff --git a/ntoskrnl/io/pnpmgr/pnpmgr.c b/ntoskrnl/io/pnpmgr/pnpmgr.c index 1d06943032a..e2f7ba98da5 100644 --- a/ntoskrnl/io/pnpmgr/pnpmgr.c +++ b/ntoskrnl/io/pnpmgr/pnpmgr.c @@ -2412,3 +2412,11 @@ IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType, AddressSpace, TranslatedAddress); } + +VOID +NTAPI +IoInvalidateDeviceState( + IN PDEVICE_OBJECT DeviceObject) +{ + PiQueueDeviceAction(DeviceObject, PiActionQueryState, NULL, NULL); +}