/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
- * FILE: ntoskrnl/io/device.c
+ * FILE: ntoskrnl/io/iomgr/device.c
* PURPOSE: Device Object Management, including Notifications and Queues.
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Filip Navara (navaraf@reactos.org)
PIRP Irp;
KEVENT Event;
NTSTATUS Status;
-
+
/* Initialize an event to wait on */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
-
+
/* What phase? */
if (Phase == 0)
{
NULL,
&Event,
&StatusBlock);
- Status = IoCallDriver(DeviceObject, Irp);
- if (Status == STATUS_PENDING)
+ if (Irp)
{
- /* Wait on the driver */
- KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ Status = IoCallDriver(DeviceObject, Irp);
+ if (Status == STATUS_PENDING)
+ {
+ /* Wait on the driver */
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ }
}
+ /* Remove the flag */
+ ShutdownEntry->DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
+
/* Get rid of our reference to it */
- ObDereferenceObject(DeviceObject);
-
+ ObDereferenceObject(ShutdownEntry->DeviceObject);
+
/* Free the shutdown entry and reset the event */
ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
KeClearEvent(&Event);
/* Shutdown tape filesystems */
IopShutdownBaseFileSystems(&IopTapeFileSystemQueueHead);
-
+
/* Loop last-chance shutdown notifications */
ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead,
&ShutdownListLock);
NULL,
&Event,
&StatusBlock);
- Status = IoCallDriver(DeviceObject, Irp);
- if (Status == STATUS_PENDING)
+ if (Irp)
{
- /* Wait on the driver */
- KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ Status = IoCallDriver(DeviceObject, Irp);
+ if (Status == STATUS_PENDING)
+ {
+ /* Wait on the driver */
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ }
}
+ /* Remove the flag */
+ ShutdownEntry->DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
+
/* Get rid of our reference to it */
- ObDereferenceObject(DeviceObject);
-
+ ObDereferenceObject(ShutdownEntry->DeviceObject);
+
/* Free the shutdown entry and reset the event */
ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
KeClearEvent(&Event);
IN IOP_DEVICE_LIST_OPERATION Type)
{
PDEVICE_OBJECT Previous;
+ KIRQL OldIrql;
+
+ /* Lock the Device list while we edit it */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
/* Check the type of operation */
if (Type == IopRemove)
while (Previous->NextDevice != DeviceObject)
{
/* Not this one, keep moving */
+ if (!Previous->NextDevice)
+ {
+ DPRINT1("Failed to remove PDO %p (not found)\n",
+ DeviceObject);
+
+ ASSERT(FALSE);
+ KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
+ return;
+ }
Previous = Previous->NextDevice;
}
DeviceObject->NextDevice = DriverObject->DeviceObject;
DriverObject->DeviceObject = DeviceObject;
}
+
+ /* Release the device list lock */
+ KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
}
VOID
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;
- }
+ PEXTENDED_DEVOBJ_EXTENSION ThisExtension = IoGetDevObjExtension(DeviceObject);
/* 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))
+ if (DeviceObject->AttachedDevice)
{
- /* We can't unload anymore */
- SafeToUnload = FALSE;
+ DPRINT("Device object is in the middle of a device stack\n");
+ return;
}
- /*
- * 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;
+ if (DeviceObject->ReferenceCount)
+ {
+ DPRINT("Device object still has %d references\n", DeviceObject->ReferenceCount);
+ return;
+ }
/* Check if we have a Security Descriptor */
if (DeviceObject->SecurityDescriptor)
{
- /* Free it */
- ExFreePoolWithTag(DeviceObject->SecurityDescriptor, TAG_SD);
+ /* Dereference it */
+ ObDereferenceSecurityDescriptor(DeviceObject->SecurityDescriptor, 1);
}
/* Remove the device from the list */
/* Dereference the keep-alive */
ObDereferenceObject(DeviceObject);
+ }
- /* If we're not unloading, stop here */
- if (!SafeToUnload) return;
+ /* We can't unload a non-PnP driver here */
+ if (DriverObject->Flags & DRVO_LEGACY_DRIVER)
+ {
+ DPRINT("Not a PnP driver! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
+ return;
}
- /* Loop all the device objects */
- DeviceObject = DriverObject->DeviceObject;
- while (DeviceObject)
+ /* Return if we've already called unload (maybe we're in it?) */
+ if (DriverObject->Flags & DRVO_UNLOAD_INVOKED) return;
+
+ /* We can't unload unless there's an unload handler */
+ if (!DriverObject->DriverUnload)
{
- /*
- * 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;
- }
+ DPRINT1("No DriverUnload function on PnP driver! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
+ return;
+ }
- /* Check the next device */
- DeviceObject = DeviceObject->NextDevice;
+ /* Bail if there are still devices present */
+ if (DriverObject->DeviceObject)
+ {
+ DPRINT("Devices still present! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
+ return;
}
+ DPRINT1("Unloading driver '%wZ' (automatic)\n", &DriverObject->DriverName);
+
/* Set the unload invoked flag */
DriverObject->Flags |= DRVO_UNLOAD_INVOKED;
/* Unload it */
- if (DriverObject->DriverUnload) DriverObject->DriverUnload(DriverObject);
+ DriverObject->DriverUnload(DriverObject);
/* Make object temporary so it can be deleted */
ObMakeTemporaryObject(DriverObject);
-
- /* Dereference once more, referenced at driver object creation */
- ObDereferenceObject(DriverObject);
-
}
VOID
ASSERT(DeviceObject->ReferenceCount);
/* Dereference the device */
- DeviceObject->ReferenceCount--;
+ InterlockedDecrement(&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).
*/
+ ASSERT(!ForceUnload);
if (!(DeviceObject->ReferenceCount) &&
- ((ForceUnload) || (IoGetDevObjExtension(DeviceObject)->ExtensionFlags &
- (DOE_UNLOAD_PENDING |
- DOE_DELETE_PENDING |
- DOE_REMOVE_PENDING |
- DOE_REMOVE_PROCESSED))))
+ (IoGetDevObjExtension(DeviceObject)->ExtensionFlags & DOE_DELETE_PENDING))
{
/* Unload it */
IopUnloadDevice(DeviceObject);
/* Initialize the name */
RtlInitUnicodeString(&AutoName, AutoNameBuffer);
DeviceName = &AutoName;
- }
+ }
/* Initialize the Object Attributes */
InitializeObjectAttributes(&ObjectAttributes,
DeviceName,
OBJ_KERNEL_HANDLE,
NULL,
- NULL);
+ SePublicOpenUnrestrictedSd);
/* Honor exclusive flag */
if (Exclusive) ObjectAttributes.Attributes |= OBJ_EXCLUSIVE;
/* 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);
Status = IopCreateVpb(CreatedDeviceObject);
if (!NT_SUCCESS(Status))
{
- /* Reference the device object and fail */
- ObDereferenceObject(DeviceObject);
+ /* Dereference the device object and fail */
+ ObDereferenceObject(CreatedDeviceObject);
return Status;
}
ASSERT((DriverObject->Flags & DRVO_UNLOAD_INVOKED) == 0);
CreatedDeviceObject->DriverObject = DriverObject;
IopEditDeviceList(DriverObject, CreatedDeviceObject, IopAdd);
-
+
/* Link with the power manager */
if (CreatedDeviceObject->Vpb) PoVolumeDevice(CreatedDeviceObject);
/* Set the pending delete flag */
IoGetDevObjExtension(DeviceObject)->ExtensionFlags |= DOE_DELETE_PENDING;
+ /* Unlink with the power manager */
+ if (DeviceObject->Vpb) PoRemoveVolumeDevice(DeviceObject);
+
/* Check if the device object can be unloaded */
if (!DeviceObject->ReferenceCount) IopUnloadDevice(DeviceObject);
}
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)) &&
+ if ((IoGetDevObjExtension(TargetDevice)->ExtensionFlags & DOE_DELETE_PENDING) &&
!(TargetDevice->ReferenceCount))
{
/* It is, do it */
{
ULONG ActualDevices = 1;
PDEVICE_OBJECT CurrentDevice = DriverObject->DeviceObject;
+ KIRQL OldIrql;
+
+ /* Lock the Device list while we enumerate it */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
/* Find out how many devices we'll enumerate */
while ((CurrentDevice = CurrentDevice->NextDevice)) ActualDevices++;
*ActualNumberDeviceObjects = ActualDevices;
/* Check if we can support so many */
- if ((ActualDevices * 4) > DeviceObjectListSize)
+ if ((ActualDevices * sizeof(PDEVICE_OBJECT)) > DeviceObjectListSize)
{
/* Fail because the buffer was too small */
+ KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
return STATUS_BUFFER_TOO_SMALL;
}
- /* Check if the caller only wanted the size */
+ /* Check if the caller wanted the device list */
if (DeviceObjectList)
{
/* Loop through all the devices */
}
}
+ /* Release the device list lock */
+ KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
+
/* Return the status */
return STATUS_SUCCESS;
}
/* Check if the extension is really present */
if (FileObject->FileObjectExtension)
{
- /* FIXME: Unhandled yet */
- DPRINT1("FOEs not supported\n");
+ PFILE_OBJECT_EXTENSION FileObjectExtension;
ASSERT(FALSE);
+
+ /* Cast the buffer to something we understand */
+ FileObjectExtension = FileObject->FileObjectExtension;
+
+ /* Check if have a replacement top level device */
+ if (FileObjectExtension->TopDeviceObjectHint)
+ {
+ /* Use this instead of returning the top level device */
+ return FileObjectExtension->TopDeviceObjectHint;
+ }
}
}
/* Set the DO */
Entry->DeviceObject = DeviceObject;
-
+
/* Reference it so it doesn't go away */
ObReferenceObject(DeviceObject);
/* Set the DO */
Entry->DeviceObject = DeviceObject;
-
+
/* Reference it so it doesn't go away */
ObReferenceObject(DeviceObject);
PLIST_ENTRY NextEntry;
KIRQL OldIrql;
+ /* Remove the flag */
+ DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
+
/* Acquire the shutdown lock and loop the shutdown list */
KeAcquireSpinLock(&ShutdownListLock, &OldIrql);
NextEntry = ShutdownListHead.Flink;
/* Free the entry */
ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
-
+
/* Get rid of our reference to it */
ObDereferenceObject(DeviceObject);
}
/* Free the entry */
ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
-
+
/* Get rid of our reference to it */
ObDereferenceObject(DeviceObject);
}
/* Release the shutdown lock */
KeReleaseSpinLock(&ShutdownListLock, OldIrql);
-
- /* Now remove the flag */
- DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
}
/*