[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / io / iomgr / device.c
index 53cdd43..88e5ba4 100644 (file)
 
 #include <ntoskrnl.h>
 #define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
 
 /* GLOBALS ********************************************************************/
 
 ULONG IopDeviceObjectNumber = 0;
-
 LIST_ENTRY ShutdownListHead, LastChanceShutdownListHead;
 KSPIN_LOCK ShutdownListLock;
+extern LIST_ENTRY IopDiskFsListHead;
+extern LIST_ENTRY IopCdRomFsListHead;
+extern LIST_ENTRY IopTapeFsListHead;
 
 /* PRIVATE FUNCTIONS **********************************************************/
 
 VOID
 NTAPI
-IoShutdownRegisteredDevices(VOID)
+IopReadyDeviceObjects(IN PDRIVER_OBJECT Driver)
+{
+    PDEVICE_OBJECT DeviceObject;
+    PAGED_CODE();
+
+    /* Set the driver as initialized */
+    Driver->Flags |= DRVO_INITIALIZED;
+    DeviceObject = Driver->DeviceObject;
+    while (DeviceObject)
+    {
+        /* Set every device as initialized too */
+        DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+        DeviceObject = DeviceObject->NextDevice;
+    }
+}
+
+VOID
+NTAPI
+IopDeleteDevice(IN PVOID ObjectBody)
+{
+    PDEVICE_OBJECT DeviceObject = ObjectBody;
+    PAGED_CODE();
+    /* TODO: Delete Device Node */
+
+    /* Dereference the driver object, referenced in IoCreateDevice */
+    if (DeviceObject->DriverObject)
+        ObDereferenceObject(DeviceObject->DriverObject);
+}
+
+
+PDEVICE_OBJECT
+NTAPI
+IopAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice,
+                                 IN PDEVICE_OBJECT TargetDevice,
+                                 OUT PDEVICE_OBJECT *AttachedToDeviceObject OPTIONAL)
+{
+    PDEVICE_OBJECT AttachedDevice;
+    PEXTENDED_DEVOBJ_EXTENSION SourceDeviceExtension;
+
+    /* Get the Attached Device and source extension */
+    AttachedDevice = IoGetAttachedDevice(TargetDevice);
+    SourceDeviceExtension = IoGetDevObjExtension(SourceDevice);
+    ASSERT(SourceDeviceExtension->AttachedTo == NULL);
+
+    /* Make sure that it's in a correct state */
+    if ((AttachedDevice->Flags & DO_DEVICE_INITIALIZING) ||
+        (IoGetDevObjExtension(AttachedDevice)->ExtensionFlags &
+         (DOE_UNLOAD_PENDING |
+          DOE_DELETE_PENDING |
+          DOE_REMOVE_PENDING |
+          DOE_REMOVE_PROCESSED)))
+    {
+        /* Device was unloading or being removed */
+        AttachedDevice = NULL;
+    }
+    else
+    {
+        /* Update atached device fields */
+        AttachedDevice->AttachedDevice = SourceDevice;
+        AttachedDevice->Spare1++;
+
+        /* Update the source with the attached data */
+        SourceDevice->StackSize = AttachedDevice->StackSize + 1;
+        SourceDevice->AlignmentRequirement = AttachedDevice->
+                                             AlignmentRequirement;
+        SourceDevice->SectorSize = AttachedDevice->SectorSize;
+
+        /* Check for pending start flag */
+        if (IoGetDevObjExtension(AttachedDevice)->ExtensionFlags &
+            DOE_START_PENDING)
+        {
+            /* Propagate */
+            IoGetDevObjExtension(SourceDevice)->ExtensionFlags |=
+                DOE_START_PENDING;
+        }
+
+        /* Set the attachment in the device extension */
+        SourceDeviceExtension->AttachedTo = AttachedDevice;
+    }
+
+    /* Return the attached device */
+    if (AttachedToDeviceObject) *AttachedToDeviceObject = AttachedDevice;
+    return AttachedDevice;
+}
+
+VOID
+NTAPI
+IoShutdownPnpDevices(VOID)
+{
+    /* This routine is only used by Driver Verifier to validate shutdown */
+    return;
+}
+
+VOID
+NTAPI
+IoShutdownSystem(IN ULONG Phase)
 {
     PLIST_ENTRY ListEntry;
     PDEVICE_OBJECT DeviceObject;
@@ -34,46 +132,108 @@ IoShutdownRegisteredDevices(VOID)
     PIRP Irp;
     KEVENT Event;
     NTSTATUS Status;
-
+        
     /* Initialize an event to wait on */
     KeInitializeEvent(&Event, NotificationEvent, FALSE);
-
-    /* Get the first entry and start looping */
-    ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
-                                            &ShutdownListLock);
-    while (ListEntry)
+    
+    /* What phase? */
+    if (Phase == 0)
     {
-        /* Get the shutdown entry */
-        ShutdownEntry = CONTAINING_RECORD(ListEntry,
-                                          SHUTDOWN_ENTRY,
-                                          ShutdownList);
+        /* Shutdown PnP */
+        IoShutdownPnpDevices();
 
-        /* Get the attached device */
-        DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject);
-
-        /* Build the shutdown IRP and call the driver */
-        Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
-                                           DeviceObject,
-                                           NULL,
-                                           0,
-                                           NULL,
-                                           &Event,
-                                           &StatusBlock);
-        Status = IoCallDriver(DeviceObject, Irp);
-        if (Status == STATUS_PENDING)
+        /* Loop first-chance shutdown notifications */
+        ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
+                                                &ShutdownListLock);
+        while (ListEntry)
         {
-            /* Wait on the driver */
-            KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
-        }
+            /* Get the shutdown entry */
+            ShutdownEntry = CONTAINING_RECORD(ListEntry,
+                                              SHUTDOWN_ENTRY,
+                                              ShutdownList);
+
+            /* Get the attached device */
+            DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject);
+
+            /* Build the shutdown IRP and call the driver */
+            Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
+                                               DeviceObject,
+                                               NULL,
+                                               0,
+                                               NULL,
+                                               &Event,
+                                               &StatusBlock);
+            Status = IoCallDriver(DeviceObject, Irp);
+            if (Status == STATUS_PENDING)
+            {
+                /* Wait on the driver */
+                KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+            }
 
-        /* Free the shutdown entry and reset the event */
-        ExFreePool(ShutdownEntry);
-        KeClearEvent(&Event);
+            /* Get rid of our reference to it */
+            ObDereferenceObject(DeviceObject);
+            
+            /* Free the shutdown entry and reset the event */
+            ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
+            KeClearEvent(&Event);
+
+            /* Go to the next entry */
+            ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
+                                                    &ShutdownListLock);
+         }
+    }
+    else if (Phase == 1)
+    {
+        /* Shutdown disk file systems */
+        IopShutdownBaseFileSystems(&IopDiskFsListHead);
 
-        /* Go to the next entry */
-        ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
+        /* Shutdown cdrom file systems */
+        IopShutdownBaseFileSystems(&IopCdRomFsListHead);
+
+        /* Shutdown tape filesystems */
+        IopShutdownBaseFileSystems(&IopTapeFsListHead);
+        
+        /* Loop last-chance shutdown notifications */
+        ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead,
                                                 &ShutdownListLock);
-     }
+        while (ListEntry)
+        {
+            /* Get the shutdown entry */
+            ShutdownEntry = CONTAINING_RECORD(ListEntry,
+                                              SHUTDOWN_ENTRY,
+                                              ShutdownList);
+
+            /* Get the attached device */
+            DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject);
+
+            /* Build the shutdown IRP and call the driver */
+            Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
+                                               DeviceObject,
+                                               NULL,
+                                               0,
+                                               NULL,
+                                               &Event,
+                                               &StatusBlock);
+            Status = IoCallDriver(DeviceObject, Irp);
+            if (Status == STATUS_PENDING)
+            {
+                /* Wait on the driver */
+                KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+            }
+
+            /* Get rid of our reference to it */
+            ObDereferenceObject(DeviceObject);
+            
+            /* Free the shutdown entry and reset the event */
+            ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
+            KeClearEvent(&Event);
+
+            /* Go to the next entry */
+            ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead,
+                                                    &ShutdownListLock);
+         }
+
+    }
 }
 
 NTSTATUS
@@ -93,7 +253,7 @@ IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName,
     /* Open the Device */
     InitializeObjectAttributes(&ObjectAttributes,
                                ObjectName,
-                               0,
+                               OBJ_KERNEL_HANDLE,
                                NULL,
                                NULL);
     Status = ZwOpenFile(&FileHandle,
@@ -116,10 +276,11 @@ IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName,
         /* Return the requested data */
         *DeviceObject = IoGetRelatedDeviceObject(LocalFileObject);
         *FileObject = LocalFileObject;
-        ZwClose(FileHandle);
     }
 
     /* Close the handle */
+    ZwClose(FileHandle);
+
     return Status;
 }
 
@@ -261,7 +422,7 @@ IopUnloadDevice(IN PDEVICE_OBJECT DeviceObject)
         if (DeviceObject->SecurityDescriptor)
         {
             /* Free it */
-            ExFreePool(DeviceObject->SecurityDescriptor);
+            ExFreePoolWithTag(DeviceObject->SecurityDescriptor, TAG_SD);
         }
 
         /* Remove the device from the list */
@@ -300,6 +461,13 @@ IopUnloadDevice(IN PDEVICE_OBJECT DeviceObject)
 
     /* Unload it */
     if (DriverObject->DriverUnload) DriverObject->DriverUnload(DriverObject);
+
+    /* Make object temporary so it can be deleted */
+    ObMakeTemporaryObject(DriverObject);
+
+    /* Dereference once more, referenced at driver object creation */
+    ObDereferenceObject(DriverObject);
+
 }
 
 VOID
@@ -329,32 +497,6 @@ IopDereferenceDeviceObject(IN PDEVICE_OBJECT DeviceObject,
     }
 }
 
-NTSTATUS
-NTAPI
-IopReferenceDeviceObject(IN PDEVICE_OBJECT DeviceObject)
-{
-    /* Make sure the object is valid */
-    if ((IoGetDevObjExtension(DeviceObject)->ExtensionFlags &
-        (DOE_UNLOAD_PENDING |
-         DOE_DELETE_PENDING |
-         DOE_REMOVE_PENDING |
-         DOE_REMOVE_PROCESSED)) ||
-        (DeviceObject->Flags & DO_DEVICE_INITIALIZING))
-    {
-        /* It's unloading or initializing, so fail */
-        DPRINT1("You are seeing this because the following ROS driver: %wZ\n"
-                " sucks. Please fix it's AddDevice Routine\n",
-                &DeviceObject->DriverObject->DriverName);
-        return STATUS_NO_SUCH_DEVICE;
-    }
-    else
-    {
-        /* Increase reference count */
-        DeviceObject->ReferenceCount++;
-        return STATUS_SUCCESS;
-    }
-}
-
 VOID
 NTAPI
 IopStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject,
@@ -489,14 +631,16 @@ IopStartNextPacketByKeyEx(IN PDEVICE_OBJECT DeviceObject,
             {
                 /* Start the packet with a key */
                 IopStartNextPacketByKey(DeviceObject,
-                                        (DOE_SIO_CANCELABLE) ? TRUE : FALSE,
+                                        (Flags & DOE_SIO_CANCELABLE) ?
+                                        TRUE : FALSE,
                                         CurrentKey);
             }
             else if (Flags & DOE_SIO_NO_KEY)
             {
                 /* Start the packet */
                 IopStartNextPacket(DeviceObject,
-                                   (DOE_SIO_CANCELABLE) ? TRUE : FALSE);
+                                   (Flags & DOE_SIO_CANCELABLE) ?
+                                   TRUE : FALSE);
             }
         }
 
@@ -520,6 +664,48 @@ IopStartNextPacketByKeyEx(IN PDEVICE_OBJECT DeviceObject,
     }
 }
 
+NTSTATUS
+NTAPI
+IopGetRelatedTargetDevice(IN PFILE_OBJECT FileObject,
+                          OUT PDEVICE_NODE *DeviceNode)
+{
+    NTSTATUS Status;
+    IO_STACK_LOCATION Stack = {0};
+    PDEVICE_RELATIONS DeviceRelations;
+    PDEVICE_OBJECT DeviceObject = NULL;
+
+    ASSERT(FileObject);
+
+    /* Get DeviceObject related to given FileObject */
+    DeviceObject = IoGetRelatedDeviceObject(FileObject);
+    if (!DeviceObject) return STATUS_NO_SUCH_DEVICE;
+
+    /* Define input parameters */
+    Stack.MajorFunction = IRP_MJ_PNP;
+    Stack.MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
+    Stack.Parameters.QueryDeviceRelations.Type = TargetDeviceRelation;
+    Stack.FileObject = FileObject;
+
+    /* Call the driver to query all relations (IRP_MJ_PNP) */
+    Status = IopSynchronousCall(DeviceObject,
+                                &Stack,
+                                (PVOID)&DeviceRelations);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Make sure it's not NULL and contains only one object */
+    ASSERT(DeviceRelations);
+    ASSERT(DeviceRelations->Count == 1);
+
+    /* Finally get the device node */
+    *DeviceNode = IopGetDeviceNode(DeviceRelations->Objects[0]);
+    if (!*DeviceNode) Status = STATUS_NO_SUCH_DEVICE;
+
+    /* Free the DEVICE_RELATIONS structure, it's not needed anymore */
+    ExFreePool(DeviceRelations);
+
+    return Status;
+}
+
 /* PUBLIC FUNCTIONS ***********************************************************/
 
 /*
@@ -562,7 +748,6 @@ IoAttachDevice(PDEVICE_OBJECT SourceDevice,
     Status = IoAttachDeviceToDeviceStackSafe(SourceDevice,
                                              TargetDevice,
                                              AttachedDevice);
-    if (!*AttachedDevice) Status = STATUS_NO_SUCH_DEVICE;
 
     /* Dereference it */
     ObDereferenceObject(FileObject);
@@ -592,26 +777,17 @@ IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice,
 }
 
 /*
- * IoAttachDeviceToDeviceStack
- *
- * Status
- *    @implemented
+ * @implemented
  */
 PDEVICE_OBJECT
 NTAPI
-IoAttachDeviceToDeviceStack(PDEVICE_OBJECT SourceDevice,
-                            PDEVICE_OBJECT TargetDevice)
+IoAttachDeviceToDeviceStack(IN PDEVICE_OBJECT SourceDevice,
+                            IN PDEVICE_OBJECT TargetDevice)
 {
-    NTSTATUS Status;
-    PDEVICE_OBJECT LocalAttach;
-
     /* Attach it safely */
-    Status = IoAttachDeviceToDeviceStackSafe(SourceDevice,
-                                             TargetDevice,
-                                             &LocalAttach);
-
-    /* Return it */
-    return LocalAttach;
+    return IopAttachDeviceToDeviceStackSafe(SourceDevice,
+                                            TargetDevice,
+                                            NULL);
 }
 
 /*
@@ -621,43 +797,18 @@ NTSTATUS
 NTAPI
 IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice,
                                 IN PDEVICE_OBJECT TargetDevice,
-                                OUT PDEVICE_OBJECT *AttachedToDeviceObject)
+                                IN OUT PDEVICE_OBJECT *AttachedToDeviceObject)
 {
-    PDEVICE_OBJECT AttachedDevice;
-    PEXTENDED_DEVOBJ_EXTENSION SourceDeviceExtension;
-
-    /* Get the Attached Device and source extension */
-    AttachedDevice = IoGetAttachedDevice(TargetDevice);
-    SourceDeviceExtension = IoGetDevObjExtension(SourceDevice);
-
-    /* Make sure that it's in a correct state */
-    if (!IoGetDevObjExtension(AttachedDevice)->ExtensionFlags &
-        (DOE_UNLOAD_PENDING |
-         DOE_DELETE_PENDING |
-         DOE_REMOVE_PENDING |
-         DOE_REMOVE_PROCESSED))
-    {
-        /* Update atached device fields */
-        AttachedDevice->AttachedDevice = SourceDevice;
-        AttachedDevice->Spare1++;
-
-        /* Update the source with the attached data */
-        SourceDevice->StackSize = AttachedDevice->StackSize + 1;
-        SourceDevice->AlignmentRequirement = AttachedDevice->
-                                             AlignmentRequirement;
-        SourceDevice->SectorSize = AttachedDevice->SectorSize;
-
-        /* Set the attachment in the device extension */
-        SourceDeviceExtension->AttachedTo = AttachedDevice;
-    }
-    else
+    /* Call the internal function */
+    if (!IopAttachDeviceToDeviceStackSafe(SourceDevice,
+                                          TargetDevice,
+                                          AttachedToDeviceObject))
     {
-        /* Device was unloading or being removed */
-        AttachedDevice = NULL;
+        /* Nothing found */
+        return STATUS_NO_SUCH_DEVICE;
     }
 
-    /* Return the attached device */
-    *AttachedToDeviceObject = AttachedDevice;
+    /* Success! */
     return STATUS_SUCCESS;
 }
 
@@ -728,7 +879,11 @@ IoCreateDevice(IN PDRIVER_OBJECT DriverObject,
    }
 
     /* Initialize the Object Attributes */
-    InitializeObjectAttributes(&ObjectAttributes, DeviceName, 0, NULL, NULL);
+    InitializeObjectAttributes(&ObjectAttributes,
+                               DeviceName,
+                               OBJ_KERNEL_HANDLE,
+                               NULL,
+                               NULL);
 
     /* Honor exclusive flag */
     if (Exclusive) ObjectAttributes.Attributes |= OBJ_EXCLUSIVE;
@@ -765,7 +920,7 @@ IoCreateDevice(IN PDRIVER_OBJECT DriverObject,
      * because that's only padding for the DevObjExt and not part of the Object.
      */
     CreatedDeviceObject->Type = IO_TYPE_DEVICE;
-    CreatedDeviceObject->Size = sizeof(DEVICE_OBJECT) + DeviceExtensionSize;
+    CreatedDeviceObject->Size = sizeof(DEVICE_OBJECT) + (USHORT)DeviceExtensionSize;
 
     /* The kernel extension is after the driver internal extension */
     DeviceObjectExtension = (PDEVOBJ_EXTENSION)
@@ -775,6 +930,9 @@ IoCreateDevice(IN PDRIVER_OBJECT DriverObject,
     /* Set the Type and Size. Question: why is Size 0 on Windows? */
     DeviceObjectExtension->Type = IO_TYPE_DEVICE_OBJECT_EXTENSION;
     DeviceObjectExtension->Size = 0;
+    
+    /* Initialize with Power Manager */
+    PoInitializeDeviceObject(DeviceObjectExtension);
 
     /* Link the Object and Extension */
     DeviceObjectExtension->DeviceObject = CreatedDeviceObject;
@@ -795,13 +953,19 @@ IoCreateDevice(IN PDRIVER_OBJECT DriverObject,
     if (DeviceName) CreatedDeviceObject->Flags |= DO_DEVICE_HAS_NAME;
 
     /* Attach a Vpb for Disks and Tapes, and create the Device Lock */
-    if (CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK ||
-        CreatedDeviceObject->DeviceType == FILE_DEVICE_VIRTUAL_DISK ||
-        CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM ||
-        CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE)
+    if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK) ||
+        (CreatedDeviceObject->DeviceType == FILE_DEVICE_VIRTUAL_DISK) ||
+        (CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) ||
+        (CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE))
     {
         /* Create Vpb */
-        IopCreateVpb(CreatedDeviceObject);
+        Status = IopCreateVpb(CreatedDeviceObject);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Reference the device object and fail */
+            ObDereferenceObject(DeviceObject);
+            return Status;
+        }
 
         /* Initialize Lock Event */
         KeInitializeEvent(&CreatedDeviceObject->DeviceLock,
@@ -829,11 +993,11 @@ IoCreateDevice(IN PDRIVER_OBJECT DriverObject,
     }
 
     /* Create the Device Queue */
-    if (CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM ||
-        CreatedDeviceObject->DeviceType == FILE_DEVICE_FILE_SYSTEM ||
-        CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM ||
-        CreatedDeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM ||
-        CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM)
+    if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) ||
+        (CreatedDeviceObject->DeviceType == FILE_DEVICE_FILE_SYSTEM) ||
+        (CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) ||
+        (CreatedDeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) ||
+        (CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM))
     {
         /* Simple FS Devices, they don't need a real Device Queue */
         InitializeListHead(&CreatedDeviceObject->Queue.ListEntry);
@@ -851,20 +1015,19 @@ IoCreateDevice(IN PDRIVER_OBJECT DriverObject,
                             1,
                             (PVOID*)&CreatedDeviceObject,
                             &TempHandle);
-    if (!NT_SUCCESS(Status))
-    {
-        /* Clear the device object and fail */
-        *DeviceObject = NULL;
-        return Status;
-    }
+    if (!NT_SUCCESS(Status)) return Status;
 
     /* Now do the final linking */
     ObReferenceObject(DriverObject);
+    ASSERT((DriverObject->Flags & DRVO_UNLOAD_INVOKED) == 0);
     CreatedDeviceObject->DriverObject = DriverObject;
     IopEditDeviceList(DriverObject, CreatedDeviceObject, IopAdd);
+    
+    /* Link with the power manager */
+    if (CreatedDeviceObject->Vpb) PoVolumeDevice(CreatedDeviceObject);
 
     /* Close the temporary handle and return to caller */
-    NtClose(TempHandle);
+    ObCloseHandle(TempHandle, KernelMode);
     *DeviceObject = CreatedDeviceObject;
     return STATUS_SUCCESS;
 }
@@ -921,8 +1084,14 @@ VOID
 NTAPI
 IoDetachDevice(IN PDEVICE_OBJECT TargetDevice)
 {
+    PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
+
+    /* Sanity check */
+    DeviceExtension = IoGetDevObjExtension(TargetDevice->AttachedDevice);
+    ASSERT(DeviceExtension->AttachedTo == TargetDevice);
+
     /* Remove the attachment */
-    IoGetDevObjExtension(TargetDevice->AttachedDevice)->AttachedTo = NULL;
+    DeviceExtension->AttachedTo = NULL;
     TargetDevice->AttachedDevice = NULL;
 
     /* Check if it's ok to delete this device */
@@ -1031,8 +1200,10 @@ PDEVICE_OBJECT
 NTAPI
 IoGetDeviceAttachmentBaseRef(IN PDEVICE_OBJECT DeviceObject)
 {
-    /* Return the attached Device */
-    return IoGetDevObjExtension(DeviceObject)->AttachedTo;
+    /* Reference the lowest attached device */
+    DeviceObject = IopGetLowestDevice(DeviceObject);
+    ObReferenceObject(DeviceObject);
+    return DeviceObject;
 }
 
 /*
@@ -1096,7 +1267,7 @@ IoGetDiskDeviceObject(IN PDEVICE_OBJECT FileSystemDeviceObject,
         else
         {
             /* It's not, so return failure */
-            return STATUS_VOLUME_DISMOUNTED;
+            Status = STATUS_VOLUME_DISMOUNTED;
         }
     }
     else
@@ -1122,16 +1293,20 @@ IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject)
 
     /* Make sure it's not getting deleted */
     DeviceExtension = IoGetDevObjExtension(DeviceObject);
-    if (DeviceExtension->ExtensionFlags & (DOE_UNLOAD_PENDING |
+    if (!(DeviceExtension->ExtensionFlags & (DOE_UNLOAD_PENDING |
                                            DOE_DELETE_PENDING |
                                            DOE_REMOVE_PENDING |
-                                           DOE_REMOVE_PROCESSED))
+                                           DOE_REMOVE_PROCESSED)))
     {
         /* Get the Lower Device Object */
         LowerDeviceObject = DeviceExtension->AttachedTo;
 
-        /* Reference it */
-        ObReferenceObject(LowerDeviceObject);
+        /* Check that we got a valid device object */
+        if (LowerDeviceObject)
+        {
+            /* We did so let's reference it */
+            ObReferenceObject(LowerDeviceObject);
+        }
     }
 
     /* Return it */
@@ -1139,13 +1314,7 @@ IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject)
 }
 
 /*
- * IoGetRelatedDeviceObject
- *
- * Remarks
- *    See "Windows NT File System Internals", page 633 - 634.
- *
- * Status
- *    @implemented
+ * @implemented
  */
 PDEVICE_OBJECT
 NTAPI
@@ -1173,9 +1342,27 @@ IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject)
         DeviceObject = FileObject->DeviceObject;
     }
 
+    /* Sanity check */
+    ASSERT(DeviceObject != NULL);
+
     /* Check if we were attached */
     if (DeviceObject->AttachedDevice)
     {
+        /* Check if the file object has an extension present */
+        if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
+        {
+            /* Sanity check, direct open files can't have this */
+            ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
+
+            /* Check if the extension is really present */
+            if (FileObject->FileObjectExtension)
+            {
+                /* FIXME: Unhandled yet */
+                DPRINT1("FOEs not supported\n");
+                ASSERT(FALSE);
+            }
+        }
+
         /* Return the highest attached device */
         DeviceObject = IoGetAttachedDevice(DeviceObject);
     }
@@ -1184,6 +1371,26 @@ IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject)
     return DeviceObject;
 }
 
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+IoGetRelatedTargetDevice(IN PFILE_OBJECT FileObject,
+                         OUT PDEVICE_OBJECT *DeviceObject)
+{
+    NTSTATUS Status;
+    PDEVICE_NODE DeviceNode = NULL;
+
+    /* Call the internal helper function */
+    Status = IopGetRelatedTargetDevice(FileObject, &DeviceNode);
+    if (NT_SUCCESS(Status) && DeviceNode)
+    {
+        *DeviceObject = DeviceNode->PhysicalDeviceObject;
+    }
+    return Status;
+}
+
 /*
  * @implemented
  */
@@ -1216,6 +1423,7 @@ IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
     }
 
     /* Return the device object we found */
+    ASSERT(DeviceObject != NULL);
     return DeviceObject;
 }
 
@@ -1236,6 +1444,9 @@ IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject)
 
     /* Set the DO */
     Entry->DeviceObject = DeviceObject;
+    
+    /* Reference it so it doesn't go away */
+    ObReferenceObject(DeviceObject);
 
     /* Insert it into the list */
     ExInterlockedInsertHeadList(&LastChanceShutdownListHead,
@@ -1264,6 +1475,9 @@ IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
 
     /* Set the DO */
     Entry->DeviceObject = DeviceObject;
+    
+    /* Reference it so it doesn't go away */
+    ObReferenceObject(DeviceObject);
 
     /* Insert it into the list */
     ExInterlockedInsertHeadList(&ShutdownListHead,
@@ -1304,7 +1518,10 @@ IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
             NextEntry = NextEntry->Blink;
 
             /* Free the entry */
-            ExFreePool(ShutdownEntry);
+            ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
+            
+            /* Get rid of our reference to it */
+            ObDereferenceObject(DeviceObject);
         }
 
         /* Go to the next entry */
@@ -1328,13 +1545,19 @@ IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
             NextEntry = NextEntry->Blink;
 
             /* Free the entry */
-            ExFreePool(ShutdownEntry);
+            ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
+            
+            /* Get rid of our reference to it */
+            ObDereferenceObject(DeviceObject);
         }
 
         /* Go to the next entry */
         NextEntry = NextEntry->Flink;
     }
 
+    /* Release the shutdown lock */
+    KeReleaseSpinLock(&ShutdownListLock, OldIrql);
+
     /* Now remove the flag */
     DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
 }
@@ -1376,15 +1599,15 @@ IoStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject,
     if (DeviceExtension->StartIoFlags & DOE_SIO_DEFERRED)
     {
         /* Call our internal function to handle the defered case */
-        return IopStartNextPacketByKeyEx(DeviceObject,
-                                         Key,
-                                         DOE_SIO_WITH_KEY |
-                                         (Cancelable) ? DOE_SIO_CANCELABLE : 0);
+        IopStartNextPacketByKeyEx(DeviceObject,
+                                  Key,
+                                  DOE_SIO_WITH_KEY |
+                                  (Cancelable ? DOE_SIO_CANCELABLE : 0));
     }
     else
     {
         /* Call the normal routine */
-        return IopStartNextPacketByKey(DeviceObject, Cancelable, Key);
+        IopStartNextPacketByKey(DeviceObject, Cancelable, Key);
     }
 }
 
@@ -1405,15 +1628,15 @@ IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject,
     if (DeviceExtension->StartIoFlags & DOE_SIO_DEFERRED)
     {
         /* Call our internal function to handle the defered case */
-        return IopStartNextPacketByKeyEx(DeviceObject,
-                                         0,
-                                         DOE_SIO_NO_KEY |
-                                         (Cancelable) ? DOE_SIO_CANCELABLE : 0);
+        IopStartNextPacketByKeyEx(DeviceObject,
+                                  0,
+                                  DOE_SIO_NO_KEY |
+                                  (Cancelable ? DOE_SIO_CANCELABLE : 0));
     }
     else
     {
         /* Call the normal routine */
-        return IopStartNextPacket(DeviceObject, Cancelable);
+        IopStartNextPacket(DeviceObject, Cancelable);
     }
 }
 
@@ -1474,7 +1697,7 @@ IoStartPacket(IN PDEVICE_OBJECT DeviceObject,
             }
 
             /* Release the cancel lock */
-            IoReleaseCancelSpinLock(OldIrql);
+            IoReleaseCancelSpinLock(CancelIrql);
         }
 
         /* Call the Start I/O function */