Changed to event object from file object.
[reactos.git] / reactos / ntoskrnl / io / fs.c
1 /* $Id: fs.c,v 1.25 2002/04/27 19:22:55 hbirr Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/fs.c
6 * PURPOSE: Filesystem functions
7 * PROGRAMMER: David Welch (welch@mcmail.com)
8 * UPDATE HISTORY:
9 * Created 22/05/98
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <internal/io.h>
16 #include <internal/ps.h>
17 #include <internal/pool.h>
18
19 #define NDEBUG
20 #include <internal/debug.h>
21
22
23 /* TYPES *******************************************************************/
24
25 typedef struct _FILE_SYSTEM_OBJECT
26 {
27 PDEVICE_OBJECT DeviceObject;
28 LIST_ENTRY Entry;
29 } FILE_SYSTEM_OBJECT, *PFILE_SYSTEM_OBJECT;
30
31 typedef struct _FS_CHANGE_NOTIFY_ENTRY
32 {
33 LIST_ENTRY FsChangeNotifyList;
34 PDRIVER_OBJECT DriverObject;
35 PFSDNOTIFICATIONPROC FSDNotificationProc;
36 } FS_CHANGE_NOTIFY_ENTRY, *PFS_CHANGE_NOTIFY_ENTRY;
37
38
39 /* GLOBALS ******************************************************************/
40
41 static KSPIN_LOCK FileSystemListLock;
42 static LIST_ENTRY FileSystemListHead;
43
44 static KSPIN_LOCK FsChangeNotifyListLock;
45 static LIST_ENTRY FsChangeNotifyListHead;
46
47 #define TAG_FILE_SYSTEM TAG('F', 'S', 'Y', 'S')
48 #define TAG_FS_CHANGE_NOTIFY TAG('F', 'S', 'C', 'N')
49
50
51 static VOID
52 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
53 BOOLEAN DriverActive);
54
55
56 /* FUNCTIONS *****************************************************************/
57
58 NTSTATUS STDCALL
59 NtFsControlFile (
60 IN HANDLE DeviceHandle,
61 IN HANDLE EventHandle OPTIONAL,
62 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
63 IN PVOID ApcContext OPTIONAL,
64 OUT PIO_STATUS_BLOCK IoStatusBlock,
65 IN ULONG IoControlCode,
66 IN PVOID InputBuffer,
67 IN ULONG InputBufferSize,
68 OUT PVOID OutputBuffer,
69 IN ULONG OutputBufferSize
70 )
71 {
72 NTSTATUS Status;
73 PFILE_OBJECT FileObject;
74 PDEVICE_OBJECT DeviceObject;
75 PIRP Irp;
76 PIO_STACK_LOCATION StackPtr;
77 PKEVENT ptrEvent;
78 IO_STATUS_BLOCK IoSB;
79
80 DPRINT("NtFsControlFile(DeviceHandle %x EventHandle %x ApcRoutine %x "
81 "ApcContext %x IoStatusBlock %x IoControlCode %x "
82 "InputBuffer %x InputBufferSize %x OutputBuffer %x "
83 "OutputBufferSize %x)\n",
84 DeviceHandle,EventHandle,ApcRoutine,ApcContext,IoStatusBlock,
85 IoControlCode,InputBuffer,InputBufferSize,OutputBuffer,
86 OutputBufferSize);
87
88 Status = ObReferenceObjectByHandle(DeviceHandle,
89 FILE_READ_DATA | FILE_WRITE_DATA,
90 NULL,
91 KernelMode,
92 (PVOID *) &FileObject,
93 NULL);
94
95 if (!NT_SUCCESS(Status))
96 {
97 return(Status);
98 }
99
100 if (EventHandle != NULL)
101 {
102 Status = ObReferenceObjectByHandle (EventHandle,
103 SYNCHRONIZE,
104 ExEventObjectType,
105 UserMode,
106 (PVOID*)&ptrEvent,
107 NULL);
108 if (!NT_SUCCESS(Status))
109 {
110 ObDereferenceObject(FileObject);
111 return Status;
112 }
113 }
114 else
115 {
116 KeResetEvent (&FileObject->Event);
117 ptrEvent = &FileObject->Event;
118 }
119
120
121 DeviceObject = FileObject->DeviceObject;
122
123 Irp = IoBuildDeviceIoControlRequest(IoControlCode,
124 DeviceObject,
125 InputBuffer,
126 InputBufferSize,
127 OutputBuffer,
128 OutputBufferSize,
129 FALSE,
130 ptrEvent,
131 &IoSB);
132
133 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
134 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
135
136 StackPtr = IoGetNextIrpStackLocation(Irp);
137 StackPtr->FileObject = FileObject;
138 StackPtr->DeviceObject = DeviceObject;
139 StackPtr->Parameters.FileSystemControl.InputBufferLength = InputBufferSize;
140 StackPtr->Parameters.FileSystemControl.OutputBufferLength =
141 OutputBufferSize;
142 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
143
144 Status = IoCallDriver(DeviceObject,Irp);
145 if (Status == STATUS_PENDING && !(FileObject->Flags & FO_SYNCHRONOUS_IO))
146 {
147 KeWaitForSingleObject(ptrEvent,Executive,KernelMode,FALSE,NULL);
148 Status = IoSB.Status;
149 }
150 if (IoStatusBlock)
151 {
152 *IoStatusBlock = IoSB;
153 }
154 return(Status);
155 }
156
157
158 VOID
159 IoInitFileSystemImplementation(VOID)
160 {
161 InitializeListHead(&FileSystemListHead);
162 KeInitializeSpinLock(&FileSystemListLock);
163
164 InitializeListHead(&FsChangeNotifyListHead);
165 KeInitializeSpinLock(&FsChangeNotifyListLock);
166 }
167
168
169 VOID
170 IoShutdownRegisteredFileSystems(VOID)
171 {
172 KIRQL oldlvl;
173 PLIST_ENTRY current_entry;
174 FILE_SYSTEM_OBJECT* current;
175 PIRP Irp;
176 KEVENT Event;
177 IO_STATUS_BLOCK IoStatusBlock;
178 NTSTATUS Status;
179
180 DPRINT("IoShutdownRegisteredFileSystems()\n");
181
182 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
183 KeInitializeEvent(&Event,NotificationEvent,FALSE);
184
185 current_entry = FileSystemListHead.Flink;
186 while (current_entry!=(&FileSystemListHead))
187 {
188 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
189
190 /* send IRP_MJ_SHUTDOWN */
191 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
192 current->DeviceObject,
193 NULL,
194 0,
195 0,
196 &Event,
197 &IoStatusBlock);
198
199 Status = IoCallDriver(current->DeviceObject,Irp);
200 if (Status==STATUS_PENDING)
201 {
202 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
203 }
204
205 current_entry = current_entry->Flink;
206 }
207
208 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
209 }
210
211
212 NTSTATUS
213 IoAskFileSystemToMountDevice(PDEVICE_OBJECT DeviceObject,
214 PDEVICE_OBJECT DeviceToMount)
215 {
216 PIRP Irp;
217 IO_STATUS_BLOCK IoStatusBlock;
218 NTSTATUS Status;
219 PKEVENT Event; // KEVENT must be allocated from non paged pool, not stack
220
221 DPRINT("IoAskFileSystemToMountDevice(DeviceObject %x, DeviceToMount %x)\n",
222 DeviceObject,DeviceToMount);
223
224 assert_irql(PASSIVE_LEVEL);
225 Event = ExAllocatePool( NonPagedPool, sizeof( KEVENT ) );
226 if( Event == 0 )
227 return STATUS_INSUFFICIENT_RESOURCES;
228 KeInitializeEvent(Event,NotificationEvent,FALSE);
229 Irp = IoBuildFilesystemControlRequest(IRP_MN_MOUNT_VOLUME,
230 DeviceObject,
231 Event,
232 &IoStatusBlock,
233 DeviceToMount);
234 Status = IoCallDriver(DeviceObject,Irp);
235 if (Status==STATUS_PENDING)
236 {
237 KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
238 Status = IoStatusBlock.Status;
239 }
240 ExFreePool( Event );
241 return(Status);
242 }
243
244
245 NTSTATUS
246 IoAskFileSystemToLoad(IN PDEVICE_OBJECT DeviceObject)
247 {
248 UNIMPLEMENTED;
249 }
250
251
252 NTSTATUS
253 IoTryToMountStorageDevice(IN PDEVICE_OBJECT DeviceObject,
254 IN BOOLEAN AllowRawMount)
255 /*
256 * FUNCTION: Trys to mount a storage device
257 * ARGUMENTS:
258 * DeviceObject = Device to try and mount
259 * RETURNS: Status
260 */
261 {
262 KIRQL oldlvl;
263 PLIST_ENTRY current_entry;
264 FILE_SYSTEM_OBJECT* current;
265 NTSTATUS Status;
266 DEVICE_TYPE MatchingDeviceType;
267
268 assert_irql(PASSIVE_LEVEL);
269
270 DPRINT("IoTryToMountStorageDevice(DeviceObject %x)\n",DeviceObject);
271
272 switch (DeviceObject->DeviceType)
273 {
274 case FILE_DEVICE_DISK:
275 case FILE_DEVICE_VIRTUAL_DISK: /* ?? */
276 MatchingDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
277 break;
278
279 case FILE_DEVICE_CD_ROM:
280 MatchingDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
281 break;
282
283 case FILE_DEVICE_NETWORK:
284 MatchingDeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
285 break;
286
287 case FILE_DEVICE_TAPE:
288 MatchingDeviceType = FILE_DEVICE_TAPE_FILE_SYSTEM;
289 break;
290
291 default:
292 CPRINT("No matching file system type found for device type: %x\n",
293 DeviceObject->DeviceType);
294 return(STATUS_UNRECOGNIZED_VOLUME);
295 }
296
297 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
298 current_entry = FileSystemListHead.Flink;
299 while (current_entry!=(&FileSystemListHead))
300 {
301 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
302 if (current->DeviceObject->DeviceType != MatchingDeviceType)
303 {
304 current_entry = current_entry->Flink;
305 continue;
306 }
307 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
308 Status = IoAskFileSystemToMountDevice(current->DeviceObject,
309 DeviceObject);
310 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
311 switch (Status)
312 {
313 case STATUS_FS_DRIVER_REQUIRED:
314 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
315 (void)IoAskFileSystemToLoad(DeviceObject);
316 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
317 current_entry = FileSystemListHead.Flink;
318 break;
319
320 case STATUS_SUCCESS:
321 DeviceObject->Vpb->Flags = DeviceObject->Vpb->Flags |
322 VPB_MOUNTED;
323 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
324 return(STATUS_SUCCESS);
325
326 case STATUS_UNRECOGNIZED_VOLUME:
327 default:
328 current_entry = current_entry->Flink;
329 }
330 }
331 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
332
333 return(STATUS_UNRECOGNIZED_VOLUME);
334 }
335
336
337 /**********************************************************************
338 * NAME EXPORTED
339 * IoVerifyVolume
340 *
341 * DESCRIPTION
342 * Veriyfy the file system type and volume information or mount
343 * a file system.
344 *
345 * ARGUMENTS
346 * DeviceObject
347 * Device to verify or mount
348 *
349 * AllowRawMount
350 * ...
351 *
352 * RETURN VALUE
353 * Status
354 */
355 NTSTATUS STDCALL
356 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject,
357 IN BOOLEAN AllowRawMount)
358 {
359 IO_STATUS_BLOCK IoStatusBlock;
360 PKEVENT Event;
361 PIRP Irp;
362 NTSTATUS Status;
363
364 DPRINT1("IoVerifyVolume(DeviceObject %x AllowRawMount %x)\n",
365 DeviceObject,
366 AllowRawMount);
367
368 Status = STATUS_SUCCESS;
369
370 KeWaitForSingleObject(&DeviceObject->DeviceLock,
371 Executive,
372 KernelMode,
373 FALSE,
374 NULL);
375
376 if (DeviceObject->Vpb->Flags & VPB_MOUNTED)
377 {
378 /* Issue verify request to the FSD */
379 Event = ExAllocatePool(NonPagedPool,
380 sizeof(KEVENT));
381 if (Event == NULL)
382 return(STATUS_INSUFFICIENT_RESOURCES);
383
384 KeInitializeEvent(Event,
385 NotificationEvent,
386 FALSE);
387
388 Irp = IoBuildFilesystemControlRequest(IRP_MN_VERIFY_VOLUME,
389 DeviceObject,
390 Event,
391 &IoStatusBlock,
392 NULL); //DeviceToMount);
393
394 Status = IoCallDriver(DeviceObject,
395 Irp);
396 if (Status==STATUS_PENDING)
397 {
398 KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
399 Status = IoStatusBlock.Status;
400 }
401 ExFreePool(Event);
402
403 if (NT_SUCCESS(Status))
404 {
405 KeSetEvent(&DeviceObject->DeviceLock,
406 IO_NO_INCREMENT,
407 FALSE);
408 return(STATUS_SUCCESS);
409 }
410 }
411
412 if (Status == STATUS_WRONG_VOLUME)
413 {
414 /* FIXME: Replace existing VPB by a new one */
415 DPRINT1("Wrong volume!\n");
416
417
418 }
419
420 /* Start mount sequence */
421 Status = IoTryToMountStorageDevice(DeviceObject,
422 AllowRawMount);
423
424 KeSetEvent(&DeviceObject->DeviceLock,
425 IO_NO_INCREMENT,
426 FALSE);
427
428 return(Status);
429 }
430
431
432 PDEVICE_OBJECT STDCALL
433 IoGetDeviceToVerify(IN PETHREAD Thread)
434 /*
435 * FUNCTION: Returns a pointer to the device, representing a removable-media
436 * device, that is the target of the given thread's I/O request
437 */
438 {
439 return(Thread->DeviceToVerify);
440 }
441
442
443 VOID STDCALL
444 IoSetDeviceToVerify(IN PETHREAD Thread,
445 IN PDEVICE_OBJECT DeviceObject)
446 {
447 Thread->DeviceToVerify = DeviceObject;
448 }
449
450
451 VOID STDCALL
452 IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
453 IN PDEVICE_OBJECT DeviceObject)
454 {
455 Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
456 }
457
458
459 VOID STDCALL
460 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
461 {
462 PFILE_SYSTEM_OBJECT Fs;
463
464 DPRINT("IoRegisterFileSystem(DeviceObject %x)\n",DeviceObject);
465
466 Fs = ExAllocatePoolWithTag(NonPagedPool,
467 sizeof(FILE_SYSTEM_OBJECT),
468 TAG_FILE_SYSTEM);
469 assert(Fs!=NULL);
470
471 Fs->DeviceObject = DeviceObject;
472 ExInterlockedInsertTailList(&FileSystemListHead,
473 &Fs->Entry,
474 &FileSystemListLock);
475 IopNotifyFileSystemChange(DeviceObject,
476 TRUE);
477 }
478
479
480 VOID STDCALL
481 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
482 {
483 KIRQL oldlvl;
484 PLIST_ENTRY current_entry;
485 PFILE_SYSTEM_OBJECT current;
486
487 DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject);
488
489 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
490 current_entry = FileSystemListHead.Flink;
491 while (current_entry!=(&FileSystemListHead))
492 {
493 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
494 if (current->DeviceObject == DeviceObject)
495 {
496 RemoveEntryList(current_entry);
497 ExFreePool(current);
498 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
499 IopNotifyFileSystemChange(DeviceObject, FALSE);
500 return;
501 }
502 current_entry = current_entry->Flink;
503 }
504 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
505 }
506
507
508 /**********************************************************************
509 * NAME EXPORTED
510 * IoGetBaseFileSystemDeviceObject@4
511 *
512 * DESCRIPTION
513 * Get the DEVICE_OBJECT associated to
514 * a FILE_OBJECT.
515 *
516 * ARGUMENTS
517 * FileObject
518 *
519 * RETURN VALUE
520 *
521 * NOTE
522 * From Bo Branten's ntifs.h v13.
523 */
524 PDEVICE_OBJECT STDCALL
525 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
526 {
527 PDEVICE_OBJECT DeviceObject = NULL;
528 PVPB Vpb = NULL;
529
530 /*
531 * If the FILE_OBJECT's VPB is defined,
532 * get the device from it.
533 */
534 if (NULL != (Vpb = FileObject->Vpb))
535 {
536 if (NULL != (DeviceObject = Vpb->DeviceObject))
537 {
538 /* Vpb->DeviceObject DEFINED! */
539 return DeviceObject;
540 }
541 }
542 /*
543 * If that failed, try the VPB
544 * in the FILE_OBJECT's DeviceObject.
545 */
546 DeviceObject = FileObject->DeviceObject;
547 if (NULL == (Vpb = DeviceObject->Vpb))
548 {
549 /* DeviceObject->Vpb UNDEFINED! */
550 return DeviceObject;
551 }
552 /*
553 * If that pointer to the VPB is again
554 * undefined, return directly the
555 * device object from the FILE_OBJECT.
556 */
557 return (
558 (NULL == Vpb->DeviceObject)
559 ? DeviceObject
560 : Vpb->DeviceObject
561 );
562 }
563
564
565 static VOID
566 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
567 BOOLEAN DriverActive)
568 {
569 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
570 PLIST_ENTRY Entry;
571 KIRQL oldlvl;
572
573 KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
574 Entry = FsChangeNotifyListHead.Flink;
575 while (Entry != &FsChangeNotifyListHead)
576 {
577 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
578
579 (ChangeEntry->FSDNotificationProc)(DeviceObject, DriverActive);
580
581 Entry = Entry->Flink;
582 }
583 KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
584 }
585
586
587 NTSTATUS STDCALL
588 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
589 IN PFSDNOTIFICATIONPROC FSDNotificationProc)
590 {
591 PFS_CHANGE_NOTIFY_ENTRY Entry;
592
593 Entry = ExAllocatePoolWithTag(NonPagedPool,
594 sizeof(FS_CHANGE_NOTIFY_ENTRY),
595 TAG_FS_CHANGE_NOTIFY);
596 if (Entry == NULL)
597 return(STATUS_INSUFFICIENT_RESOURCES);
598
599 Entry->DriverObject = DriverObject;
600 Entry->FSDNotificationProc = FSDNotificationProc;
601
602 ExInterlockedInsertHeadList(&FsChangeNotifyListHead,
603 &Entry->FsChangeNotifyList,
604 &FsChangeNotifyListLock);
605
606 return(STATUS_SUCCESS);
607 }
608
609
610 VOID STDCALL
611 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
612 IN PFSDNOTIFICATIONPROC FSDNotificationProc)
613 {
614 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
615 PLIST_ENTRY Entry;
616 KIRQL oldlvl;
617
618 Entry = FsChangeNotifyListHead.Flink;
619 while (Entry != &FsChangeNotifyListHead)
620 {
621 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
622 if (ChangeEntry->DriverObject == DriverObject &&
623 ChangeEntry->FSDNotificationProc == FSDNotificationProc)
624 {
625 KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
626 RemoveEntryList(Entry);
627 KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
628
629 ExFreePool(Entry);
630 return;
631 }
632
633 Entry = Entry->Flink;
634 }
635 }
636
637 /* EOF */