3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/fs.c
6 * PURPOSE: Filesystem functions
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
11 /* INCLUDES *****************************************************************/
15 #include <internal/debug.h>
17 #if defined (ALLOC_PRAGMA)
18 #pragma alloc_text(INIT, IoInitFileSystemImplementation)
21 /* TYPES *******************************************************************/
23 typedef struct _FILE_SYSTEM_OBJECT
25 PDEVICE_OBJECT DeviceObject
;
27 } FILE_SYSTEM_OBJECT
, *PFILE_SYSTEM_OBJECT
;
29 typedef struct _FS_CHANGE_NOTIFY_ENTRY
31 LIST_ENTRY FsChangeNotifyList
;
32 PDRIVER_OBJECT DriverObject
;
33 PDRIVER_FS_NOTIFICATION FSDNotificationProc
;
34 } FS_CHANGE_NOTIFY_ENTRY
, *PFS_CHANGE_NOTIFY_ENTRY
;
36 /* GLOBALS ******************************************************************/
38 static ERESOURCE FileSystemListLock
;
39 static LIST_ENTRY FileSystemListHead
;
41 static KGUARDED_MUTEX FsChangeNotifyListLock
;
42 static LIST_ENTRY FsChangeNotifyListHead
;
45 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject
,
46 BOOLEAN DriverActive
);
49 /* FUNCTIONS *****************************************************************/
57 IN PDEVICE_OBJECT DeviceObject
,
58 IN PFILE_OBJECT FileObject
65 IoInitFileSystemImplementation(VOID
)
67 InitializeListHead(&FileSystemListHead
);
68 ExInitializeResourceLite(&FileSystemListLock
);
70 InitializeListHead(&FsChangeNotifyListHead
);
71 KeInitializeGuardedMutex(&FsChangeNotifyListLock
);
76 IoShutdownRegisteredFileSystems(VOID
)
78 FILE_SYSTEM_OBJECT
* current
;
81 IO_STATUS_BLOCK IoStatusBlock
;
84 DPRINT("IoShutdownRegisteredFileSystems()\n");
86 KeEnterCriticalRegion();
87 ExAcquireResourceSharedLite(&FileSystemListLock
,TRUE
);
88 KeInitializeEvent(&Event
,
92 LIST_FOR_EACH(current
, &FileSystemListHead
, FILE_SYSTEM_OBJECT
,Entry
)
94 /* send IRP_MJ_SHUTDOWN */
95 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN
,
96 current
->DeviceObject
,
103 Status
= IoCallDriver(current
->DeviceObject
,Irp
);
104 if (Status
== STATUS_PENDING
)
106 KeWaitForSingleObject(&Event
,
114 ExReleaseResourceLite(&FileSystemListLock
);
115 KeLeaveCriticalRegion();
120 IopMountFileSystem(PDEVICE_OBJECT DeviceObject
,
121 PDEVICE_OBJECT DeviceToMount
)
123 IO_STATUS_BLOCK IoStatusBlock
;
124 PIO_STACK_LOCATION StackPtr
;
129 DPRINT("IopMountFileSystem(DeviceObject 0x%p, DeviceToMount 0x%p)\n",
130 DeviceObject
,DeviceToMount
);
132 ASSERT_IRQL(PASSIVE_LEVEL
);
134 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
135 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, TRUE
);
138 return(STATUS_INSUFFICIENT_RESOURCES
);
141 Irp
->UserIosb
= &IoStatusBlock
;
142 DPRINT("Irp->UserIosb 0x%p\n", Irp
->UserIosb
);
143 Irp
->UserEvent
= &Event
;
144 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
146 StackPtr
= IoGetNextIrpStackLocation(Irp
);
147 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
148 StackPtr
->MinorFunction
= IRP_MN_MOUNT_VOLUME
;
150 StackPtr
->Control
= 0;
151 StackPtr
->DeviceObject
= DeviceObject
;
152 StackPtr
->FileObject
= NULL
;
153 StackPtr
->CompletionRoutine
= NULL
;
155 StackPtr
->Parameters
.MountVolume
.Vpb
= DeviceToMount
->Vpb
;
156 StackPtr
->Parameters
.MountVolume
.DeviceObject
= DeviceToMount
;
158 Status
= IoCallDriver(DeviceObject
,Irp
);
159 if (Status
==STATUS_PENDING
)
161 KeWaitForSingleObject(&Event
,Executive
,KernelMode
,FALSE
,NULL
);
162 Status
= IoStatusBlock
.Status
;
170 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject
)
172 IO_STATUS_BLOCK IoStatusBlock
;
173 PIO_STACK_LOCATION StackPtr
;
178 DPRINT("IopLoadFileSystem(DeviceObject 0x%p)\n", DeviceObject
);
180 ASSERT_IRQL(PASSIVE_LEVEL
);
182 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
183 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, TRUE
);
186 return(STATUS_INSUFFICIENT_RESOURCES
);
189 Irp
->UserIosb
= &IoStatusBlock
;
190 DPRINT("Irp->UserIosb 0x%p\n", Irp
->UserIosb
);
191 Irp
->UserEvent
= &Event
;
192 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
194 StackPtr
= IoGetNextIrpStackLocation(Irp
);
195 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
196 StackPtr
->MinorFunction
= IRP_MN_LOAD_FILE_SYSTEM
;
198 StackPtr
->Control
= 0;
199 StackPtr
->DeviceObject
= DeviceObject
;
200 StackPtr
->FileObject
= NULL
;
201 StackPtr
->CompletionRoutine
= NULL
;
203 Status
= IoCallDriver(DeviceObject
,Irp
);
204 if (Status
==STATUS_PENDING
)
206 KeWaitForSingleObject(&Event
,Executive
,KernelMode
,FALSE
,NULL
);
207 Status
= IoStatusBlock
.Status
;
215 IoMountVolume(IN PDEVICE_OBJECT DeviceObject
,
216 IN BOOLEAN AllowRawMount
)
218 * FUNCTION: Mounts a logical volume
220 * DeviceObject = Device to mount
224 PFILE_SYSTEM_OBJECT current
;
226 DEVICE_TYPE MatchingDeviceType
;
227 PDEVICE_OBJECT DevObject
;
229 ASSERT_IRQL(PASSIVE_LEVEL
);
231 DPRINT("IoMountVolume(DeviceObject 0x%p AllowRawMount %x)\n",
232 DeviceObject
, AllowRawMount
);
234 switch (DeviceObject
->DeviceType
)
236 case FILE_DEVICE_DISK
:
237 case FILE_DEVICE_VIRTUAL_DISK
: /* ?? */
238 MatchingDeviceType
= FILE_DEVICE_DISK_FILE_SYSTEM
;
241 case FILE_DEVICE_CD_ROM
:
242 MatchingDeviceType
= FILE_DEVICE_CD_ROM_FILE_SYSTEM
;
245 case FILE_DEVICE_NETWORK
:
246 MatchingDeviceType
= FILE_DEVICE_NETWORK_FILE_SYSTEM
;
249 case FILE_DEVICE_TAPE
:
250 MatchingDeviceType
= FILE_DEVICE_TAPE_FILE_SYSTEM
;
254 CPRINT("No matching file system type found for device type: %x\n",
255 DeviceObject
->DeviceType
);
256 return(STATUS_UNRECOGNIZED_VOLUME
);
259 KeEnterCriticalRegion();
260 ExAcquireResourceSharedLite(&FileSystemListLock
,TRUE
);
263 LIST_FOR_EACH(current
,&FileSystemListHead
, FILE_SYSTEM_OBJECT
, Entry
)
265 if (current
->DeviceObject
->DeviceType
!= MatchingDeviceType
)
269 /* If we are not allowed to mount this volume as a raw filesystem volume
270 then don't try this */
271 if (!AllowRawMount
&& RawFsIsRawFileSystemDeviceObject(current
->DeviceObject
))
273 Status
= STATUS_UNRECOGNIZED_VOLUME
;
277 Status
= IopMountFileSystem(current
->DeviceObject
,
282 case STATUS_FS_DRIVER_REQUIRED
:
283 DevObject
= current
->DeviceObject
;
284 ExReleaseResourceLite(&FileSystemListLock
);
285 Status
= IopLoadFileSystem(DevObject
);
286 if (!NT_SUCCESS(Status
))
288 KeLeaveCriticalRegion();
291 ExAcquireResourceSharedLite(&FileSystemListLock
,TRUE
);
295 DeviceObject
->Vpb
->Flags
= DeviceObject
->Vpb
->Flags
|
297 ExReleaseResourceLite(&FileSystemListLock
);
298 KeLeaveCriticalRegion();
299 return(STATUS_SUCCESS
);
301 case STATUS_UNRECOGNIZED_VOLUME
:
307 ExReleaseResourceLite(&FileSystemListLock
);
308 KeLeaveCriticalRegion();
310 return(STATUS_UNRECOGNIZED_VOLUME
);
314 /**********************************************************************
319 * Verify the file system type and volume information or mount
324 * Device to verify or mount
335 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject
,
336 IN BOOLEAN AllowRawMount
)
338 IO_STATUS_BLOCK IoStatusBlock
;
339 PIO_STACK_LOCATION StackPtr
;
343 PDEVICE_OBJECT DevObject
;
345 DPRINT("IoVerifyVolume(DeviceObject 0x%p AllowRawMount %x)\n",
346 DeviceObject
, AllowRawMount
);
348 Status
= STATUS_SUCCESS
;
350 KeWaitForSingleObject(&DeviceObject
->DeviceLock
,
356 if (DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
)
358 /* Issue verify request to the FSD */
359 DevObject
= DeviceObject
->Vpb
->DeviceObject
;
361 KeInitializeEvent(&Event
,
365 Irp
= IoAllocateIrp(DevObject
->StackSize
, TRUE
);
368 return(STATUS_INSUFFICIENT_RESOURCES
);
371 Irp
->UserIosb
= &IoStatusBlock
;
372 Irp
->UserEvent
= &Event
;
373 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
375 StackPtr
= IoGetNextIrpStackLocation(Irp
);
376 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
377 StackPtr
->MinorFunction
= IRP_MN_VERIFY_VOLUME
;
379 StackPtr
->Control
= 0;
380 StackPtr
->DeviceObject
= DevObject
;
381 StackPtr
->FileObject
= NULL
;
382 StackPtr
->CompletionRoutine
= NULL
;
384 StackPtr
->Parameters
.VerifyVolume
.Vpb
= DeviceObject
->Vpb
;
385 StackPtr
->Parameters
.VerifyVolume
.DeviceObject
= DeviceObject
;
387 Status
= IoCallDriver(DevObject
,
389 if (Status
==STATUS_PENDING
)
391 KeWaitForSingleObject(&Event
,Executive
,KernelMode
,FALSE
,NULL
);
392 Status
= IoStatusBlock
.Status
;
395 if (NT_SUCCESS(Status
))
397 KeSetEvent(&DeviceObject
->DeviceLock
,
400 return(STATUS_SUCCESS
);
404 if (Status
== STATUS_WRONG_VOLUME
)
406 /* Clean existing VPB. This unmounts the filesystem. */
407 DPRINT("Wrong volume!\n");
409 DeviceObject
->Vpb
->DeviceObject
= NULL
;
410 DeviceObject
->Vpb
->Flags
&= ~VPB_MOUNTED
;
413 /* Start mount sequence */
414 Status
= IoMountVolume(DeviceObject
,
417 KeSetEvent(&DeviceObject
->DeviceLock
,
428 PDEVICE_OBJECT STDCALL
429 IoGetDeviceToVerify(IN PETHREAD Thread
)
431 * FUNCTION: Returns a pointer to the device, representing a removable-media
432 * device, that is the target of the given thread's I/O request
435 return(Thread
->DeviceToVerify
);
443 IoSetDeviceToVerify(IN PETHREAD Thread
,
444 IN PDEVICE_OBJECT DeviceObject
)
446 Thread
->DeviceToVerify
= DeviceObject
;
454 IoSetHardErrorOrVerifyDevice(IN PIRP Irp
,
455 IN PDEVICE_OBJECT DeviceObject
)
457 Irp
->Tail
.Overlay
.Thread
->DeviceToVerify
= DeviceObject
;
465 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject
)
467 PFILE_SYSTEM_OBJECT Fs
;
469 DPRINT("IoRegisterFileSystem(DeviceObject 0x%p)\n", DeviceObject
);
471 Fs
= ExAllocatePoolWithTag(NonPagedPool
,
472 sizeof(FILE_SYSTEM_OBJECT
),
476 Fs
->DeviceObject
= DeviceObject
;
477 KeEnterCriticalRegion();
478 ExAcquireResourceExclusiveLite(&FileSystemListLock
, TRUE
);
480 /* The RAW filesystem device objects must be last in the list so the
481 raw filesystem driver is the last filesystem driver asked to mount
482 a volume. It is always the first filesystem driver registered so
483 we use InsertHeadList() here as opposed to the other alternative
485 InsertHeadList(&FileSystemListHead
,
488 ExReleaseResourceLite(&FileSystemListLock
);
489 KeLeaveCriticalRegion();
491 IopNotifyFileSystemChange(DeviceObject
,
500 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject
)
502 PFILE_SYSTEM_OBJECT current
;
504 DPRINT("IoUnregisterFileSystem(DeviceObject 0x%p)\n", DeviceObject
);
506 KeEnterCriticalRegion();
507 ExAcquireResourceExclusiveLite(&FileSystemListLock
, TRUE
);
509 LIST_FOR_EACH(current
,&FileSystemListHead
, FILE_SYSTEM_OBJECT
,Entry
)
511 if (current
->DeviceObject
== DeviceObject
)
513 RemoveEntryList(¤t
->Entry
);
514 ExFreePoolWithTag(current
, TAG_FILE_SYSTEM
);
515 ExReleaseResourceLite(&FileSystemListLock
);
516 KeLeaveCriticalRegion();
517 IopNotifyFileSystemChange(DeviceObject
, FALSE
);
522 ExReleaseResourceLite(&FileSystemListLock
);
523 KeLeaveCriticalRegion();
527 /**********************************************************************
529 * IoGetBaseFileSystemDeviceObject@4
532 * Get the DEVICE_OBJECT associated to
541 * From Bo Branten's ntifs.h v13.
545 PDEVICE_OBJECT STDCALL
546 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject
)
548 PDEVICE_OBJECT DeviceObject
= NULL
;
552 * If the FILE_OBJECT's VPB is defined,
553 * get the device from it.
555 if (NULL
!= (Vpb
= FileObject
->Vpb
))
557 if (NULL
!= (DeviceObject
= Vpb
->DeviceObject
))
559 /* Vpb->DeviceObject DEFINED! */
564 * If that failed, try the VPB
565 * in the FILE_OBJECT's DeviceObject.
567 DeviceObject
= FileObject
->DeviceObject
;
568 if (NULL
== (Vpb
= DeviceObject
->Vpb
))
570 /* DeviceObject->Vpb UNDEFINED! */
574 * If that pointer to the VPB is again
575 * undefined, return directly the
576 * device object from the FILE_OBJECT.
579 (NULL
== Vpb
->DeviceObject
)
587 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject
,
588 BOOLEAN DriverActive
)
590 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry
;
592 KeAcquireGuardedMutex(&FsChangeNotifyListLock
);
593 LIST_FOR_EACH(ChangeEntry
, &FsChangeNotifyListHead
,FS_CHANGE_NOTIFY_ENTRY
, FsChangeNotifyList
)
595 (ChangeEntry
->FSDNotificationProc
)(DeviceObject
, DriverActive
);
597 KeReleaseGuardedMutex(&FsChangeNotifyListLock
);
605 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject
,
606 IN PDRIVER_FS_NOTIFICATION FSDNotificationProc
)
608 PFS_CHANGE_NOTIFY_ENTRY Entry
;
610 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
611 sizeof(FS_CHANGE_NOTIFY_ENTRY
),
612 TAG_FS_CHANGE_NOTIFY
);
614 return(STATUS_INSUFFICIENT_RESOURCES
);
616 Entry
->DriverObject
= DriverObject
;
617 Entry
->FSDNotificationProc
= FSDNotificationProc
;
619 KeAcquireGuardedMutex(&FsChangeNotifyListLock
);
620 InsertHeadList(&FsChangeNotifyListHead
,
621 &Entry
->FsChangeNotifyList
);
622 KeReleaseGuardedMutex(&FsChangeNotifyListLock
);
624 return(STATUS_SUCCESS
);
632 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject
,
633 IN PDRIVER_FS_NOTIFICATION FSDNotificationProc
)
635 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry
;
637 LIST_FOR_EACH(ChangeEntry
, &FsChangeNotifyListHead
, FS_CHANGE_NOTIFY_ENTRY
, FsChangeNotifyList
)
639 if (ChangeEntry
->DriverObject
== DriverObject
&&
640 ChangeEntry
->FSDNotificationProc
== FSDNotificationProc
)
642 KeAcquireGuardedMutex(&FsChangeNotifyListLock
);
643 RemoveEntryList(&ChangeEntry
->FsChangeNotifyList
);
644 KeReleaseGuardedMutex(&FsChangeNotifyListLock
);
646 ExFreePoolWithTag(ChangeEntry
, TAG_FS_CHANGE_NOTIFY
);