[ros-diffs] [cgutman] 52046: [NTOSKRNL] - Massive rework of device removal - IRP_MN_QUERY_REMOVE_DEVICE is sent to all devices that will be removed in response to a removal/ejection - If any of the IRP_MN_QUER...

cgutman at svn.reactos.org cgutman at svn.reactos.org
Wed Jun 1 19:32:12 UTC 2011


Author: cgutman
Date: Wed Jun  1 19:32:12 2011
New Revision: 52046

URL: http://svn.reactos.org/svn/reactos?rev=52046&view=rev
Log:
[NTOSKRNL]
- Massive rework of device removal
- IRP_MN_QUERY_REMOVE_DEVICE is sent to all devices that will be removed in response to a removal/ejection
- If any of the IRP_MN_QUERY_REMOVE_DEVICE requests fail, all devices which received a IRP_MN_QUERY_REMOVE_DEVICE will receive IRP_MN_CANCEL_REMOVE_DEVICE
- If everything approves the remove request, IRP_MN_REMOVE_DEVICE will be sent to children, ejection and/or removal relations, and finally the device itself
- Handle removal relations for all devices not just 1st level devices
- Remove child devices before removing the parent
- Move GUID_DEVICE_REMOVE_PENDING and GUID_DEVICE_REMOVAL_VETOED notifications to IopQueryRemoveDevice
- Implement IopCancelRemoveDevice which sends IRP_MN_CANCEL_REMOVE_DEVICE to the driver stack and sends GUID_TARGET_DEVICE_REMOVE_CANCELLED to any drivers waiting on target device change
- Use the IopRemoveDevice function to remove devices instead of calling IopQueryRemoveDevice and IopSendRemoveDevice manually so removal and/or ejection relations and children are processed
- IRPs and PnP notifications sent upon device removal (surprise and safe) should now be compatible with XP/Vista/7

Modified:
    trunk/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c

Modified: trunk/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c?rev=52046&r1=52045&r2=52046&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c [iso-8859-1] Wed Jun  1 19:32:12 2011
@@ -45,6 +45,12 @@
                        IN ULONG CreateOptions,
                        OUT PHANDLE Handle);
 
+VOID
+IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject);
+
+NTSTATUS
+IopPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject);
+
 PDEVICE_NODE
 FASTCALL
 IopGetDeviceNode(PDEVICE_OBJECT DeviceObject)
@@ -125,6 +131,7 @@
    return STATUS_SUCCESS;
 }
 
+static
 NTSTATUS
 NTAPI
 IopSendEject(IN PDEVICE_OBJECT DeviceObject)
@@ -139,6 +146,7 @@
     return IopSynchronousCall(DeviceObject, &Stack, &Dummy); 
 }
 
+static
 VOID
 NTAPI
 IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject)
@@ -154,13 +162,20 @@
     IopSynchronousCall(DeviceObject, &Stack, &Dummy);
 }
 
+static
 NTSTATUS
 NTAPI
 IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
 {
+    PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
     IO_STACK_LOCATION Stack;
     PVOID Dummy;
     NTSTATUS Status;
+    
+    ASSERT(DeviceNode);
+    
+    IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING,
+                              &DeviceNode->InstancePath);
     
     RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
     Stack.MajorFunction = IRP_MJ_PNP;
@@ -173,10 +188,18 @@
                                   &GUID_TARGET_DEVICE_QUERY_REMOVE,
                                   NULL,
                                   NULL);
+    
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Removal vetoed by %wZ\n", &DeviceNode->InstancePath);
+        IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED,
+                                  &DeviceNode->InstancePath);
+    }
 
     return Status;
 }
 
+static
 NTSTATUS
 NTAPI
 IopQueryStopDevice(IN PDEVICE_OBJECT DeviceObject)
@@ -191,6 +214,7 @@
     return IopSynchronousCall(DeviceObject, &Stack, &Dummy);
 }
 
+static
 VOID
 NTAPI
 IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
@@ -212,6 +236,29 @@
                                   NULL);
 }
 
+static
+VOID
+NTAPI
+IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
+{
+    IO_STACK_LOCATION Stack;
+    PVOID Dummy;
+    
+    RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
+    Stack.MajorFunction = IRP_MJ_PNP;
+    Stack.MinorFunction = IRP_MN_CANCEL_REMOVE_DEVICE;
+    
+    /* 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);
+}
+
+static
 VOID
 NTAPI
 IopSendStopDevice(IN PDEVICE_OBJECT DeviceObject)
@@ -257,7 +304,7 @@
     if (!NT_SUCCESS(Status))
     {
         /* Send an IRP_MN_REMOVE_DEVICE request */
-        IopSendRemoveDevice(DeviceObject);
+        IopRemoveDevice(DeviceNode);
 
         /* Set the appropriate flag */
         DeviceNode->Flags |= DNF_START_FAILED;
@@ -3721,7 +3768,7 @@
             DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING);
             DeviceNode->Flags |= DNF_START_FAILED;
 
-            IopSendRemoveDevice(PhysicalDeviceObject);
+            IopRemoveDevice(DeviceNode);
         }
     }
 }
@@ -3881,8 +3928,213 @@
    return Status;
 }
 
+static
 NTSTATUS
-NTAPI
+IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
+{
+    PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice;
+    NTSTATUS Status;
+    KIRQL OldIrql;
+    
+    KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
+    ChildDeviceNode = ParentDeviceNode->Child;
+    while (ChildDeviceNode != NULL)
+    {
+        NextDeviceNode = ChildDeviceNode->Sibling;
+        KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
+        
+        Status = IopPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject);
+        if (!NT_SUCCESS(Status))
+        {
+            FailedRemoveDevice = ChildDeviceNode;
+            goto cleanup;
+        }
+        
+        KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
+        ChildDeviceNode = NextDeviceNode;
+    }
+    KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
+    
+    return STATUS_SUCCESS;
+    
+cleanup:
+    KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
+    ChildDeviceNode = ParentDeviceNode->Child;
+    while (ChildDeviceNode != NULL)
+    {
+        NextDeviceNode = ChildDeviceNode->Sibling;
+        KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
+        
+        IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject);
+        
+        /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
+         * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
+        if (ChildDeviceNode == FailedRemoveDevice)
+            return Status;
+        
+        ChildDeviceNode = NextDeviceNode;
+        
+        KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
+    }
+    KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
+    
+    return Status;
+}
+
+static
+VOID
+IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
+{
+    PDEVICE_NODE ChildDeviceNode, NextDeviceNode;
+    KIRQL OldIrql;
+    
+    KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
+    ChildDeviceNode = ParentDeviceNode->Child;
+    while (ChildDeviceNode != NULL)
+    {
+        NextDeviceNode = ChildDeviceNode->Sibling;
+        KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
+        
+        IopSendRemoveDevice(ChildDeviceNode->PhysicalDeviceObject);
+        
+        ChildDeviceNode = NextDeviceNode;
+        
+        KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
+    }
+    KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
+}
+
+static
+VOID
+IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
+{
+    PDEVICE_NODE ChildDeviceNode, NextDeviceNode;
+    KIRQL OldIrql;
+    
+    KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
+    ChildDeviceNode = ParentDeviceNode->Child;
+    while (ChildDeviceNode != NULL)
+    {
+        NextDeviceNode = ChildDeviceNode->Sibling;
+        KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
+        
+        IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject);
+        
+        ChildDeviceNode = NextDeviceNode;
+        
+        KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
+    }
+    KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
+}
+
+static
+NTSTATUS
+IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
+{
+    /* This function DOES NOT dereference the device objects on SUCCESS
+     * but it DOES dereference device objects on FAILURE */
+    
+    ULONG i, j;
+    NTSTATUS Status;
+    
+    for (i = 0; i < DeviceRelations->Count; i++)
+    {
+        Status = IopPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
+        if (!NT_SUCCESS(Status))
+        {
+            j = i;
+            goto cleanup;
+        }
+    }
+    
+    return STATUS_SUCCESS;
+    
+cleanup:
+    /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
+     * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
+    for (i = 0; i <= j; i++)
+    {
+        IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
+        ObDereferenceObject(DeviceRelations->Objects[i]);
+        DeviceRelations->Objects[i] = NULL;
+    }
+    for (; i < DeviceRelations->Count; i++)
+    {
+        ObDereferenceObject(DeviceRelations->Objects[i]);
+        DeviceRelations->Objects[i] = NULL;
+    }
+    ExFreePool(DeviceRelations);
+    
+    return Status;
+}
+
+static
+VOID
+IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
+{
+    /* This function DOES dereference the device objects in all cases */
+    
+    ULONG i;
+    
+    for (i = 0; i < DeviceRelations->Count; i++)
+    {
+        IopSendRemoveDevice(DeviceRelations->Objects[i]);
+        ObDereferenceObject(DeviceRelations->Objects[i]);
+        DeviceRelations->Objects[i] = NULL;
+    }
+    
+    ExFreePool(DeviceRelations);
+}
+
+static
+VOID
+IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
+{
+    /* This function DOES dereference the device objects in all cases */
+    
+    ULONG i;
+    
+    for (i = 0; i < DeviceRelations->Count; i++)
+    {
+        IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
+        ObDereferenceObject(DeviceRelations->Objects[i]);
+        DeviceRelations->Objects[i] = NULL;
+    }
+    
+    ExFreePool(DeviceRelations);
+}
+
+VOID
+IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject)
+{
+    IO_STACK_LOCATION Stack;
+    IO_STATUS_BLOCK IoStatusBlock;
+    PDEVICE_RELATIONS DeviceRelations;
+    NTSTATUS Status;
+    
+    IopCancelRemoveDevice(DeviceObject);
+    
+    Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
+    
+    Status = IopInitiatePnpIrp(DeviceObject,
+                               &IoStatusBlock,
+                               IRP_MN_QUERY_DEVICE_RELATIONS,
+                               &Stack);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
+        DeviceRelations = NULL;
+    }
+    else
+    {
+        DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
+    }
+    
+    if (DeviceRelations)
+        IopCancelRemoveDeviceRelations(DeviceRelations);
+}
+
+NTSTATUS
 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject)
 {
     PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
@@ -3890,7 +4142,6 @@
     IO_STATUS_BLOCK IoStatusBlock;
     PDEVICE_RELATIONS DeviceRelations;
     NTSTATUS Status;
-    ULONG i;
 
     if (DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE)
     {
@@ -3898,15 +4149,9 @@
         return STATUS_UNSUCCESSFUL;
     }
     
-    IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING,
-                              &DeviceNode->InstancePath);
-    
     if (IopQueryRemoveDevice(DeviceObject) != STATUS_SUCCESS)
     {
         DPRINT1("Removal vetoed by failing the query remove request\n");
-        
-        IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED,
-                                  &DeviceNode->InstancePath);
         
         return STATUS_UNSUCCESSFUL;
     }
@@ -3929,51 +4174,24 @@
     
     if (DeviceRelations)
     {
-        for (i = 0; i < DeviceRelations->Count; i++)
-        {
-            PDEVICE_NODE RelationsDeviceNode = IopGetDeviceNode(DeviceRelations->Objects[i]);
-            
-            IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING,
-                                      &RelationsDeviceNode->InstancePath);
-            
-            if (IopRemoveDevice(RelationsDeviceNode) != STATUS_SUCCESS)
-            {
-                DPRINT1("Device removal vetoed by failing a dependent query remove request\n");
-                
-                Status = STATUS_UNSUCCESSFUL;
-                
-                goto cleanup;
-            }
-            else
-            {
-                ObDereferenceObject(DeviceRelations->Objects[i]);
-                
-                DeviceRelations->Objects[i] = NULL;
-            }
-        }
-        
-        ExFreePool(DeviceRelations);
-        
-        DeviceRelations = NULL;
-    }
-    
-    Status = STATUS_SUCCESS;
-    
-cleanup:
+        Status = IopQueryRemoveDeviceRelations(DeviceRelations);
+        if (!NT_SUCCESS(Status))
+            return Status;
+    }
+    
+    Status = IopQueryRemoveChildDevices(DeviceNode);
+    if (!NT_SUCCESS(Status))
+    {
+        if (DeviceRelations)
+            IopCancelRemoveDeviceRelations(DeviceRelations);
+        return Status;
+    }
+    
     if (DeviceRelations)
-    {
-        for (i = 0; i < DeviceRelations->Count; i++)
-        {
-            if (DeviceRelations->Objects[i])
-            {
-                ObDereferenceObject(DeviceRelations->Objects[i]);
-            }
-        }
-        
-        ExFreePool(DeviceRelations);
-    }
-
-    return Status;
+        IopSendRemoveDeviceRelations(DeviceRelations);
+    IopSendRemoveChildDevices(DeviceNode);
+    
+    return STATUS_SUCCESS;
 }
 
 NTSTATUS
@@ -3992,9 +4210,6 @@
         DeviceNode->Flags |= DNF_WILL_BE_REMOVED;
         return STATUS_SUCCESS;
     }
-
-    IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED,
-                              &DeviceNode->InstancePath);
 
     return Status;
 }
@@ -4012,16 +4227,13 @@
     IO_STACK_LOCATION Stack;
     DEVICE_CAPABILITIES Capabilities;
     NTSTATUS Status;
-    ULONG i;
     
     IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT,
                               &DeviceNode->InstancePath);
     
     if (IopQueryDeviceCapabilities(DeviceNode, &Capabilities) != STATUS_SUCCESS)
     {
-       IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED,
-                                 &DeviceNode->InstancePath);
-       return;
+        goto cleanup;
     }
     
     Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations;
@@ -4042,47 +4254,36 @@
     
     if (DeviceRelations)
     {
-        for (i = 0; i < DeviceRelations->Count; i++)
-        {
-            PDEVICE_NODE RelationsDeviceNode = IopGetDeviceNode(DeviceRelations->Objects[i]);
-            
-            IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING,
-                                      &RelationsDeviceNode->InstancePath);
-            
-            if (IopRemoveDevice(RelationsDeviceNode) != STATUS_SUCCESS)
-            {
-                DPRINT1("Device removal vetoed by failing a query remove request (ejection relations)\n");
-
-                goto cleanup;
-            }
-            else
-            {
-                ObDereferenceObject(DeviceRelations->Objects[i]);
-                
-                DeviceRelations->Objects[i] = NULL;
-            }
-        }
-        
-        ExFreePool(DeviceRelations);
-        
-        DeviceRelations = NULL;
+        Status = IopQueryRemoveDeviceRelations(DeviceRelations);
+        if (!NT_SUCCESS(Status))
+            goto cleanup;
+    }
+    
+    Status = IopQueryRemoveChildDevices(DeviceNode);
+    if (!NT_SUCCESS(Status))
+    {
+        if (DeviceRelations)
+            IopCancelRemoveDeviceRelations(DeviceRelations);
+        goto cleanup;
     }
     
     if (IopPrepareDeviceForRemoval(PhysicalDeviceObject) != STATUS_SUCCESS)
     {
-        IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED,
-                                  &DeviceNode->InstancePath);
-        return;
-    }
+        if (DeviceRelations)
+            IopCancelRemoveDeviceRelations(DeviceRelations);
+        IopCancelRemoveChildDevices(DeviceNode);
+        goto cleanup;
+    }
+    
+    if (DeviceRelations)
+        IopSendRemoveDeviceRelations(DeviceRelations);
+    IopSendRemoveChildDevices(DeviceNode);
     
     if (Capabilities.EjectSupported)
     {
         if (IopSendEject(PhysicalDeviceObject) != STATUS_SUCCESS)
         {
-            IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED,
-                                      &DeviceNode->InstancePath);
-
-            return;
+            goto cleanup;
         }
     }
     else
@@ -4090,27 +4291,14 @@
         DeviceNode->Flags |= DNF_DISABLED;
     }
     
+    IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT,
+                              &DeviceNode->InstancePath);
+    
+    return;
+    
 cleanup:
-    if (DeviceRelations)
-    {
-        for (i = 0; i < DeviceRelations->Count; i++)
-        {
-            if (DeviceRelations->Objects[i])
-            {
-                ObDereferenceObject(DeviceRelations->Objects[i]);
-            }
-        }
-        
-        ExFreePool(DeviceRelations);
-
-        IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED,
-                                  &DeviceNode->InstancePath);
-    }
-    else
-    {
-        IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT,
-                                  &DeviceNode->InstancePath);
-    }
+    IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED,
+                              &DeviceNode->InstancePath);
 }
 
 /*




More information about the Ros-diffs mailing list