Author: ion Date: Sat Jul 1 21:40:03 2006 New Revision: 22740
URL: http://svn.reactos.org/svn/reactos?rev=22740&view=rev Log: - Add IoGetDevObjExtension for getting the PEXTENDED_DEVOBJ_EXTENSION from a device object instead of always doing a huge typecast. - Implement device unloading through IopUnloadDevice and device referencing through IopReferenceDeviceObject and IopDereferenceDeviceObject, and make IoDeleteDevice and IoDetachDevice unload the device on 0 reference count. Doesn't fully work yet. - Simplify IoGetAttachedDEvice/IoGetAttachedDeviceReference not to use an extra stack variable.
Modified: trunk/reactos/ntoskrnl/include/internal/io.h trunk/reactos/ntoskrnl/io/device.c trunk/reactos/ntoskrnl/io/file.c
Modified: trunk/reactos/ntoskrnl/include/internal/io.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/i... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/io.h (original) +++ trunk/reactos/ntoskrnl/include/internal/io.h Sat Jul 1 21:40:03 2006 @@ -79,6 +79,13 @@ (!(FileObject) ? \ FALSE : \ FileObject->Flags & FO_SYNCHRONOUS_IO)) \ + +// +// Returns the internal Device Object Extension +// +#define IoGetDevObjExtension(DeviceObject) \ + ((PEXTENDED_DEVOBJ_EXTENSION) \ + (DeviceObject->DeviceObjectExtension)) \
/* * VOID @@ -176,6 +183,15 @@ (_DeviceNode); \ (_DeviceTreeTraverseContext)->Action = (_Action); \ (_DeviceTreeTraverseContext)->Context = (_Context); } + +// +// Device List Operations +// +typedef enum _IOP_DEVICE_LIST_OPERATION +{ + IopRemove, + IopAdd +} IOP_DEVICE_LIST_OPERATION, *PIOP_DEVICE_LIST_OPERATION;
// // Special version of the IRP Overlay used to optimize I/O completion @@ -563,6 +579,12 @@ VOID );
+NTSTATUS +NTAPI +IopReferenceDeviceObject( + IN PDEVICE_OBJECT DeviceObject +); + // // Shutdown routines //
Modified: trunk/reactos/ntoskrnl/io/device.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/device.c?rev=22... ============================================================================== --- trunk/reactos/ntoskrnl/io/device.c (original) +++ trunk/reactos/ntoskrnl/io/device.c Sat Jul 1 21:40:03 2006 @@ -171,7 +171,7 @@ }
NTSTATUS -STDCALL +NTAPI IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName, IN ACCESS_MASK DesiredAccess, OUT PFILE_OBJECT *FileObject, @@ -217,6 +217,235 @@ return Status; }
+PDEVICE_OBJECT +NTAPI +IopGetLowestDevice(IN PDEVICE_OBJECT DeviceObject) +{ + PDEVICE_OBJECT LowestDevice; + PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; + + /* Get the current device and its extension */ + LowestDevice = DeviceObject; + DeviceExtension = IoGetDevObjExtension(LowestDevice); + + /* Keep looping as long as we're attached */ + while (DeviceExtension->AttachedTo) + { + /* Get the lowest device and its extension */ + LowestDevice = DeviceExtension->AttachedTo; + DeviceExtension = IoGetDevObjExtension(LowestDevice); + } + + /* Return the lowest device */ + return LowestDevice; +} + +VOID +NTAPI +IopEditDeviceList(IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject, + IN IOP_DEVICE_LIST_OPERATION Type) +{ + PDEVICE_OBJECT Previous; + + /* Check the type of operation */ + if (Type == IopRemove) + { + /* Get the current device and check if it's the current one */ + Previous = DeviceObject->DriverObject->DeviceObject; + if (Previous == DeviceObject) + { + /* It is, simply unlink this one directly */ + DeviceObject->DriverObject->DeviceObject = + DeviceObject->NextDevice; + } + else + { + /* It's not, so loop until we find the device */ + while (Previous->NextDevice != DeviceObject) + { + /* Not this one, keep moving */ + Previous = Previous->NextDevice; + } + + /* We found it, now unlink us */ + Previous->NextDevice = DeviceObject->NextDevice; + } + } + else + { + /* Link the device object and the driver object */ + DeviceObject->NextDevice = DriverObject->DeviceObject; + DriverObject->DeviceObject = DeviceObject; + } +} + +VOID +NTAPI +IopUnloadDevice(IN PDEVICE_OBJECT DeviceObject) +{ + PDRIVER_OBJECT DriverObject = DeviceObject->DriverObject; + PDEVICE_OBJECT AttachedDeviceObject, LowestDeviceObject; + PEXTENDED_DEVOBJ_EXTENSION ThisExtension, DeviceExtension; + PDEVICE_NODE DeviceNode; + BOOLEAN SafeToUnload = TRUE; + + /* Check if removal is pending */ + ThisExtension = IoGetDevObjExtension(DeviceObject); + if (ThisExtension->ExtensionFlags & DOE_REMOVE_PENDING) + { + /* Get the PDO, extension, and node */ + LowestDeviceObject = IopGetLowestDevice(DeviceObject); + DeviceExtension = IoGetDevObjExtension(LowestDeviceObject); + DeviceNode = DeviceExtension->DeviceNode; + + /* The PDO needs a device node */ + ASSERT(DeviceNode != NULL); + + /* Loop all attached objects */ + AttachedDeviceObject = LowestDeviceObject; + while (AttachedDeviceObject) + { + /* Make sure they're dereferenced */ + if (AttachedDeviceObject->ReferenceCount) return; + AttachedDeviceObject = AttachedDeviceObject->AttachedDevice; + } + + /* Loop all attached objects */ + AttachedDeviceObject = LowestDeviceObject; + while (AttachedDeviceObject) + { + /* Get the device extension */ + DeviceExtension = IoGetDevObjExtension(AttachedDeviceObject); + + /* Remove the pending flag and set processed */ + DeviceExtension->ExtensionFlags &= ~DOE_REMOVE_PENDING; + DeviceExtension->ExtensionFlags |= DOE_REMOVE_PROCESSED; + AttachedDeviceObject = AttachedDeviceObject->AttachedDevice; + } + + /* + * FIXME: TODO HPOUSSIN + * We need to parse/lock the device node, and if we have any pending + * surprise removals, query all relationships and send IRP_MN_REMOVE_ + * _DEVICE to the devices related... + */ + return; + } + + /* Check if deletion is pending */ + if (ThisExtension->ExtensionFlags & DOE_DELETE_PENDING) + { + /* Make sure unload is pending */ + if (!(ThisExtension->ExtensionFlags & DOE_UNLOAD_PENDING) || + (DriverObject->Flags & DRVO_UNLOAD_INVOKED)) + { + /* We can't unload anymore */ + SafeToUnload = FALSE; + } + + /* + * Check if we have an attached device and fail if we're attached + * and still have a reference count. + */ + AttachedDeviceObject = DeviceObject->AttachedDevice; + if ((AttachedDeviceObject) && (DeviceObject->ReferenceCount)) return; + + /* Check if we have a Security Descriptor */ + if (DeviceObject->SecurityDescriptor) + { + /* Free it */ + ExFreePool(DeviceObject->SecurityDescriptor); + } + + /* Remove the device from the list */ + IopEditDeviceList(DeviceObject->DriverObject, DeviceObject, IopRemove); + + /* Dereference the keep-alive */ + ObDereferenceObject(DeviceObject); + + /* If we're not unloading, stop here */ + if (!SafeToUnload) return; + } + + /* Loop all the device objects */ + DeviceObject = DriverObject->DeviceObject; + while (DeviceObject) + { + /* + * Make sure we're not attached, having a reference count + * or already deleting + */ + if ((DeviceObject->ReferenceCount) || + (DeviceObject->AttachedDevice) || + (IoGetDevObjExtension(DeviceObject)->ExtensionFlags & + (DOE_DELETE_PENDING | DOE_REMOVE_PENDING))) + { + /* We're not safe to unload, quit */ + return; + } + + /* Check the next device */ + DeviceObject = DeviceObject->NextDevice; + } + + /* Set the unload invoked flag */ + DriverObject->Flags |= DRVO_UNLOAD_INVOKED; + + /* Unload it */ + if (DriverObject->DriverUnload) DriverObject->DriverUnload(DriverObject); +} + +VOID +NTAPI +IopDereferenceDeviceObject(IN PDEVICE_OBJECT DeviceObject, + IN BOOLEAN ForceUnload) +{ + /* Sanity check */ + ASSERT(DeviceObject->ReferenceCount); + + /* Dereference the device */ + DeviceObject->ReferenceCount--; + + /* + * Check if we can unload it and it's safe to unload (or if we're forcing + * an unload, which is OK too). + */ + if (!(DeviceObject->ReferenceCount) && + ((ForceUnload) || (IoGetDevObjExtension(DeviceObject)->ExtensionFlags & + (DOE_UNLOAD_PENDING | + DOE_DELETE_PENDING | + DOE_REMOVE_PENDING | + DOE_REMOVE_PROCESSED)))) + { + /* Unload it */ + IopUnloadDevice(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 */ + return STATUS_NO_SUCH_DEVICE; + } + else + { + /* Increase reference count */ + DeviceObject->ReferenceCount++; + return STATUS_SUCCESS; + } +} + /* PUBLIC FUNCTIONS ***********************************************************/
/* @@ -238,7 +467,7 @@ * @implemented */ NTSTATUS -STDCALL +NTAPI IoAttachDevice(PDEVICE_OBJECT SourceDevice, PUNICODE_STRING TargetDeviceName, PDEVICE_OBJECT *AttachedDevice) @@ -273,7 +502,7 @@ * @implemented */ NTSTATUS -STDCALL +NTAPI IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice, IN PDEVICE_OBJECT TargetDevice) { @@ -295,7 +524,7 @@ * @implemented */ PDEVICE_OBJECT -STDCALL +NTAPI IoAttachDeviceToDeviceStack(PDEVICE_OBJECT SourceDevice, PDEVICE_OBJECT TargetDevice) { @@ -315,7 +544,7 @@ * @implemented */ NTSTATUS -STDCALL +NTAPI IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice, IN PDEVICE_OBJECT TargetDevice, OUT PDEVICE_OBJECT *AttachedToDeviceObject) @@ -325,15 +554,14 @@
/* Get the Attached Device and source extension */ AttachedDevice = IoGetAttachedDevice(TargetDevice); - SourceDeviceExtension = (PEXTENDED_DEVOBJ_EXTENSION)SourceDevice-> - DeviceObjectExtension; + SourceDeviceExtension = IoGetDevObjExtension(SourceDevice);
/* Make sure that it's in a correct state */ - if (!(((PEXTENDED_DEVOBJ_EXTENSION)AttachedDevice->DeviceObjectExtension)-> - ExtensionFlags & (DOE_UNLOAD_PENDING | - DOE_DELETE_PENDING | - DOE_REMOVE_PENDING | - DOE_REMOVE_PROCESSED))) + if (!IoGetDevObjExtension(AttachedDevice)->ExtensionFlags & + (DOE_UNLOAD_PENDING | + DOE_DELETE_PENDING | + DOE_REMOVE_PENDING | + DOE_REMOVE_PROCESSED)) { /* Update atached device fields */ AttachedDevice->AttachedDevice = SourceDevice; @@ -392,7 +620,7 @@ * @implemented */ NTSTATUS -STDCALL +NTAPI IoCreateDevice(IN PDRIVER_OBJECT DriverObject, IN ULONG DeviceExtensionSize, IN PUNICODE_STRING DeviceName, @@ -559,8 +787,7 @@ /* Now do the final linking */ ObReferenceObject(DriverObject); CreatedDeviceObject->DriverObject = DriverObject; - CreatedDeviceObject->NextDevice = DriverObject->DeviceObject; - DriverObject->DeviceObject = CreatedDeviceObject; + IopEditDeviceList(DriverObject, CreatedDeviceObject, IopAdd);
/* Close the temporary handle and return to caller */ NtClose(TempHandle); @@ -575,46 +802,39 @@ * @implemented */ VOID -STDCALL -IoDeleteDevice(PDEVICE_OBJECT DeviceObject) -{ - PDEVICE_OBJECT Previous; - - if (DeviceObject->Flags & DO_SHUTDOWN_REGISTERED) - IoUnregisterShutdownNotification(DeviceObject); - - /* Remove the timer if it exists */ - if (DeviceObject->Timer) - { - IopRemoveTimerFromTimerList(DeviceObject->Timer); - ExFreePoolWithTag(DeviceObject->Timer, TAG_IO_TIMER); - } - - /* Remove device from driver device list */ - Previous = DeviceObject->DriverObject->DeviceObject; - if (Previous == DeviceObject) - { - DeviceObject->DriverObject->DeviceObject = DeviceObject->NextDevice; - } - else - { - while (Previous->NextDevice != DeviceObject) - Previous = Previous->NextDevice; - Previous->NextDevice = DeviceObject->NextDevice; - } - - /* I guess this should be removed later... but it shouldn't cause problems */ - ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->ExtensionFlags |= DOE_DELETE_PENDING; - - /* Make the object temporary. This should automatically remove the device - from the namespace */ - ObMakeTemporaryObject(DeviceObject); - - /* Dereference the driver object */ - ObDereferenceObject(DeviceObject->DriverObject); - - /* Remove the keep-alive reference */ - ObDereferenceObject(DeviceObject); +NTAPI +IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject) +{ + PIO_TIMER Timer; + + /* Check if the device is registered for shutdown notifications */ + if (DeviceObject->Flags & DO_SHUTDOWN_REGISTERED) + { + /* Call the shutdown notifications */ + IoUnregisterShutdownNotification(DeviceObject); + } + + /* Check if it has a timer */ + Timer = DeviceObject->Timer; + if (Timer) + { + /* Remove it and free it */ + IopRemoveTimerFromTimerList(Timer); + ExFreePoolWithTag(Timer, TAG_IO_TIMER); + } + + /* Check if the device has a name */ + if (DeviceObject->Flags & DO_DEVICE_HAS_NAME) + { + /* It does, make it temporary so we can remove it */ + ObMakeTemporaryObject(DeviceObject); + } + + /* Set the pending delete flag */ + IoGetDevObjExtension(DeviceObject)->ExtensionFlags |= DOE_DELETE_PENDING; + + /* Check if the device object can be unloaded */ + if (!DeviceObject->ReferenceCount) IopUnloadDevice(DeviceObject); }
/* @@ -624,21 +844,28 @@ * @implemented */ VOID -STDCALL -IoDetachDevice(PDEVICE_OBJECT TargetDevice) -{ - DPRINT("IoDetachDevice(TargetDevice 0x%p)\n", TargetDevice); - +NTAPI +IoDetachDevice(IN PDEVICE_OBJECT TargetDevice) +{ /* Remove the attachment */ - ((PEXTENDED_DEVOBJ_EXTENSION)TargetDevice->AttachedDevice->DeviceObjectExtension)->AttachedTo = NULL; + IoGetDevObjExtension(TargetDevice->AttachedDevice)->AttachedTo = NULL; TargetDevice->AttachedDevice = NULL; + + /* Check if it's ok to delete this device */ + if ((IoGetDevObjExtension(TargetDevice)->ExtensionFlags & + (DOE_UNLOAD_PENDING | DOE_DELETE_PENDING | DOE_REMOVE_PENDING)) && + !(TargetDevice->ReferenceCount)) + { + /* It is, do it */ + IopUnloadDevice(TargetDevice); + } }
/* * @implemented */ NTSTATUS -STDCALL +NTAPI IoEnumerateDeviceObjectList(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT *DeviceObjectList, IN ULONG DeviceObjectListSize, @@ -647,13 +874,8 @@ ULONG ActualDevices = 1; PDEVICE_OBJECT CurrentDevice = DriverObject->DeviceObject;
- DPRINT1("IoEnumerateDeviceObjectList\n"); - /* Find out how many devices we'll enumerate */ - while ((CurrentDevice = CurrentDevice->NextDevice)) - { - ActualDevices++; - } + while ((CurrentDevice = CurrentDevice->NextDevice)) ActualDevices++;
/* Go back to the first */ CurrentDevice = DriverObject->DeviceObject; @@ -698,19 +920,18 @@ * @implemented */ PDEVICE_OBJECT -STDCALL +NTAPI IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject) { - PDEVICE_OBJECT Current = DeviceObject; - /* Get the last attached device */ - while (Current->AttachedDevice) - { - Current = Current->AttachedDevice; + while (DeviceObject->AttachedDevice) + { + /* Move to the next one */ + DeviceObject = DeviceObject->AttachedDevice; }
/* Return it */ - return Current; + return DeviceObject; }
/* @@ -720,14 +941,13 @@ * @implemented */ PDEVICE_OBJECT -STDCALL +NTAPI IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject) { - PDEVICE_OBJECT Current = IoGetAttachedDevice(DeviceObject); - - /* Reference the ATtached Device */ - ObReferenceObject(Current); - return Current; + /* Reference the Attached Device */ + DeviceObject = IoGetAttachedDevice(DeviceObject); + ObReferenceObject(DeviceObject); + return DeviceObject; }
/*
Modified: trunk/reactos/ntoskrnl/io/file.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/file.c?rev=2274... ============================================================================== --- trunk/reactos/ntoskrnl/io/file.c (original) +++ trunk/reactos/ntoskrnl/io/file.c Sat Jul 1 21:40:03 2006 @@ -55,6 +55,9 @@ if (!*RemainingName->Buffer) { DeviceObject = ParseObject; + Status = IopReferenceDeviceObject(DeviceObject); + // fixme: NT wouldn't allow this + //if (!NT_SUCCESS(Status)) return Status;// KEBUGCHECK(0);
Status = ObCreateObject(AccessMode, IoFileObjectType, @@ -116,6 +119,9 @@ DeviceObject = OpenPacket->RelatedFileObject->DeviceObject; }
+ Status = IopReferenceDeviceObject(DeviceObject); + // fixme: NT wouldn't allow this + //if (!NT_SUCCESS(Status)) return Status;// KEBUGCHECK(0); RtlCreateUnicodeString(&FileObject->FileName, RemainingName->Buffer); FileObject->DeviceObject = DeviceObject; *Object = FileObject;