update for HEAD-2003091401
[reactos.git] / ntoskrnl / io / fs.c
1 /* $Id$
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 /* GLOBALS ******************************************************************/
39
40 static ERESOURCE FileSystemListLock;
41 static LIST_ENTRY FileSystemListHead;
42
43 static KSPIN_LOCK FsChangeNotifyListLock;
44 static LIST_ENTRY FsChangeNotifyListHead;
45
46 #define TAG_FILE_SYSTEM       TAG('F', 'S', 'Y', 'S')
47 #define TAG_FS_CHANGE_NOTIFY  TAG('F', 'S', 'C', 'N')
48
49
50 static VOID
51 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
52                           BOOLEAN DriverActive);
53
54
55 /* FUNCTIONS *****************************************************************/
56
57 /*
58  * @implemented
59  */
60 NTSTATUS STDCALL
61 NtFsControlFile (
62         IN      HANDLE                  DeviceHandle,
63         IN      HANDLE                  EventHandle     OPTIONAL, 
64         IN      PIO_APC_ROUTINE         ApcRoutine      OPTIONAL, 
65         IN      PVOID                   ApcContext      OPTIONAL, 
66         OUT     PIO_STATUS_BLOCK        IoStatusBlock, 
67         IN      ULONG                   IoControlCode,
68         IN      PVOID                   InputBuffer, 
69         IN      ULONG                   InputBufferSize,
70         OUT     PVOID                   OutputBuffer,
71         IN      ULONG                   OutputBufferSize
72         )
73 {
74    NTSTATUS Status;
75    PFILE_OBJECT FileObject;
76    PDEVICE_OBJECT DeviceObject;
77    PIRP Irp;
78    PEXTENDED_IO_STACK_LOCATION StackPtr;
79    PKEVENT ptrEvent;
80    IO_STATUS_BLOCK IoSB;
81
82    DPRINT("NtFsControlFile(DeviceHandle %x EventHandle %x ApcRoutine %x "
83           "ApcContext %x IoStatusBlock %x IoControlCode %x "
84           "InputBuffer %x InputBufferSize %x OutputBuffer %x "
85           "OutputBufferSize %x)\n",
86           DeviceHandle,EventHandle,ApcRoutine,ApcContext,IoStatusBlock,
87           IoControlCode,InputBuffer,InputBufferSize,OutputBuffer,
88           OutputBufferSize);
89
90    Status = ObReferenceObjectByHandle(DeviceHandle,
91                                       FILE_READ_DATA | FILE_WRITE_DATA,
92                                       NULL,
93                                       KernelMode,
94                                       (PVOID *) &FileObject,
95                                       NULL);
96    
97    if (!NT_SUCCESS(Status))
98      {
99         return(Status);
100      }
101
102    if (EventHandle != NULL)
103      {
104         Status = ObReferenceObjectByHandle (EventHandle,
105                                             SYNCHRONIZE,
106                                             ExEventObjectType,
107                                             UserMode,
108                                             (PVOID*)&ptrEvent,
109                                             NULL);
110         if (!NT_SUCCESS(Status))
111           {
112             ObDereferenceObject(FileObject);
113             return Status;
114           }
115       }
116     else
117       {
118          KeResetEvent (&FileObject->Event);
119          ptrEvent = &FileObject->Event;
120       }
121
122    
123    DeviceObject = FileObject->DeviceObject;
124
125    Irp = IoBuildDeviceIoControlRequest(IoControlCode,
126                                        DeviceObject,
127                                        InputBuffer,
128                                        InputBufferSize,
129                                        OutputBuffer,
130                                        OutputBufferSize,
131                                        FALSE,
132                                        ptrEvent,
133                                        &IoSB);
134    
135    //trigger FileObject/Event dereferencing
136    Irp->Tail.Overlay.OriginalFileObject = FileObject;
137    
138    Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
139    Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
140
141    StackPtr = (PEXTENDED_IO_STACK_LOCATION) IoGetNextIrpStackLocation(Irp);
142    StackPtr->FileObject = FileObject;
143    StackPtr->DeviceObject = DeviceObject;
144    StackPtr->Parameters.FileSystemControl.InputBufferLength = InputBufferSize;
145    StackPtr->Parameters.FileSystemControl.OutputBufferLength = 
146      OutputBufferSize;
147    StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
148    
149    Status = IoCallDriver(DeviceObject,Irp);
150    if (Status == STATUS_PENDING && !(FileObject->Flags & FO_SYNCHRONOUS_IO))
151      {
152         KeWaitForSingleObject(ptrEvent,Executive,KernelMode,FALSE,NULL);
153         Status = IoSB.Status;
154      }
155    if (IoStatusBlock)
156      {
157         *IoStatusBlock = IoSB;
158      }
159    return(Status);
160 }
161
162
163 VOID
164 IoInitFileSystemImplementation(VOID)
165 {
166   InitializeListHead(&FileSystemListHead);
167   ExInitializeResourceLite(&FileSystemListLock);
168
169   InitializeListHead(&FsChangeNotifyListHead);
170   KeInitializeSpinLock(&FsChangeNotifyListLock);
171 }
172
173
174 VOID
175 IoShutdownRegisteredFileSystems(VOID)
176 {
177   PLIST_ENTRY current_entry;
178   FILE_SYSTEM_OBJECT* current;
179   PIRP Irp;
180   KEVENT Event;
181   IO_STATUS_BLOCK IoStatusBlock;
182   NTSTATUS Status;
183
184   DPRINT("IoShutdownRegisteredFileSystems()\n");
185
186   ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
187   KeInitializeEvent(&Event,
188                     NotificationEvent,
189                     FALSE);
190
191   current_entry = FileSystemListHead.Flink;
192   while (current_entry!=(&FileSystemListHead))
193     {
194       current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
195
196       /* send IRP_MJ_SHUTDOWN */
197       Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
198                                          current->DeviceObject,
199                                          NULL,
200                                          0,
201                                          0,
202                                          &Event,
203                                          &IoStatusBlock);
204
205       Status = IoCallDriver(current->DeviceObject,Irp);
206       if (Status == STATUS_PENDING)
207         {
208           KeWaitForSingleObject(&Event,
209                                 Executive,
210                                 KernelMode,
211                                 FALSE,
212                                 NULL);
213         }
214
215       current_entry = current_entry->Flink;
216     }
217
218   ExReleaseResourceLite(&FileSystemListLock);
219 }
220
221
222 static NTSTATUS
223 IopMountFileSystem(PDEVICE_OBJECT DeviceObject,
224                    PDEVICE_OBJECT DeviceToMount)
225 {
226   IO_STATUS_BLOCK IoStatusBlock;
227   PIO_STACK_LOCATION StackPtr;
228   KEVENT Event;
229   PIRP Irp;
230   NTSTATUS Status;
231
232   DPRINT("IopMountFileSystem(DeviceObject %x, DeviceToMount %x)\n",
233          DeviceObject,DeviceToMount);
234
235   assert_irql(PASSIVE_LEVEL);
236
237   KeInitializeEvent(&Event, NotificationEvent, FALSE);
238   Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
239   if (Irp==NULL)
240     {
241       return(STATUS_INSUFFICIENT_RESOURCES);
242     }
243
244   Irp->UserIosb = &IoStatusBlock;
245   DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
246   Irp->UserEvent = &Event;
247   Irp->Tail.Overlay.Thread = PsGetCurrentThread();
248
249   StackPtr = IoGetNextIrpStackLocation(Irp);
250   StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
251   StackPtr->MinorFunction = IRP_MN_MOUNT_VOLUME;
252   StackPtr->Flags = 0;
253   StackPtr->Control = 0;
254   StackPtr->DeviceObject = DeviceObject;
255   StackPtr->FileObject = NULL;
256   StackPtr->CompletionRoutine = NULL;
257
258   StackPtr->Parameters.MountVolume.Vpb = DeviceToMount->Vpb;
259   StackPtr->Parameters.MountVolume.DeviceObject = DeviceToMount;
260
261   Status = IoCallDriver(DeviceObject,Irp);
262   if (Status==STATUS_PENDING)
263     {
264       KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
265       Status = IoStatusBlock.Status;
266     }
267
268   return(Status);
269 }
270
271
272 static NTSTATUS
273 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject)
274 {
275   IO_STATUS_BLOCK IoStatusBlock;
276   PIO_STACK_LOCATION StackPtr;
277   KEVENT Event;
278   PIRP Irp;
279   NTSTATUS Status;
280
281   DPRINT("IopLoadFileSystem(DeviceObject %x)\n", DeviceObject);
282
283   assert_irql(PASSIVE_LEVEL);
284
285   KeInitializeEvent(&Event, NotificationEvent, FALSE);
286   Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
287   if (Irp==NULL)
288     {
289       return(STATUS_INSUFFICIENT_RESOURCES);
290     }
291
292   Irp->UserIosb = &IoStatusBlock;
293   DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
294   Irp->UserEvent = &Event;
295   Irp->Tail.Overlay.Thread = PsGetCurrentThread();
296
297   StackPtr = IoGetNextIrpStackLocation(Irp);
298   StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
299   StackPtr->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM;
300   StackPtr->Flags = 0;
301   StackPtr->Control = 0;
302   StackPtr->DeviceObject = DeviceObject;
303   StackPtr->FileObject = NULL;
304   StackPtr->CompletionRoutine = NULL;
305
306   Status = IoCallDriver(DeviceObject,Irp);
307   if (Status==STATUS_PENDING)
308     {
309       KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
310       Status = IoStatusBlock.Status;
311     }
312
313   return(Status);
314 }
315
316
317 NTSTATUS
318 IoMountVolume(IN PDEVICE_OBJECT DeviceObject,
319               IN BOOLEAN AllowRawMount)
320 /*
321  * FUNCTION: Mounts a logical volume
322  * ARGUMENTS:
323  *         DeviceObject = Device to mount
324  * RETURNS: Status
325  */
326 {
327   PLIST_ENTRY current_entry;
328   FILE_SYSTEM_OBJECT* current;
329   NTSTATUS Status;
330   DEVICE_TYPE MatchingDeviceType;
331   PDEVICE_OBJECT DevObject;
332
333   assert_irql(PASSIVE_LEVEL);
334
335   DPRINT("IoMountVolume(DeviceObject %x  AllowRawMount %x)\n",
336          DeviceObject, AllowRawMount);
337
338   switch (DeviceObject->DeviceType)
339     {
340       case FILE_DEVICE_DISK:
341       case FILE_DEVICE_VIRTUAL_DISK: /* ?? */
342         MatchingDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
343         break;
344
345       case FILE_DEVICE_CD_ROM:
346         MatchingDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
347         break;
348
349       case FILE_DEVICE_NETWORK:
350         MatchingDeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
351         break;
352
353       case FILE_DEVICE_TAPE:
354         MatchingDeviceType = FILE_DEVICE_TAPE_FILE_SYSTEM;
355         break;
356
357       default:
358         CPRINT("No matching file system type found for device type: %x\n",
359                DeviceObject->DeviceType);
360         return(STATUS_UNRECOGNIZED_VOLUME);
361     }
362
363   ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
364   current_entry = FileSystemListHead.Flink;
365   while (current_entry!=(&FileSystemListHead))
366     {
367       current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
368       if (current->DeviceObject->DeviceType != MatchingDeviceType)
369         {
370           current_entry = current_entry->Flink;
371           continue;
372         }
373       /* If we are not allowed to mount this volume as a raw filesystem volume
374          then don't try this */
375       if (!AllowRawMount && RawFsIsRawFileSystemDeviceObject(current->DeviceObject))
376         {
377           Status = STATUS_UNRECOGNIZED_VOLUME;
378         }
379       else
380         {
381           Status = IopMountFileSystem(current->DeviceObject,
382                                   DeviceObject);
383         }
384       switch (Status)
385         {
386           case STATUS_FS_DRIVER_REQUIRED:
387             DevObject = current->DeviceObject;
388             ExReleaseResourceLite(&FileSystemListLock);
389             Status = IopLoadFileSystem(DevObject);
390             if (!NT_SUCCESS(Status))
391               {
392                 return(Status);
393               }
394             ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
395             current_entry = FileSystemListHead.Flink;
396             continue;
397
398           case STATUS_SUCCESS:
399             DeviceObject->Vpb->Flags = DeviceObject->Vpb->Flags |
400                                        VPB_MOUNTED;
401             ExReleaseResourceLite(&FileSystemListLock);
402             return(STATUS_SUCCESS);
403
404           case STATUS_UNRECOGNIZED_VOLUME:
405           default:
406             current_entry = current_entry->Flink;
407         }
408     }
409   ExReleaseResourceLite(&FileSystemListLock);
410
411   return(STATUS_UNRECOGNIZED_VOLUME);
412 }
413
414
415 /**********************************************************************
416  * NAME                                                 EXPORTED
417  *      IoVerifyVolume
418  *
419  * DESCRIPTION
420  *      Verify the file system type and volume information or mount
421  *      a file system.
422  *
423  * ARGUMENTS
424  *      DeviceObject
425  *              Device to verify or mount
426  *
427  *      AllowRawMount
428  *              ...
429  *
430  * RETURN VALUE
431  *      Status
432  *
433  * @implemented
434  */
435 NTSTATUS STDCALL
436 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject,
437                IN BOOLEAN AllowRawMount)
438 {
439   IO_STATUS_BLOCK IoStatusBlock;
440   PIO_STACK_LOCATION StackPtr;
441   KEVENT Event;
442   PIRP Irp;
443   NTSTATUS Status;
444   PDEVICE_OBJECT DevObject;
445
446   DPRINT("IoVerifyVolume(DeviceObject %x  AllowRawMount %x)\n",
447          DeviceObject, AllowRawMount);
448
449   Status = STATUS_SUCCESS;
450
451   KeWaitForSingleObject(&DeviceObject->DeviceLock,
452                         Executive,
453                         KernelMode,
454                         FALSE,
455                         NULL);
456
457   DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
458
459   if (DeviceObject->Vpb->Flags & VPB_MOUNTED)
460     {
461       /* Issue verify request to the FSD */
462       DevObject = DeviceObject->Vpb->DeviceObject;
463
464       KeInitializeEvent(&Event,
465                         NotificationEvent,
466                         FALSE);
467
468       Irp = IoAllocateIrp(DevObject->StackSize, TRUE);
469       if (Irp==NULL)
470         {
471           return(STATUS_INSUFFICIENT_RESOURCES);
472         }
473
474       Irp->UserIosb = &IoStatusBlock;
475       Irp->UserEvent = &Event;
476       Irp->Tail.Overlay.Thread = PsGetCurrentThread();
477
478       StackPtr = IoGetNextIrpStackLocation(Irp);
479       StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
480       StackPtr->MinorFunction = IRP_MN_VERIFY_VOLUME;
481       StackPtr->Flags = 0;
482       StackPtr->Control = 0;
483       StackPtr->DeviceObject = DevObject;
484       StackPtr->FileObject = NULL;
485       StackPtr->CompletionRoutine = NULL;
486
487       StackPtr->Parameters.VerifyVolume.Vpb = DeviceObject->Vpb;
488       StackPtr->Parameters.VerifyVolume.DeviceObject = DeviceObject;
489
490       Status = IoCallDriver(DevObject,
491                             Irp);
492       if (Status==STATUS_PENDING)
493         {
494           KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
495           Status = IoStatusBlock.Status;
496         }
497
498       if (NT_SUCCESS(Status))
499         {
500           KeSetEvent(&DeviceObject->DeviceLock,
501                      IO_NO_INCREMENT,
502                      FALSE);
503           return(STATUS_SUCCESS);
504         }
505     }
506
507   if (Status == STATUS_WRONG_VOLUME)
508     {
509       /* Clean existing VPB. This unmounts the filesystem (in an ugly way). */
510       DPRINT("Wrong volume!\n");
511
512       DeviceObject->Vpb->DeviceObject = NULL;
513       DeviceObject->Vpb->Flags &= ~VPB_MOUNTED;
514     }
515
516   /* Start mount sequence */
517   Status = IoMountVolume(DeviceObject,
518                          AllowRawMount);
519
520   KeSetEvent(&DeviceObject->DeviceLock,
521              IO_NO_INCREMENT,
522              FALSE);
523
524   return(Status);
525 }
526
527
528 /*
529  * @implemented
530  */
531 PDEVICE_OBJECT STDCALL
532 IoGetDeviceToVerify(IN PETHREAD Thread)
533 /*
534  * FUNCTION: Returns a pointer to the device, representing a removable-media
535  * device, that is the target of the given thread's I/O request
536  */
537 {
538   return(Thread->DeviceToVerify);
539 }
540
541
542 /*
543  * @implemented
544  */
545 VOID STDCALL
546 IoSetDeviceToVerify(IN PETHREAD Thread,
547                     IN PDEVICE_OBJECT DeviceObject)
548 {
549   Thread->DeviceToVerify = DeviceObject;
550 }
551
552
553 /*
554  * @implemented
555  */
556 VOID STDCALL
557 IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
558                              IN PDEVICE_OBJECT DeviceObject)
559 {
560   Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
561 }
562
563
564 /*
565  * @implemented
566  */
567 VOID STDCALL
568 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
569 {
570   PFILE_SYSTEM_OBJECT Fs;
571
572   DPRINT("IoRegisterFileSystem(DeviceObject %x)\n",DeviceObject);
573
574   Fs = ExAllocatePoolWithTag(NonPagedPool,
575                              sizeof(FILE_SYSTEM_OBJECT),
576                              TAG_FILE_SYSTEM);
577   assert(Fs!=NULL);
578
579   Fs->DeviceObject = DeviceObject;
580   ExAcquireResourceExclusiveLite(&FileSystemListLock, TRUE);
581
582   /* The RAW filesystem device objects must be last in the list so the
583      raw filesystem driver is the last filesystem driver asked to mount
584      a volume. It is always the first filesystem driver registered so
585      we use InsertHeadList() here as opposed to the other alternative
586      InsertTailList(). */
587   InsertHeadList(&FileSystemListHead,
588                  &Fs->Entry);
589
590   ExReleaseResourceLite(&FileSystemListLock);
591
592   IopNotifyFileSystemChange(DeviceObject,
593                             TRUE);
594 }
595
596
597 /*
598  * @implemented
599  */
600 VOID STDCALL
601 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
602 {
603   PLIST_ENTRY current_entry;
604   PFILE_SYSTEM_OBJECT current;
605
606   DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject);
607
608   ExAcquireResourceExclusiveLite(&FileSystemListLock, TRUE);
609   current_entry = FileSystemListHead.Flink;
610   while (current_entry!=(&FileSystemListHead))
611     {
612       current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
613       if (current->DeviceObject == DeviceObject)
614         {
615           RemoveEntryList(current_entry);
616           ExFreePool(current);
617           ExReleaseResourceLite(&FileSystemListLock);
618           IopNotifyFileSystemChange(DeviceObject, FALSE);
619           return;
620         }
621       current_entry = current_entry->Flink;
622     }
623   ExReleaseResourceLite(&FileSystemListLock);
624 }
625
626
627 /**********************************************************************
628  * NAME                                                 EXPORTED
629  *      IoGetBaseFileSystemDeviceObject@4
630  *
631  * DESCRIPTION
632  *      Get the DEVICE_OBJECT associated to
633  *      a FILE_OBJECT.
634  *
635  * ARGUMENTS
636  *      FileObject
637  *
638  * RETURN VALUE
639  *
640  * NOTE
641  *      From Bo Branten's ntifs.h v13.
642  *
643  * @implemented
644  */
645 PDEVICE_OBJECT STDCALL
646 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
647 {
648         PDEVICE_OBJECT  DeviceObject = NULL;
649         PVPB            Vpb = NULL;
650
651         /*
652          * If the FILE_OBJECT's VPB is defined,
653          * get the device from it.
654          */
655         if (NULL != (Vpb = FileObject->Vpb)) 
656         {
657                 if (NULL != (DeviceObject = Vpb->DeviceObject))
658                 {
659                         /* Vpb->DeviceObject DEFINED! */
660                         return DeviceObject;
661                 }
662         }
663         /*
664          * If that failed, try the VPB
665          * in the FILE_OBJECT's DeviceObject.
666          */
667         DeviceObject = FileObject->DeviceObject;
668         if (NULL == (Vpb = DeviceObject->Vpb)) 
669         {
670                 /* DeviceObject->Vpb UNDEFINED! */
671                 return DeviceObject;
672         }
673         /*
674          * If that pointer to the VPB is again
675          * undefined, return directly the
676          * device object from the FILE_OBJECT.
677          */
678         return (
679                 (NULL == Vpb->DeviceObject)
680                         ? DeviceObject
681                         : Vpb->DeviceObject
682                 );
683 }
684
685
686 static VOID
687 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
688                           BOOLEAN DriverActive)
689 {
690   PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
691   PLIST_ENTRY Entry;
692   KIRQL oldlvl;
693
694   KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
695   Entry = FsChangeNotifyListHead.Flink;
696   while (Entry != &FsChangeNotifyListHead)
697     {
698       ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
699
700       (ChangeEntry->FSDNotificationProc)(DeviceObject, DriverActive);
701
702       Entry = Entry->Flink;
703     }
704   KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
705 }
706
707
708 /*
709  * @implemented
710  */
711 NTSTATUS STDCALL
712 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
713                                IN PFSDNOTIFICATIONPROC FSDNotificationProc)
714 {
715   PFS_CHANGE_NOTIFY_ENTRY Entry;
716
717   Entry = ExAllocatePoolWithTag(NonPagedPool,
718                                 sizeof(FS_CHANGE_NOTIFY_ENTRY),
719                                 TAG_FS_CHANGE_NOTIFY);
720   if (Entry == NULL)
721     return(STATUS_INSUFFICIENT_RESOURCES);
722
723   Entry->DriverObject = DriverObject;
724   Entry->FSDNotificationProc = FSDNotificationProc;
725
726   ExInterlockedInsertHeadList(&FsChangeNotifyListHead,
727                               &Entry->FsChangeNotifyList,
728                               &FsChangeNotifyListLock);
729
730   return(STATUS_SUCCESS);
731 }
732
733
734 /*
735  * @implemented
736  */
737 VOID STDCALL
738 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
739                                  IN PFSDNOTIFICATIONPROC FSDNotificationProc)
740 {
741   PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
742   PLIST_ENTRY Entry;
743   KIRQL oldlvl;
744
745   Entry = FsChangeNotifyListHead.Flink;
746   while (Entry != &FsChangeNotifyListHead)
747     {
748       ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
749       if (ChangeEntry->DriverObject == DriverObject &&
750           ChangeEntry->FSDNotificationProc == FSDNotificationProc)
751         {
752           KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
753           RemoveEntryList(Entry);
754           KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
755
756           ExFreePool(Entry);
757           return;
758         }
759
760       Entry = Entry->Flink;
761     }
762 }
763
764 /* EOF */