2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/volume.c
5 * PURPOSE: Volume and File System I/O Support
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Hervé Poussineau (hpoussin@reactos.org)
9 * Pierre Schweitzer (pierre.schweitzer@reactos.org)
12 /* INCLUDES *****************************************************************/
18 #if defined (ALLOC_PRAGMA)
19 #pragma alloc_text(INIT, IoInitFileSystemImplementation)
20 #pragma alloc_text(INIT, IoInitVpbImplementation)
23 /* GLOBALS ******************************************************************/
25 ERESOURCE IopDatabaseResource
;
26 LIST_ENTRY IopDiskFileSystemQueueHead
, IopNetworkFileSystemQueueHead
;
27 LIST_ENTRY IopCdRomFileSystemQueueHead
, IopTapeFileSystemQueueHead
;
28 LIST_ENTRY IopFsNotifyChangeQueueHead
;
29 ULONG IopFsRegistrationOps
;
31 /* PRIVATE FUNCTIONS *********************************************************/
38 IopDecrementDeviceObjectRef(IN PDEVICE_OBJECT DeviceObject
,
39 IN BOOLEAN UnloadIfUnused
)
44 OldIrql
= KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock
);
45 ASSERT(DeviceObject
->ReferenceCount
> 0);
47 if (--DeviceObject
->ReferenceCount
> 0)
49 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock
, OldIrql
);
54 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock
, OldIrql
);
56 /* Here, DO is not referenced any longer, check if we have to unload it */
57 if (UnloadIfUnused
|| IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
&
58 (DOE_UNLOAD_PENDING
| DOE_DELETE_PENDING
| DOE_REMOVE_PENDING
))
60 /* Unload the driver */
61 IopUnloadDevice(DeviceObject
);
70 IopDecrementDeviceObjectHandleCount(IN PDEVICE_OBJECT DeviceObject
)
72 /* Just decrease reference count */
73 IopDecrementDeviceObjectRef(DeviceObject
, FALSE
);
81 IopCheckVpbMounted(IN POPEN_PACKET OpenPacket
,
82 IN PDEVICE_OBJECT DeviceObject
,
83 IN PUNICODE_STRING RemainingName
,
86 BOOLEAN Alertable
, Raw
;
91 IoAcquireVpbSpinLock(&OldIrql
);
93 /* Set VPB mount settings */
94 Raw
= !RemainingName
->Length
&& !OpenPacket
->RelatedFileObject
;
95 Alertable
= (OpenPacket
->CreateOptions
& FILE_SYNCHRONOUS_IO_ALERT
) ?
98 /* Start looping until the VPB is mounted */
99 while (!(DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
))
101 /* Release the lock */
102 IoReleaseVpbSpinLock(OldIrql
);
104 /* Mount the volume */
105 *Status
= IopMountVolume(DeviceObject
,
111 /* Check if we failed or if we were alerted */
112 if (!(NT_SUCCESS(*Status
)) ||
113 (*Status
== STATUS_USER_APC
) ||
114 (*Status
== STATUS_ALERTED
))
116 /* Dereference the device, since IopParseDevice referenced it */
117 IopDereferenceDeviceObject(DeviceObject
, FALSE
);
119 /* Check if it was a total failure */
120 if (!NT_SUCCESS(*Status
)) return NULL
;
122 /* Otherwise we were alerted */
123 *Status
= STATUS_WRONG_VOLUME
;
127 /* Re-acquire the lock */
128 IoAcquireVpbSpinLock(&OldIrql
);
131 /* Make sure the VPB isn't locked */
132 Vpb
= DeviceObject
->Vpb
;
133 if (Vpb
->Flags
& VPB_LOCKED
)
135 /* We're locked, so fail */
136 *Status
= STATUS_ACCESS_DENIED
;
141 /* Success! Reference the VPB */
142 Vpb
->ReferenceCount
++;
145 /* Release the lock and return the VPB */
146 IoReleaseVpbSpinLock(OldIrql
);
155 IopCreateVpb(IN PDEVICE_OBJECT DeviceObject
)
159 /* Allocate the Vpb */
160 Vpb
= ExAllocatePoolWithTag(NonPagedPool
,
163 if (!Vpb
) return STATUS_INSUFFICIENT_RESOURCES
;
165 /* Clear it so we don't waste time manually */
166 RtlZeroMemory(Vpb
, sizeof(VPB
));
168 /* Set the Header and Device Field */
169 Vpb
->Type
= IO_TYPE_VPB
;
170 Vpb
->Size
= sizeof(VPB
);
171 Vpb
->RealDevice
= DeviceObject
;
173 /* Link it to the Device Object */
174 DeviceObject
->Vpb
= Vpb
;
175 return STATUS_SUCCESS
;
183 IopDereferenceVpbAndFree(IN PVPB Vpb
)
187 /* Lock the VPBs and decrease references */
188 IoAcquireVpbSpinLock(&OldIrql
);
189 Vpb
->ReferenceCount
--;
191 /* Check if we're out of references */
192 if (!Vpb
->ReferenceCount
&& Vpb
->RealDevice
->Vpb
== Vpb
&&
193 !(Vpb
->Flags
& VPB_PERSISTENT
))
195 /* Release VPB lock */
196 IoReleaseVpbSpinLock(OldIrql
);
199 ExFreePoolWithTag(Vpb
, TAG_VPB
);
203 /* Release VPB lock */
204 IoReleaseVpbSpinLock(OldIrql
);
213 IopReferenceVerifyVpb(IN PDEVICE_OBJECT DeviceObject
,
214 OUT PDEVICE_OBJECT
*FileSystemObject
,
219 BOOLEAN Result
= FALSE
;
221 /* Lock the VPBs and assume failure */
222 IoAcquireVpbSpinLock(&OldIrql
);
224 *FileSystemObject
= NULL
;
226 /* Get the VPB and make sure it's mounted */
227 LocalVpb
= DeviceObject
->Vpb
;
228 if ((LocalVpb
) && (LocalVpb
->Flags
& VPB_MOUNTED
))
232 *FileSystemObject
= LocalVpb
->DeviceObject
;
235 LocalVpb
->ReferenceCount
++;
239 /* Release the VPB lock and return status */
240 IoReleaseVpbSpinLock(OldIrql
);
246 IopMountInitializeVpb(IN PDEVICE_OBJECT DeviceObject
,
247 IN PDEVICE_OBJECT AttachedDeviceObject
,
254 IoAcquireVpbSpinLock(&OldIrql
);
255 Vpb
= DeviceObject
->Vpb
;
257 /* Set the VPB as mounted and possibly raw */
258 Vpb
->Flags
|= VPB_MOUNTED
| (Raw
? VPB_RAW_MOUNT
: 0);
260 /* Set the stack size */
261 Vpb
->DeviceObject
->StackSize
= AttachedDeviceObject
->StackSize
;
263 /* Add one for the FS Driver */
264 Vpb
->DeviceObject
->StackSize
++;
266 /* Set the VPB in the device extension */
267 IoGetDevObjExtension(Vpb
->DeviceObject
)->Vpb
= Vpb
;
270 Vpb
->ReferenceCount
++;
272 /* Release the VPB lock and return it */
273 IoReleaseVpbSpinLock(OldIrql
);
282 IopNotifyFileSystemChange(IN PDEVICE_OBJECT DeviceObject
,
283 IN BOOLEAN DriverActive
)
285 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry
;
286 PLIST_ENTRY ListEntry
;
289 ListEntry
= IopFsNotifyChangeQueueHead
.Flink
;
290 while (ListEntry
!= &IopFsNotifyChangeQueueHead
)
293 ChangeEntry
= CONTAINING_RECORD(ListEntry
,
294 FS_CHANGE_NOTIFY_ENTRY
,
297 /* Call the notification procedure */
298 ChangeEntry
->FSDNotificationProc(DeviceObject
, DriverActive
);
300 /* Go to the next entry */
301 ListEntry
= ListEntry
->Flink
;
310 IopInterlockedIncrementUlong(IN KSPIN_LOCK_QUEUE_NUMBER Queue
,
316 Irql
= KeAcquireQueuedSpinLock(Queue
);
317 OldValue
= (*Ulong
)++;
318 KeReleaseQueuedSpinLock(Queue
, Irql
);
328 IopInterlockedDecrementUlong(IN KSPIN_LOCK_QUEUE_NUMBER Queue
,
334 Irql
= KeAcquireQueuedSpinLock(Queue
);
335 OldValue
= (*Ulong
)--;
336 KeReleaseQueuedSpinLock(Queue
, Irql
);
346 IopShutdownBaseFileSystems(IN PLIST_ENTRY ListHead
)
348 PLIST_ENTRY ListEntry
;
349 PDEVICE_OBJECT DeviceObject
;
350 IO_STATUS_BLOCK StatusBlock
;
355 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
357 /* Get the first entry and start looping */
358 ListEntry
= ListHead
->Flink
;
359 while (ListEntry
!= ListHead
)
361 /* Get the device object */
362 DeviceObject
= CONTAINING_RECORD(ListEntry
,
366 /* Get the attached device */
367 DeviceObject
= IoGetAttachedDevice(DeviceObject
);
369 ObReferenceObject(DeviceObject
);
370 IopInterlockedIncrementUlong(LockQueueIoDatabaseLock
, (PULONG
)&DeviceObject
->ReferenceCount
);
372 /* Build the shutdown IRP and call the driver */
373 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN
,
382 Status
= IoCallDriver(DeviceObject
, Irp
);
383 if (Status
== STATUS_PENDING
)
385 /* Wait on the driver */
386 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
390 /* Reset the event */
391 KeClearEvent(&Event
);
393 IopDecrementDeviceObjectRef(DeviceObject
, FALSE
);
394 ObDereferenceObject(DeviceObject
);
396 /* Go to the next entry */
397 ListEntry
= ListEntry
->Flink
;
406 IopLoadFileSystemDriver(IN PDEVICE_OBJECT DeviceObject
)
408 IO_STATUS_BLOCK IoStatusBlock
;
409 PIO_STACK_LOCATION StackPtr
;
413 PDEVICE_OBJECT AttachedDeviceObject
= DeviceObject
;
416 /* Loop as long as we're attached */
417 while (AttachedDeviceObject
->AttachedDevice
)
419 /* Get the attached device object */
420 AttachedDeviceObject
= AttachedDeviceObject
->AttachedDevice
;
423 /* Initialize the event and build the IRP */
424 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
425 Irp
= IoBuildDeviceIoControlRequest(IRP_MJ_DEVICE_CONTROL
,
426 AttachedDeviceObject
,
436 /* Set the major and minor functions */
437 StackPtr
= IoGetNextIrpStackLocation(Irp
);
438 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
439 StackPtr
->MinorFunction
= IRP_MN_LOAD_FILE_SYSTEM
;
441 /* Call the driver */
442 Status
= IoCallDriver(AttachedDeviceObject
, Irp
);
443 if (Status
== STATUS_PENDING
)
446 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
450 /* Dereference DO - FsRec? - Comment out call, since it breaks up 2nd stage boot, needs more research. */
451 // IopDecrementDeviceObjectRef(AttachedDeviceObject, TRUE);
459 IopMountVolume(IN PDEVICE_OBJECT DeviceObject
,
460 IN BOOLEAN AllowRawMount
,
461 IN BOOLEAN DeviceIsLocked
,
462 IN BOOLEAN Alertable
,
467 IO_STATUS_BLOCK IoStatusBlock
;
469 PIO_STACK_LOCATION StackPtr
;
470 PLIST_ENTRY FsList
, ListEntry
;
471 LIST_ENTRY LocalList
;
472 PDEVICE_OBJECT AttachedDeviceObject
= DeviceObject
;
473 PDEVICE_OBJECT FileSystemDeviceObject
, ParentFsDeviceObject
;
474 ULONG FsStackOverhead
, RegistrationOps
;
477 /* Check if the device isn't already locked */
480 /* Lock it ourselves */
481 Status
= KeWaitForSingleObject(&DeviceObject
->DeviceLock
,
486 if ((Status
== STATUS_ALERTED
) || (Status
== STATUS_USER_APC
))
488 /* Don't mount if we were interrupted */
493 /* Acquire the FS Lock*/
494 KeEnterCriticalRegion();
495 ExAcquireResourceSharedLite(&IopDatabaseResource
, TRUE
);
497 /* Make sure we weren't already mounted */
498 if (!(DeviceObject
->Vpb
->Flags
& (VPB_MOUNTED
| VPB_REMOVE_PENDING
)))
500 /* Initialize the event to wait on */
501 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
503 /* Remove the verify flag and get the actual device to mount */
504 DeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
505 while (AttachedDeviceObject
->AttachedDevice
)
507 /* Get the next one */
508 AttachedDeviceObject
= AttachedDeviceObject
->AttachedDevice
;
512 ObReferenceObject(AttachedDeviceObject
);
514 /* For a mount operation, this can only be a Disk, CD-ROM or tape */
515 if ((DeviceObject
->DeviceType
== FILE_DEVICE_DISK
) ||
516 (DeviceObject
->DeviceType
== FILE_DEVICE_VIRTUAL_DISK
))
518 /* Use the disk list */
519 FsList
= &IopDiskFileSystemQueueHead
;
521 else if (DeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM
)
523 /* Use the CD-ROM list */
524 FsList
= &IopCdRomFileSystemQueueHead
;
528 /* It's gotta be a tape... */
529 FsList
= &IopTapeFileSystemQueueHead
;
532 /* Now loop the fs list until one of the file systems accepts us */
533 Status
= STATUS_UNSUCCESSFUL
;
534 ListEntry
= FsList
->Flink
;
535 while ((ListEntry
!= FsList
) && !(NT_SUCCESS(Status
)))
538 * If we're not allowed to mount this volume and this is our last
539 * (but not only) chance to mount it...
541 if (!(AllowRawMount
) &&
542 (ListEntry
->Flink
== FsList
) &&
543 (ListEntry
!= FsList
->Flink
))
545 /* Then fail this mount request */
550 * Also check if this is a raw mount and there are other file
551 * systems on the list.
553 if ((DeviceObject
->Vpb
->Flags
& VPB_RAW_MOUNT
) &&
554 (ListEntry
->Flink
!= FsList
))
556 /* Then skip this entry */
557 ListEntry
= ListEntry
->Flink
;
561 /* Get the Device Object for this FS */
562 FileSystemDeviceObject
= CONTAINING_RECORD(ListEntry
,
565 ParentFsDeviceObject
= FileSystemDeviceObject
;
568 * If this file system device is attached to some other device,
569 * then we must make sure to increase the stack size for the IRP.
570 * The default is +1, for the FS device itself.
573 while (FileSystemDeviceObject
->AttachedDevice
)
575 /* Get the next attached device and increase overhead */
576 FileSystemDeviceObject
= FileSystemDeviceObject
->
581 /* Clear the event */
582 KeClearEvent(&Event
);
584 /* Allocate the IRP */
585 Irp
= IoAllocateIrp(AttachedDeviceObject
->StackSize
+
586 (UCHAR
)FsStackOverhead
,
591 Status
= STATUS_INSUFFICIENT_RESOURCES
;
596 Irp
->UserIosb
= &IoStatusBlock
;
597 Irp
->UserEvent
= &Event
;
598 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
599 Irp
->Flags
= IRP_MOUNT_COMPLETION
| IRP_SYNCHRONOUS_PAGING_IO
;
600 Irp
->RequestorMode
= KernelMode
;
602 /* Get the I/O Stack location and set it up */
603 StackPtr
= IoGetNextIrpStackLocation(Irp
);
604 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
605 StackPtr
->MinorFunction
= IRP_MN_MOUNT_VOLUME
;
606 StackPtr
->Flags
= AllowRawMount
;
607 StackPtr
->Parameters
.MountVolume
.Vpb
= DeviceObject
->Vpb
;
608 StackPtr
->Parameters
.MountVolume
.DeviceObject
=
609 AttachedDeviceObject
;
611 /* Save registration operations */
612 RegistrationOps
= IopFsRegistrationOps
;
615 IopInterlockedIncrementUlong(LockQueueIoDatabaseLock
, (PULONG
)&DeviceObject
->ReferenceCount
);
616 ExReleaseResourceLite(&IopDatabaseResource
);
618 /* Call the driver */
619 Status
= IoCallDriver(FileSystemDeviceObject
, Irp
);
620 if (Status
== STATUS_PENDING
)
623 KeWaitForSingleObject(&Event
,
628 Status
= IoStatusBlock
.Status
;
631 ExAcquireResourceSharedLite(&IopDatabaseResource
, TRUE
);
632 IopInterlockedDecrementUlong(LockQueueIoDatabaseLock
, (PULONG
)&DeviceObject
->ReferenceCount
);
634 /* Check if mounting was successful */
635 if (NT_SUCCESS(Status
))
638 *Vpb
= IopMountInitializeVpb(DeviceObject
,
639 AttachedDeviceObject
,
640 (DeviceObject
->Vpb
->Flags
&
645 /* Check if we failed because of the user */
646 if ((IoIsErrorUserInduced(Status
)) &&
647 (IoStatusBlock
.Information
== 1))
649 /* Break out and fail */
653 /* If there were registration operations in the meanwhile */
654 if (RegistrationOps
!= IopFsRegistrationOps
)
656 /* We need to setup a local list to pickup where we left */
657 LocalList
.Flink
= FsList
->Flink
;
658 ListEntry
= &LocalList
;
660 Status
= STATUS_UNRECOGNIZED_VOLUME
;
663 /* Otherwise, check if we need to load the FS driver */
664 if (Status
== STATUS_FS_DRIVER_REQUIRED
)
666 /* We need to release the lock */
667 IopInterlockedIncrementUlong(LockQueueIoDatabaseLock
, (PULONG
)&DeviceObject
->ReferenceCount
);
668 ExReleaseResourceLite(&IopDatabaseResource
);
670 /* Release the device lock if we're holding it */
673 KeSetEvent(&DeviceObject
->DeviceLock
, 0, FALSE
);
676 /* Leave critical section */
677 KeLeaveCriticalRegion();
680 IopLoadFileSystemDriver(ParentFsDeviceObject
);
682 /* Check if the device isn't already locked */
685 /* Lock it ourselves */
686 Status
= KeWaitForSingleObject(&DeviceObject
->
692 if ((Status
== STATUS_ALERTED
) ||
693 (Status
== STATUS_USER_APC
))
695 /* Don't mount if we were interrupted */
696 ObDereferenceObject(AttachedDeviceObject
);
701 /* Reacquire the lock */
702 KeEnterCriticalRegion();
703 ExAcquireResourceSharedLite(&IopDatabaseResource
, TRUE
);
705 /* When we released the lock, make sure nobody beat us */
706 if (DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
)
708 /* Someone did, break out */
709 Status
= STATUS_SUCCESS
;
713 /* Start over by setting a failure */
714 Status
= STATUS_UNRECOGNIZED_VOLUME
;
716 /* We need to setup a local list to pickup where we left */
717 LocalList
.Flink
= FsList
->Flink
;
718 ListEntry
= &LocalList
;
722 * Check if we failed with any other error then an unrecognized
723 * volume, and if this request doesn't allow mounting the raw
726 if (!(AllowRawMount
) &&
727 (Status
!= STATUS_UNRECOGNIZED_VOLUME
) &&
728 (FsRtlIsTotalDeviceFailure(Status
)))
730 /* Break out and give up */
735 /* Go to the next FS entry */
736 ListEntry
= ListEntry
->Flink
;
739 /* Dereference the device if we failed */
740 if (!NT_SUCCESS(Status
)) ObDereferenceObject(AttachedDeviceObject
);
742 else if (DeviceObject
->Vpb
->Flags
& VPB_REMOVE_PENDING
)
744 /* Someone wants to remove us */
745 Status
= STATUS_DEVICE_DOES_NOT_EXIST
;
749 /* Someone already mounted us */
750 Status
= STATUS_SUCCESS
;
753 /* Release the FS lock */
754 ExReleaseResourceLite(&IopDatabaseResource
);
755 KeLeaveCriticalRegion();
757 /* Release the device lock if we're holding it */
758 if (!DeviceIsLocked
) KeSetEvent(&DeviceObject
->DeviceLock
, 0, FALSE
);
760 /* Check if we failed to mount the boot partition */
761 if ((!NT_SUCCESS(Status
)) &&
762 (DeviceObject
->Flags
& DO_SYSTEM_BOOT_PARTITION
) &&
763 ExpInitializationPhase
< 2)
765 /* Bugcheck the system */
766 KeBugCheckEx(INACCESSIBLE_BOOT_DEVICE
,
767 (ULONG_PTR
)DeviceObject
,
773 /* Return the mount status */
782 IopNotifyAlreadyRegisteredFileSystems(IN PLIST_ENTRY ListHead
,
783 IN PDRIVER_FS_NOTIFICATION DriverNotificationRoutine
,
786 PLIST_ENTRY ListEntry
;
787 PDEVICE_OBJECT DeviceObject
;
789 /* Browse the whole list */
790 ListEntry
= ListHead
->Flink
;
791 while (ListEntry
!= ListHead
)
793 /* Check if we reached rawfs and if we have to skip it */
794 if (ListEntry
->Flink
== ListHead
&& SkipRawFs
)
799 /* Otherwise, get DO and notify */
800 DeviceObject
= CONTAINING_RECORD(ListEntry
,
804 DriverNotificationRoutine(DeviceObject
, TRUE
);
806 /* Go to the next entry */
807 ListEntry
= ListEntry
->Flink
;
811 /* PUBLIC FUNCTIONS **********************************************************/
818 IoEnumerateRegisteredFiltersList(OUT PDRIVER_OBJECT
*DriverObjectList
,
819 IN ULONG DriverObjectListSize
,
820 OUT PULONG ActualNumberDriverObjects
)
822 PLIST_ENTRY ListEntry
;
823 NTSTATUS Status
= STATUS_SUCCESS
;
824 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry
;
825 ULONG ListSize
= 0, MaximumSize
= DriverObjectListSize
/ sizeof(PDRIVER_OBJECT
);
827 /* Acquire the FS lock */
828 KeEnterCriticalRegion();
829 ExAcquireResourceExclusiveLite(&IopDatabaseResource
, TRUE
);
831 /* Browse the whole list */
832 ListEntry
= IopFsNotifyChangeQueueHead
.Flink
;
833 while (ListEntry
!= &IopFsNotifyChangeQueueHead
)
835 ChangeEntry
= CONTAINING_RECORD(ListEntry
,
836 FS_CHANGE_NOTIFY_ENTRY
,
839 /* If buffer is still big enough */
840 if (ListSize
< MaximumSize
)
842 /* Reference the driver object */
843 ObReferenceObject(ChangeEntry
->DriverObject
);
844 /* And pass it to the caller */
845 DriverObjectList
[ListSize
] = ChangeEntry
->DriverObject
;
849 Status
= STATUS_BUFFER_TOO_SMALL
;
852 /* Increase size counter */
855 /* Go to the next entry */
856 ListEntry
= ListEntry
->Flink
;
859 /* Return list size */
860 *ActualNumberDriverObjects
= ListSize
;
862 /* Release the FS lock */
863 ExReleaseResourceLite(&IopDatabaseResource
);
864 KeLeaveCriticalRegion();
874 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject
,
875 IN BOOLEAN AllowRawMount
)
877 IO_STATUS_BLOCK IoStatusBlock
;
878 PIO_STACK_LOCATION StackPtr
;
881 NTSTATUS Status
, VpbStatus
;
882 PDEVICE_OBJECT FileSystemDeviceObject
;
884 //BOOLEAN WasNotMounted = TRUE;
886 /* Wait on the device lock */
887 Status
= KeWaitForSingleObject(&DeviceObject
->DeviceLock
,
892 ASSERT(Status
== STATUS_SUCCESS
);
894 /* Reference the VPB */
895 if (IopReferenceVerifyVpb(DeviceObject
, &FileSystemDeviceObject
, &Vpb
))
897 /* Initialize the event */
898 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
900 /* Find the actual File System DO */
901 //WasNotMounted = FALSE;
902 FileSystemDeviceObject
= DeviceObject
->Vpb
->DeviceObject
;
903 while (FileSystemDeviceObject
->AttachedDevice
)
905 /* Go to the next one */
906 FileSystemDeviceObject
= FileSystemDeviceObject
->AttachedDevice
;
909 /* Allocate the IRP */
910 Irp
= IoAllocateIrp(FileSystemDeviceObject
->StackSize
, FALSE
);
913 Status
= STATUS_INSUFFICIENT_RESOURCES
;
918 Irp
->UserIosb
= &IoStatusBlock
;
919 Irp
->UserEvent
= &Event
;
920 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
921 Irp
->Flags
= IRP_MOUNT_COMPLETION
| IRP_SYNCHRONOUS_PAGING_IO
;
922 Irp
->RequestorMode
= KernelMode
;
924 /* Get the I/O Stack location and set it */
925 StackPtr
= IoGetNextIrpStackLocation(Irp
);
926 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
927 StackPtr
->MinorFunction
= IRP_MN_VERIFY_VOLUME
;
928 StackPtr
->Flags
= AllowRawMount
? SL_ALLOW_RAW_MOUNT
: 0;
929 StackPtr
->Parameters
.VerifyVolume
.Vpb
= Vpb
;
930 StackPtr
->Parameters
.VerifyVolume
.DeviceObject
=
931 DeviceObject
->Vpb
->DeviceObject
;
933 /* Call the driver */
934 Status
= IoCallDriver(FileSystemDeviceObject
, Irp
);
935 if (Status
== STATUS_PENDING
)
938 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
939 Status
= IoStatusBlock
.Status
;
942 /* Dereference the VPB */
943 IopDereferenceVpbAndFree(Vpb
);
946 /* Check if we had the wrong volume or didn't mount at all */
947 if (Status
== STATUS_WRONG_VOLUME
)
950 VpbStatus
= IopCreateVpb(DeviceObject
);
951 if (NT_SUCCESS(VpbStatus
))
953 PoVolumeDevice(DeviceObject
);
956 VpbStatus
= IopMountVolume(DeviceObject
,
962 /* If we got a new VPB, dereference it */
965 IopInterlockedDecrementUlong(LockQueueIoVpbLock
, &NewVpb
->ReferenceCount
);
969 /* If we failed, remove the verify flag */
970 if (!NT_SUCCESS(VpbStatus
)) DeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
974 /* Signal the device lock and return */
975 KeSetEvent(&DeviceObject
->DeviceLock
, IO_NO_INCREMENT
, FALSE
);
984 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject
)
986 PLIST_ENTRY FsList
= NULL
;
989 /* Acquire the FS lock */
990 KeEnterCriticalRegion();
991 ExAcquireResourceExclusiveLite(&IopDatabaseResource
, TRUE
);
993 /* Check what kind of FS this is */
994 if (DeviceObject
->DeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
)
996 /* Use the disk list */
997 FsList
= &IopDiskFileSystemQueueHead
;
999 else if (DeviceObject
->DeviceType
== FILE_DEVICE_NETWORK_FILE_SYSTEM
)
1001 /* Use the network device list */
1002 FsList
= &IopNetworkFileSystemQueueHead
;
1004 else if (DeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM_FILE_SYSTEM
)
1006 /* Use the CD-ROM list */
1007 FsList
= &IopCdRomFileSystemQueueHead
;
1009 else if (DeviceObject
->DeviceType
== FILE_DEVICE_TAPE_FILE_SYSTEM
)
1011 /* Use the tape list */
1012 FsList
= &IopTapeFileSystemQueueHead
;
1015 /* Make sure that we have a valid list */
1018 /* Check if we should insert it at the top or bottom of the list */
1019 if (DeviceObject
->Flags
& DO_LOW_PRIORITY_FILESYSTEM
)
1022 InsertTailList(FsList
->Blink
, &DeviceObject
->Queue
.ListEntry
);
1027 InsertHeadList(FsList
, &DeviceObject
->Queue
.ListEntry
);
1031 /* Update operations counter */
1032 IopFsRegistrationOps
++;
1034 /* Clear the initializing flag */
1035 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1037 /* Notify file systems of the addition */
1038 IopNotifyFileSystemChange(DeviceObject
, TRUE
);
1040 /* Release the FS Lock */
1041 ExReleaseResourceLite(&IopDatabaseResource
);
1042 KeLeaveCriticalRegion();
1044 /* Ensure driver won't be unloaded */
1045 IopInterlockedIncrementUlong(LockQueueIoDatabaseLock
, (PULONG
)&DeviceObject
->ReferenceCount
);
1053 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject
)
1057 /* Acquire the FS lock */
1058 KeEnterCriticalRegion();
1059 ExAcquireResourceExclusiveLite(&IopDatabaseResource
, TRUE
);
1061 /* Simply remove the entry - if queued */
1062 if (DeviceObject
->Queue
.ListEntry
.Flink
)
1064 RemoveEntryList(&DeviceObject
->Queue
.ListEntry
);
1067 /* And notify all registered file systems */
1068 IopNotifyFileSystemChange(DeviceObject
, FALSE
);
1070 /* Update operations counter */
1071 IopFsRegistrationOps
++;
1073 /* Then release the lock */
1074 ExReleaseResourceLite(&IopDatabaseResource
);
1075 KeLeaveCriticalRegion();
1077 /* Decrease reference count to allow unload */
1078 IopInterlockedDecrementUlong(LockQueueIoDatabaseLock
, (PULONG
)&DeviceObject
->ReferenceCount
);
1086 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject
,
1087 IN PDRIVER_FS_NOTIFICATION DriverNotificationRoutine
)
1089 PFS_CHANGE_NOTIFY_ENTRY Entry
;
1092 /* Acquire the list lock */
1093 KeEnterCriticalRegion();
1094 ExAcquireResourceExclusiveLite(&IopDatabaseResource
, TRUE
);
1096 /* Check if that driver is already registered (successive calls)
1097 * See MSDN note: http://msdn.microsoft.com/en-us/library/ff548499%28v=vs.85%29.aspx
1099 if (!IsListEmpty(&IopFsNotifyChangeQueueHead
))
1101 Entry
= CONTAINING_RECORD(IopFsNotifyChangeQueueHead
.Blink
,
1102 FS_CHANGE_NOTIFY_ENTRY
,
1103 FsChangeNotifyList
);
1105 if (Entry
->DriverObject
== DriverObject
&&
1106 Entry
->FSDNotificationProc
== DriverNotificationRoutine
)
1108 /* Release the lock */
1109 ExReleaseResourceLite(&IopDatabaseResource
);
1111 return STATUS_DEVICE_ALREADY_ATTACHED
;
1115 /* Allocate a notification entry */
1116 Entry
= ExAllocatePoolWithTag(PagedPool
,
1117 sizeof(FS_CHANGE_NOTIFY_ENTRY
),
1118 TAG_FS_CHANGE_NOTIFY
);
1121 /* Release the lock */
1122 ExReleaseResourceLite(&IopDatabaseResource
);
1124 return STATUS_INSUFFICIENT_RESOURCES
;
1127 /* Save the driver object and notification routine */
1128 Entry
->DriverObject
= DriverObject
;
1129 Entry
->FSDNotificationProc
= DriverNotificationRoutine
;
1131 /* Insert it into the notification list */
1132 InsertTailList(&IopFsNotifyChangeQueueHead
, &Entry
->FsChangeNotifyList
);
1134 /* Start notifying all already present FS */
1135 IopNotifyAlreadyRegisteredFileSystems(&IopNetworkFileSystemQueueHead
, DriverNotificationRoutine
, FALSE
);
1136 IopNotifyAlreadyRegisteredFileSystems(&IopCdRomFileSystemQueueHead
, DriverNotificationRoutine
, TRUE
);
1137 IopNotifyAlreadyRegisteredFileSystems(&IopDiskFileSystemQueueHead
, DriverNotificationRoutine
, TRUE
);
1138 IopNotifyAlreadyRegisteredFileSystems(&IopTapeFileSystemQueueHead
, DriverNotificationRoutine
, TRUE
);
1140 /* Release the lock */
1141 ExReleaseResourceLite(&IopDatabaseResource
);
1142 KeLeaveCriticalRegion();
1144 /* Reference the driver */
1145 ObReferenceObject(DriverObject
);
1146 return STATUS_SUCCESS
;
1154 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject
,
1155 IN PDRIVER_FS_NOTIFICATION FSDNotificationProc
)
1157 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry
;
1158 PLIST_ENTRY NextEntry
;
1161 /* Acquire the list lock */
1162 KeEnterCriticalRegion();
1163 ExAcquireResourceExclusiveLite(&IopDatabaseResource
, TRUE
);
1166 NextEntry
= IopFsNotifyChangeQueueHead
.Flink
;
1167 while (NextEntry
!= &IopFsNotifyChangeQueueHead
)
1170 ChangeEntry
= CONTAINING_RECORD(NextEntry
,
1171 FS_CHANGE_NOTIFY_ENTRY
,
1172 FsChangeNotifyList
);
1174 /* Check if it matches this de-registration */
1175 if ((ChangeEntry
->DriverObject
== DriverObject
) &&
1176 (ChangeEntry
->FSDNotificationProc
== FSDNotificationProc
))
1178 /* It does, remove it from the list */
1179 RemoveEntryList(&ChangeEntry
->FsChangeNotifyList
);
1180 ExFreePoolWithTag(ChangeEntry
, TAG_FS_CHANGE_NOTIFY
);
1184 /* Go to the next entry */
1185 NextEntry
= NextEntry
->Flink
;
1188 /* Release the lock and dereference the driver */
1189 ExReleaseResourceLite(&IopDatabaseResource
);
1190 KeLeaveCriticalRegion();
1192 /* Dereference the driver */
1193 ObDereferenceObject(DriverObject
);
1201 IoAcquireVpbSpinLock(OUT PKIRQL Irql
)
1203 /* Simply acquire the lock */
1204 *Irql
= KeAcquireQueuedSpinLock(LockQueueIoVpbLock
);
1212 IoReleaseVpbSpinLock(IN KIRQL Irql
)
1214 /* Just release the lock */
1215 KeReleaseQueuedSpinLock(LockQueueIoVpbLock
, Irql
);
1223 IoSetSystemPartition(IN PUNICODE_STRING VolumeNameString
)
1226 HANDLE RootHandle
, KeyHandle
;
1227 UNICODE_STRING HKLMSystem
, KeyString
;
1228 WCHAR Buffer
[sizeof(L
"SystemPartition") / sizeof(WCHAR
)];
1230 RtlInitUnicodeString(&HKLMSystem
, L
"\\REGISTRY\\MACHINE\\SYSTEM");
1232 /* Open registry to save data (HKLM\SYSTEM) */
1233 Status
= IopOpenRegistryKeyEx(&RootHandle
, 0, &HKLMSystem
, KEY_ALL_ACCESS
);
1234 if (!NT_SUCCESS(Status
))
1239 /* Create or open Setup subkey */
1240 KeyString
.Buffer
= Buffer
;
1241 KeyString
.Length
= sizeof(L
"Setup") - sizeof(UNICODE_NULL
);
1242 KeyString
.MaximumLength
= sizeof(L
"Setup");
1243 RtlCopyMemory(Buffer
, L
"Setup", sizeof(L
"Setup"));
1244 Status
= IopCreateRegistryKeyEx(&KeyHandle
,
1248 REG_OPTION_NON_VOLATILE
,
1250 ZwClose(RootHandle
);
1251 if (!NT_SUCCESS(Status
))
1256 /* Store caller value */
1257 KeyString
.Length
= sizeof(L
"SystemPartition") - sizeof(UNICODE_NULL
);
1258 KeyString
.MaximumLength
= sizeof(L
"SystemPartition");
1259 RtlCopyMemory(Buffer
, L
"SystemPartition", sizeof(L
"SystemPartition"));
1260 Status
= ZwSetValueKey(KeyHandle
,
1264 VolumeNameString
->Buffer
,
1265 VolumeNameString
->Length
+ sizeof(UNICODE_NULL
));
1276 IoVolumeDeviceToDosName(IN PVOID VolumeDeviceObject
,
1277 OUT PUNICODE_STRING DosName
)
1283 PFILE_OBJECT FileObject
;
1284 PDEVICE_OBJECT DeviceObject
;
1285 IO_STATUS_BLOCK IoStatusBlock
;
1286 UNICODE_STRING MountMgrDevice
;
1287 MOUNTMGR_VOLUME_PATHS VolumePath
;
1288 PMOUNTMGR_VOLUME_PATHS VolumePathPtr
;
1290 * This variable with be required to query device name.
1291 * It's based on MOUNTDEV_NAME (mountmgr.h).
1292 * Doing it that way will prevent dyn memory allocation.
1293 * Device name won't be longer.
1298 WCHAR DeviceName
[256];
1303 /* First step, getting device name */
1304 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
1305 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
1306 VolumeDeviceObject
, NULL
, 0,
1307 &DeviceName
, sizeof(DeviceName
),
1308 FALSE
, &Event
, &IoStatusBlock
);
1311 return STATUS_INSUFFICIENT_RESOURCES
;
1314 Status
= IoCallDriver(VolumeDeviceObject
, Irp
);
1315 if (Status
== STATUS_PENDING
)
1317 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1318 Status
= IoStatusBlock
.Status
;
1321 if (!NT_SUCCESS(Status
))
1326 /* Now that we have the device name, we can query the MountMgr
1327 * So, get its device object first.
1329 RtlInitUnicodeString(&MountMgrDevice
, MOUNTMGR_DEVICE_NAME
);
1330 Status
= IoGetDeviceObjectPointer(&MountMgrDevice
, FILE_READ_ATTRIBUTES
,
1331 &FileObject
, &DeviceObject
);
1332 if (!NT_SUCCESS(Status
))
1337 /* Then, use the proper IOCTL to query the DOS name */
1338 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
1339 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH
,
1340 DeviceObject
, &DeviceName
, sizeof(DeviceName
),
1341 &VolumePath
, sizeof(VolumePath
),
1342 FALSE
, &Event
, &IoStatusBlock
);
1345 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1349 Status
= IoCallDriver(VolumeDeviceObject
, Irp
);
1350 if (Status
== STATUS_PENDING
)
1352 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1353 Status
= IoStatusBlock
.Status
;
1356 /* Only tolerated failure here is buffer too small, which is
1359 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_OVERFLOW
)
1364 /* Compute needed size to store DOS name.
1365 * Even if MOUNTMGR_VOLUME_PATHS allows bigger
1366 * name lengths than MAXUSHORT, we can't use
1367 * them, because we have to return this in an UNICODE_STRING
1368 * that stores length on USHORT.
1370 Length
= VolumePath
.MultiSzLength
+ sizeof(VolumePath
);
1371 if (Length
> MAXUSHORT
)
1373 Status
= STATUS_INVALID_BUFFER_SIZE
;
1377 /* Reallocate memory, even in case of success, because
1378 * that's the buffer that will be returned to caller
1380 VolumePathPtr
= ExAllocatePoolWithTag(PagedPool
, Length
, 'D2d ');
1383 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1387 /* Requery DOS path with proper size */
1388 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
1389 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH
,
1390 DeviceObject
, &DeviceName
, sizeof(DeviceName
),
1391 VolumePathPtr
, Length
,
1392 FALSE
, &Event
, &IoStatusBlock
);
1395 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1399 Status
= IoCallDriver(VolumeDeviceObject
, Irp
);
1400 if (Status
== STATUS_PENDING
)
1402 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1403 Status
= IoStatusBlock
.Status
;
1406 if (!NT_SUCCESS(Status
))
1411 /* Set output string */
1412 DosName
->Length
= (USHORT
)VolumePathPtr
->MultiSzLength
;
1413 DosName
->MaximumLength
= (USHORT
)VolumePathPtr
->MultiSzLength
+ sizeof(UNICODE_NULL
);
1414 /* Our MOUNTMGR_VOLUME_PATHS will be used as output buffer */
1415 DosName
->Buffer
= (PWSTR
)VolumePathPtr
;
1416 /* Move name at the begin, RtlMoveMemory is OK with overlapping */
1417 RtlMoveMemory(DosName
->Buffer
, VolumePathPtr
->MultiSz
, VolumePathPtr
->MultiSzLength
);
1418 DosName
->Buffer
[DosName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1420 /* DON'T release buffer, just dereference FO, and return success */
1421 Status
= STATUS_SUCCESS
;
1425 ExFreePoolWithTag(VolumePathPtr
, 'D2d ');
1428 ObDereferenceObject(FileObject
);