https://git.reactos.org/?p=reactos.git;a=commitdiff;h=cf0bc1c1321047b879edcd19bfbf08138ba9c988

commit cf0bc1c1321047b879edcd19bfbf08138ba9c988
Author:     Victor Perevertkin <[email protected]>
AuthorDate: Wed Oct 13 02:28:24 2021 +0300
Commit:     Victor Perevertkin <[email protected]>
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);
+}

Reply via email to