reactos/ntoskrnl/io/iomgr/volume.c
Jérôme Gardou c16ad873a6 sync with trunk (r46275)
svn path=/branches/reactos-yarotows/; revision=46279
2010-03-19 21:09:21 +00:00

962 lines
29 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/io/iomgr/volume.c
* PURPOSE: Volume and File System I/O Support
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Hervé Poussineau (hpoussin@reactos.org)
* Eric Kohl
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(INIT, IoInitFileSystemImplementation)
#pragma alloc_text(INIT, IoInitVpbImplementation)
#endif
/* GLOBALS ******************************************************************/
ERESOURCE FileSystemListLock;
LIST_ENTRY IopDiskFsListHead, IopNetworkFsListHead;
LIST_ENTRY IopCdRomFsListHead, IopTapeFsListHead;
KGUARDED_MUTEX FsChangeNotifyListLock;
LIST_ENTRY FsChangeNotifyListHead;
/* PRIVATE FUNCTIONS *********************************************************/
PVPB
NTAPI
IopCheckVpbMounted(IN POPEN_PACKET OpenPacket,
IN PDEVICE_OBJECT DeviceObject,
IN PUNICODE_STRING RemainingName,
OUT PNTSTATUS Status)
{
BOOLEAN Alertable, Raw;
KIRQL OldIrql;
PVPB Vpb = NULL;
/* Lock the VPBs */
IoAcquireVpbSpinLock(&OldIrql);
/* Set VPB mount settings */
Raw = !RemainingName->Length && !OpenPacket->RelatedFileObject;
Alertable = (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT) ?
TRUE: FALSE;
/* Start looping until the VPB is mounted */
while (!(DeviceObject->Vpb->Flags & VPB_MOUNTED))
{
/* Release the lock */
IoReleaseVpbSpinLock(OldIrql);
/* Mount the volume */
*Status = IopMountVolume(DeviceObject,
Raw,
FALSE,
Alertable,
&Vpb);
/* Check if we failed or if we were alerted */
if (!(NT_SUCCESS(*Status)) ||
(*Status == STATUS_USER_APC) ||
(*Status == STATUS_ALERTED))
{
/* Dereference the device, since IopParseDevice referenced it */
IopDereferenceDeviceObject(DeviceObject, FALSE);
/* Check if it was a total failure */
if (!NT_SUCCESS(*Status)) return NULL;
/* Otherwise we were alerted */
*Status = STATUS_WRONG_VOLUME;
return NULL;
}
/* Re-acquire the lock */
IoAcquireVpbSpinLock(&OldIrql);
}
/* Make sure the VPB isn't locked */
Vpb = DeviceObject->Vpb;
if (Vpb->Flags & VPB_LOCKED)
{
/* We're locked, so fail */
*Status = STATUS_ACCESS_DENIED;
Vpb = NULL;
}
else
{
/* Success! Reference the VPB */
Vpb->ReferenceCount++;
}
/* Release the lock and return the VPB */
IoReleaseVpbSpinLock(OldIrql);
return Vpb;
}
NTSTATUS
NTAPI
IopCreateVpb(IN PDEVICE_OBJECT DeviceObject)
{
PVPB Vpb;
/* Allocate the Vpb */
Vpb = ExAllocatePoolWithTag(NonPagedPool,
sizeof(VPB),
TAG_VPB);
if (!Vpb) return STATUS_UNSUCCESSFUL;
/* Clear it so we don't waste time manually */
RtlZeroMemory(Vpb, sizeof(VPB));
/* Set the Header and Device Field */
Vpb->Type = IO_TYPE_VPB;
Vpb->Size = sizeof(VPB);
Vpb->RealDevice = DeviceObject;
/* Link it to the Device Object */
DeviceObject->Vpb = Vpb;
return STATUS_SUCCESS;
}
VOID
NTAPI
IopDereferenceVpb(IN PVPB Vpb)
{
KIRQL OldIrql;
/* Lock the VPBs and decrease references */
IoAcquireVpbSpinLock(&OldIrql);
Vpb->ReferenceCount--;
/* Check if we're out of references */
if (!Vpb->ReferenceCount)
{
/* FIXME: IMPLEMENT CLEANUP! */
ASSERT(FALSE);
}
/* Release VPB lock */
IoReleaseVpbSpinLock(OldIrql);
}
BOOLEAN
NTAPI
IopReferenceVpbForVerify(IN PDEVICE_OBJECT DeviceObject,
OUT PDEVICE_OBJECT *FileSystemObject,
OUT PVPB *Vpb)
{
KIRQL OldIrql;
PVPB LocalVpb;
BOOLEAN Result = FALSE;
/* Lock the VPBs and assume failure */
IoAcquireVpbSpinLock(&OldIrql);
*Vpb = NULL;
*FileSystemObject = NULL;
/* Get the VPB and make sure it's mounted */
LocalVpb = DeviceObject->Vpb;
if ((LocalVpb) && (LocalVpb->Flags & VPB_MOUNTED))
{
/* Return it */
*Vpb = LocalVpb;
*FileSystemObject = LocalVpb->DeviceObject;
/* Reference it */
LocalVpb->ReferenceCount++;
Result = TRUE;
}
/* Release the VPB lock and return status */
IoReleaseVpbSpinLock(OldIrql);
return Result;
}
PVPB
NTAPI
IopInitializeVpbForMount(IN PDEVICE_OBJECT DeviceObject,
IN PDEVICE_OBJECT AttachedDeviceObject,
IN BOOLEAN Raw)
{
KIRQL OldIrql;
PVPB Vpb;
/* Lock the VPBs */
IoAcquireVpbSpinLock(&OldIrql);
Vpb = DeviceObject->Vpb;
/* Set the VPB as mounted and possibly raw */
Vpb->Flags |= VPB_MOUNTED | (Raw ? VPB_RAW_MOUNT : 0);
/* Set the stack size */
Vpb->DeviceObject->StackSize = AttachedDeviceObject->StackSize;
/* Add one for the FS Driver */
Vpb->DeviceObject->StackSize++;
/* Set the VPB in the device extension */
IoGetDevObjExtension(Vpb->DeviceObject)->Vpb = Vpb;
/* Reference it */
Vpb->ReferenceCount++;
/* Release the VPB lock and return it */
IoReleaseVpbSpinLock(OldIrql);
return Vpb;
}
VOID
NTAPI
IopNotifyFileSystemChange(IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN DriverActive)
{
PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
PLIST_ENTRY ListEntry;
/* Acquire the notification lock */
KeAcquireGuardedMutex(&FsChangeNotifyListLock);
/* Loop the list */
ListEntry = FsChangeNotifyListHead.Flink;
while (ListEntry != &FsChangeNotifyListHead)
{
/* Get the entry */
ChangeEntry = CONTAINING_RECORD(ListEntry,
FS_CHANGE_NOTIFY_ENTRY,
FsChangeNotifyList);
/* Call the notification procedure */
ChangeEntry->FSDNotificationProc(DeviceObject, DriverActive);
/* Go to the next entry */
ListEntry = ListEntry->Flink;
}
/* Release the lock */
KeReleaseGuardedMutex(&FsChangeNotifyListLock);
}
VOID
NTAPI
IopShutdownBaseFileSystems(IN PLIST_ENTRY ListHead)
{
PLIST_ENTRY ListEntry;
PDEVICE_OBJECT DeviceObject;
IO_STATUS_BLOCK StatusBlock;
PIRP Irp;
KEVENT Event;
NTSTATUS Status;
/* Lock the FS List and initialize an event to wait on */
KeEnterCriticalRegion();
ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
KeInitializeEvent(&Event, NotificationEvent, FALSE);
/* Get the first entry and start looping */
ListEntry = ListHead->Flink;
while (ListEntry != ListHead)
{
/* Get the device object */
DeviceObject = CONTAINING_RECORD(ListEntry,
DEVICE_OBJECT,
Queue.ListEntry);
/* Check if we're attached */
if (DeviceObject->AttachedDevice)
{
/* Get the attached device */
DeviceObject = IoGetAttachedDevice(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);
}
/* Reset the event */
KeClearEvent(&Event);
/* Go to the next entry */
ListEntry = ListEntry->Flink;
}
/* Release the lock */
ExReleaseResourceLite(&FileSystemListLock);
KeLeaveCriticalRegion();
}
VOID
NTAPI
IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject)
{
IO_STATUS_BLOCK IoStatusBlock;
PIO_STACK_LOCATION StackPtr;
KEVENT Event;
PIRP Irp;
NTSTATUS Status;
PDEVICE_OBJECT AttachedDeviceObject = DeviceObject;
PAGED_CODE();
/* Loop as long as we're attached */
while (AttachedDeviceObject->AttachedDevice)
{
/* Get the attached device object */
AttachedDeviceObject = AttachedDeviceObject->AttachedDevice;
}
/* Initialize the event and build the IRP */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
Irp = IoBuildDeviceIoControlRequest(IRP_MJ_DEVICE_CONTROL,
AttachedDeviceObject,
NULL,
0,
NULL,
0,
FALSE,
&Event,
&IoStatusBlock);
if (Irp)
{
/* Set the major and minor functions */
StackPtr = IoGetNextIrpStackLocation(Irp);
StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
StackPtr->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM;
/* Call the driver */
Status = IoCallDriver(AttachedDeviceObject, Irp);
if (Status == STATUS_PENDING)
{
/* Wait on it */
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
}
}
}
NTSTATUS
NTAPI
IopMountVolume(IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN AllowRawMount,
IN BOOLEAN DeviceIsLocked,
IN BOOLEAN Alertable,
OUT PVPB *Vpb)
{
KEVENT Event;
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
PIRP Irp;
PIO_STACK_LOCATION StackPtr;
PLIST_ENTRY FsList, ListEntry;
LIST_ENTRY LocalList;
PDEVICE_OBJECT AttachedDeviceObject = DeviceObject;
PDEVICE_OBJECT FileSystemDeviceObject, ParentFsDeviceObject;
ULONG FsStackOverhead;
PAGED_CODE();
/* Check if the device isn't already locked */
if (!DeviceIsLocked)
{
/* Lock it ourselves */
Status = KeWaitForSingleObject(&DeviceObject->DeviceLock,
Executive,
KeGetPreviousMode(),
Alertable,
NULL);
if ((Status == STATUS_ALERTED) || (Status == STATUS_USER_APC))
{
/* Don't mount if we were interrupted */
return Status;
}
}
/* Acquire the FS Lock*/
KeEnterCriticalRegion();
ExAcquireResourceSharedLite(&FileSystemListLock, TRUE);
/* Make sure we weren't already mounted */
if (!(DeviceObject->Vpb->Flags & (VPB_MOUNTED | VPB_REMOVE_PENDING)))
{
/* Initialize the event to wait on */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
/* Remove the verify flag and get the actual device to mount */
DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
while (AttachedDeviceObject->AttachedDevice)
{
/* Get the next one */
AttachedDeviceObject = AttachedDeviceObject->AttachedDevice;
}
/* Reference it */
ObReferenceObject(AttachedDeviceObject);
/* For a mount operation, this can only be a Disk, CD-ROM or tape */
if ((DeviceObject->DeviceType == FILE_DEVICE_DISK) ||
(DeviceObject->DeviceType == FILE_DEVICE_VIRTUAL_DISK))
{
/* Use the disk list */
FsList = &IopDiskFsListHead;
}
else if (DeviceObject->DeviceType == FILE_DEVICE_CD_ROM)
{
/* Use the CD-ROM list */
FsList = &IopCdRomFsListHead;
}
else
{
/* It's gotta be a tape... */
FsList = &IopTapeFsListHead;
}
/* Now loop the fs list until one of the file systems accepts us */
Status = STATUS_UNSUCCESSFUL;
ListEntry = FsList->Flink;
while ((ListEntry != FsList) && !(NT_SUCCESS(Status)))
{
/*
* If we're not allowed to mount this volume and this is our last
* (but not only) chance to mount it...
*/
if (!(AllowRawMount) &&
(ListEntry->Flink == FsList) &&
(ListEntry != FsList->Flink))
{
/* Then fail this mount request */
break;
}
/*
* Also check if this is a raw mount and there are other file
* systems on the list.
*/
if ((DeviceObject->Vpb->Flags & VPB_RAW_MOUNT) &&
(ListEntry->Flink != FsList))
{
/* Then skip this entry */
continue;
}
/* Get the Device Object for this FS */
FileSystemDeviceObject = CONTAINING_RECORD(ListEntry,
DEVICE_OBJECT,
Queue.ListEntry);
ParentFsDeviceObject = FileSystemDeviceObject;
/*
* If this file system device is attached to some other device,
* then we must make sure to increase the stack size for the IRP.
* The default is +1, for the FS device itself.
*/
FsStackOverhead = 1;
while (FileSystemDeviceObject->AttachedDevice)
{
/* Get the next attached device and increase overhead */
FileSystemDeviceObject = FileSystemDeviceObject->
AttachedDevice;
FsStackOverhead++;
}
/* Clear the event */
KeClearEvent(&Event);
/* Allocate the IRP */
Irp = IoAllocateIrp(AttachedDeviceObject->StackSize +
(UCHAR)FsStackOverhead,
TRUE);
if (!Irp)
{
/* Fail */
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
/* Setup the IRP */
Irp->UserIosb = &IoStatusBlock;
Irp->UserEvent = &Event;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->Flags = IRP_MOUNT_COMPLETION | IRP_SYNCHRONOUS_PAGING_IO;
Irp->RequestorMode = KernelMode;
/* Get the I/O Stack location and set it up */
StackPtr = IoGetNextIrpStackLocation(Irp);
StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
StackPtr->MinorFunction = IRP_MN_MOUNT_VOLUME;
StackPtr->Flags = AllowRawMount;
StackPtr->Parameters.MountVolume.Vpb = DeviceObject->Vpb;
StackPtr->Parameters.MountVolume.DeviceObject =
AttachedDeviceObject;
/* Call the driver */
Status = IoCallDriver(FileSystemDeviceObject, Irp);
if (Status == STATUS_PENDING)
{
/* Wait on it */
KeWaitForSingleObject(&Event,
Executive,
KernelMode,
FALSE,
NULL);
Status = IoStatusBlock.Status;
}
/* Check if mounting was successful */
if (NT_SUCCESS(Status))
{
/* Mount the VPB */
*Vpb = IopInitializeVpbForMount(DeviceObject,
AttachedDeviceObject,
(DeviceObject->Vpb->Flags &
VPB_RAW_MOUNT));
}
else
{
/* Check if we failed because of the user */
if ((IoIsErrorUserInduced(Status)) &&
(IoStatusBlock.Information == 1))
{
/* Break out and fail */
break;
}
/* Otherwise, check if we need to load the FS driver */
if (Status == STATUS_FS_DRIVER_REQUIRED)
{
/* We need to release the lock */
ExReleaseResourceLite(&FileSystemListLock);
/* Release the device lock if we're holding it */
if (!DeviceIsLocked)
{
KeSetEvent(&DeviceObject->DeviceLock, 0, FALSE);
}
/* Load the FS */
IopLoadFileSystem(ParentFsDeviceObject);
/* Check if the device isn't already locked */
if (!DeviceIsLocked)
{
/* Lock it ourselves */
Status = KeWaitForSingleObject(&DeviceObject->
DeviceLock,
Executive,
KeGetPreviousMode(),
Alertable,
NULL);
if ((Status == STATUS_ALERTED) ||
(Status == STATUS_USER_APC))
{
/* Don't mount if we were interrupted */
ObDereferenceObject(AttachedDeviceObject);
return Status;
}
}
/* Reacquire the lock */
ExAcquireResourceSharedLite(&FileSystemListLock, TRUE);
/* When we released the lock, make sure nobody beat us */
if (DeviceObject->Vpb->Flags & VPB_MOUNTED)
{
/* Someone did, break out */
Status = STATUS_SUCCESS;
break;
}
/* Start over by setting a failure */
Status = STATUS_UNRECOGNIZED_VOLUME;
/* We need to setup a local list to pickup where we left */
LocalList.Flink = FsList->Flink;
ListEntry = &LocalList;
}
/*
* Check if we failed with any other error then an unrecognized
* volume, and if this request doesn't allow mounting the raw
* file system.
*/
if (!(AllowRawMount) &&
(Status != STATUS_UNRECOGNIZED_VOLUME) &&
(FsRtlIsTotalDeviceFailure(Status)))
{
/* Break out and give up */
break;
}
}
/* Go to the next FS entry */
ListEntry = ListEntry->Flink;
}
/* Dereference the device if we failed */
if (!NT_SUCCESS(Status)) ObDereferenceObject(AttachedDeviceObject);
}
else if (DeviceObject->Vpb->Flags & VPB_REMOVE_PENDING)
{
/* Someone wants to remove us */
Status = STATUS_DEVICE_DOES_NOT_EXIST;
}
else
{
/* Someone already mounted us */
Status = STATUS_SUCCESS;
}
/* Release the FS lock */
ExReleaseResourceLite(&FileSystemListLock);
KeLeaveCriticalRegion();
/* Release the device lock if we're holding it */
if (!DeviceIsLocked) KeSetEvent(&DeviceObject->DeviceLock, 0, FALSE);
/* Check if we failed to mount the boot partition */
if ((!NT_SUCCESS(Status)) &&
(DeviceObject->Flags & DO_SYSTEM_BOOT_PARTITION))
{
/* Bugcheck the system */
KeBugCheckEx(INACCESSIBLE_BOOT_DEVICE,
(ULONG_PTR)DeviceObject,
Status,
0,
0);
}
/* Return the mount status */
return Status;
}
/* PUBLIC FUNCTIONS **********************************************************/
/*
* @unimplemented
*/
NTSTATUS
NTAPI
IoEnumerateRegisteredFiltersList(IN PDRIVER_OBJECT *DriverObjectList,
IN ULONG DriverObjectListSize,
OUT PULONG ActualNumberDriverObjects)
{
UNIMPLEMENTED;
return STATUS_UNSUCCESSFUL;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN AllowRawMount)
{
IO_STATUS_BLOCK IoStatusBlock;
PIO_STACK_LOCATION StackPtr;
KEVENT Event;
PIRP Irp;
NTSTATUS Status = STATUS_SUCCESS, VpbStatus;
PDEVICE_OBJECT FileSystemDeviceObject;
PVPB Vpb, NewVpb;
BOOLEAN WasNotMounted = TRUE;
/* Wait on the device lock */
KeWaitForSingleObject(&DeviceObject->DeviceLock,
Executive,
KernelMode,
FALSE,
NULL);
/* Reference the VPB */
if (IopReferenceVpbForVerify(DeviceObject, &FileSystemDeviceObject, &Vpb))
{
/* Initialize the event */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
/* Find the actual File System DO */
WasNotMounted = FALSE;
FileSystemDeviceObject = DeviceObject->Vpb->DeviceObject;
while (FileSystemDeviceObject->AttachedDevice)
{
/* Go to the next one */
FileSystemDeviceObject = FileSystemDeviceObject->AttachedDevice;
}
/* Allocate the IRP */
Irp = IoAllocateIrp(FileSystemDeviceObject->StackSize, FALSE);
if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
/* Set it up */
Irp->UserIosb = &IoStatusBlock;
Irp->UserEvent = &Event;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->Flags = IRP_MOUNT_COMPLETION | IRP_SYNCHRONOUS_PAGING_IO;
Irp->RequestorMode = KernelMode;
/* Get the I/O Stack location and set it */
StackPtr = IoGetNextIrpStackLocation(Irp);
StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
StackPtr->MinorFunction = IRP_MN_VERIFY_VOLUME;
StackPtr->Flags = AllowRawMount ? SL_ALLOW_RAW_MOUNT : 0;
StackPtr->Parameters.VerifyVolume.Vpb = Vpb;
StackPtr->Parameters.VerifyVolume.DeviceObject =
DeviceObject->Vpb->DeviceObject;
/* Call the driver */
Status = IoCallDriver(FileSystemDeviceObject, Irp);
if (Status == STATUS_PENDING)
{
/* Wait on it */
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock.Status;
}
/* Dereference the VPB */
IopDereferenceVpb(Vpb);
}
/* Check if we had the wrong volume or didn't mount at all */
if ((Status == STATUS_WRONG_VOLUME) || (WasNotMounted))
{
/* Create a VPB */
VpbStatus = IopCreateVpb(DeviceObject);
if (NT_SUCCESS(VpbStatus))
{
/* Mount it */
VpbStatus = IopMountVolume(DeviceObject,
AllowRawMount,
TRUE,
FALSE,
&NewVpb);
}
/* If we failed, remove the verify flag */
if (!NT_SUCCESS(VpbStatus)) DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
}
/* Signal the device lock and return */
KeSetEvent(&DeviceObject->DeviceLock, IO_NO_INCREMENT, FALSE);
return Status;
}
/*
* @implemented
*/
VOID
NTAPI
IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
{
PLIST_ENTRY FsList = NULL;
PAGED_CODE();
/* Acquire the FS lock */
KeEnterCriticalRegion();
ExAcquireResourceExclusiveLite(&FileSystemListLock, TRUE);
/* Check what kind of FS this is */
if (DeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM)
{
/* Use the disk list */
FsList = &IopDiskFsListHead;
}
else if (DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM)
{
/* Use the network device list */
FsList = &IopNetworkFsListHead;
}
else if (DeviceObject->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM)
{
/* Use the CD-ROM list */
FsList = &IopCdRomFsListHead;
}
else if (DeviceObject->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM)
{
/* Use the tape list */
FsList = &IopTapeFsListHead;
}
/* Make sure that we have a valid list */
if (FsList)
{
/* Check if we should insert it at the top or bottom of the list */
if (DeviceObject->Flags & DO_LOW_PRIORITY_FILESYSTEM)
{
/* At the bottom */
InsertTailList(FsList->Blink, &DeviceObject->Queue.ListEntry);
}
else
{
/* On top */
InsertHeadList(FsList, &DeviceObject->Queue.ListEntry);
}
}
/* Clear the initializing flag */
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
/* Release the FS Lock */
ExReleaseResourceLite(&FileSystemListLock);
KeLeaveCriticalRegion();
/* Notify file systems of the addition */
IopNotifyFileSystemChange(DeviceObject, TRUE);
}
/*
* @implemented
*/
VOID
NTAPI
IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();
/* Acquire the FS lock */
KeEnterCriticalRegion();
ExAcquireResourceExclusiveLite(&FileSystemListLock, TRUE);
/* Simply remove the entry */
RemoveEntryList(&DeviceObject->Queue.ListEntry);
/* And notify all registered file systems */
IopNotifyFileSystemChange(DeviceObject, FALSE);
/* Then release the lock */
ExReleaseResourceLite(&FileSystemListLock);
KeLeaveCriticalRegion();
}
/*
* @implemented
*/
NTSTATUS
NTAPI
IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
IN PDRIVER_FS_NOTIFICATION FSDNotificationProc)
{
PFS_CHANGE_NOTIFY_ENTRY Entry;
PAGED_CODE();
/* Allocate a notification entry */
Entry = ExAllocatePoolWithTag(PagedPool,
sizeof(FS_CHANGE_NOTIFY_ENTRY),
TAG_FS_CHANGE_NOTIFY);
if (!Entry) return(STATUS_INSUFFICIENT_RESOURCES);
/* Save the driver object and notification routine */
Entry->DriverObject = DriverObject;
Entry->FSDNotificationProc = FSDNotificationProc;
/* Insert it into the notification list */
KeAcquireGuardedMutex(&FsChangeNotifyListLock);
InsertTailList(&FsChangeNotifyListHead, &Entry->FsChangeNotifyList);
KeReleaseGuardedMutex(&FsChangeNotifyListLock);
/* Reference the driver */
ObReferenceObject(DriverObject);
return STATUS_SUCCESS;
}
/*
* @implemented
*/
VOID
NTAPI
IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
IN PDRIVER_FS_NOTIFICATION FSDNotificationProc)
{
PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
PLIST_ENTRY NextEntry;
PAGED_CODE();
/* Acquire the list lock */
KeAcquireGuardedMutex(&FsChangeNotifyListLock);
/* Loop the list */
NextEntry = FsChangeNotifyListHead.Flink;
while (NextEntry != &FsChangeNotifyListHead)
{
/* Get the entry */
ChangeEntry = CONTAINING_RECORD(NextEntry,
FS_CHANGE_NOTIFY_ENTRY,
FsChangeNotifyList);
/* Check if it matches this de-registration */
if ((ChangeEntry->DriverObject == DriverObject) &&
(ChangeEntry->FSDNotificationProc == FSDNotificationProc))
{
/* It does, remove it from the list */
RemoveEntryList(&ChangeEntry->FsChangeNotifyList);
ExFreePoolWithTag(ChangeEntry, TAG_FS_CHANGE_NOTIFY);
break;
}
/* Go to the next entry */
NextEntry = NextEntry->Flink;
}
/* Release the lock and dereference the driver */
KeReleaseGuardedMutex(&FsChangeNotifyListLock);
ObDereferenceObject(DriverObject);
}
/*
* @implemented
*/
VOID
NTAPI
IoAcquireVpbSpinLock(OUT PKIRQL Irql)
{
/* Simply acquire the lock */
*Irql = KeAcquireQueuedSpinLock(LockQueueIoVpbLock);
}
/*
* @implemented
*/
VOID
NTAPI
IoReleaseVpbSpinLock(IN KIRQL Irql)
{
/* Just release the lock */
KeReleaseQueuedSpinLock(LockQueueIoVpbLock, Irql);
}
/*
* @unimplemented
*/
NTSTATUS
NTAPI
IoSetSystemPartition(IN PUNICODE_STRING VolumeNameString)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @unimplemented
*/
NTSTATUS
NTAPI
IoVolumeDeviceToDosName(IN PVOID VolumeDeviceObject,
OUT PUNICODE_STRING DosName)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/* EOF */