https://git.reactos.org/?p=reactos.git;a=commitdiff;h=cf0bc1c1321047b879edc…
commit cf0bc1c1321047b879edcd19bfbf08138ba9c988
Author: Victor Perevertkin <victor.perevertkin(a)reactos.org>
AuthorDate: Wed Oct 13 02:28:24 2021 +0300
Commit: Victor Perevertkin <victor.perevertkin(a)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);
+}