update for HEAD-2003050101
[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
39 /* GLOBALS ******************************************************************/
40
41 static ERESOURCE 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   ExInitializeResourceLite(&FileSystemListLock);
163
164   InitializeListHead(&FsChangeNotifyListHead);
165   KeInitializeSpinLock(&FsChangeNotifyListLock);
166 }
167
168
169 VOID
170 IoShutdownRegisteredFileSystems(VOID)
171 {
172   PLIST_ENTRY current_entry;
173   FILE_SYSTEM_OBJECT* current;
174   PIRP Irp;
175   KEVENT Event;
176   IO_STATUS_BLOCK IoStatusBlock;
177   NTSTATUS Status;
178
179   DPRINT("IoShutdownRegisteredFileSystems()\n");
180
181   ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
182   KeInitializeEvent(&Event,
183                     NotificationEvent,
184                     FALSE);
185
186   current_entry = FileSystemListHead.Flink;
187   while (current_entry!=(&FileSystemListHead))
188     {
189       current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
190
191       /* send IRP_MJ_SHUTDOWN */
192       Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
193                                          current->DeviceObject,
194                                          NULL,
195                                          0,
196                                          0,
197                                          &Event,
198                                          &IoStatusBlock);
199
200       Status = IoCallDriver(current->DeviceObject,Irp);
201       if (Status == STATUS_PENDING)
202         {
203           KeWaitForSingleObject(&Event,
204                                 Executive,
205                                 KernelMode,
206                                 FALSE,
207                                 NULL);
208         }
209
210       current_entry = current_entry->Flink;
211     }
212
213   ExReleaseResourceLite(&FileSystemListLock);
214 }
215
216
217 static NTSTATUS
218 IopMountFileSystem(PDEVICE_OBJECT DeviceObject,
219                    PDEVICE_OBJECT DeviceToMount)
220 {
221   IO_STATUS_BLOCK IoStatusBlock;
222   PIO_STACK_LOCATION StackPtr;
223   KEVENT Event;
224   PIRP Irp;
225   NTSTATUS Status;
226
227   DPRINT("IoAskFileSystemToMountDevice(DeviceObject %x, DeviceToMount %x)\n",
228          DeviceObject,DeviceToMount);
229
230   assert_irql(PASSIVE_LEVEL);
231
232   KeInitializeEvent(&Event, NotificationEvent, FALSE);
233   Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
234   if (Irp==NULL)
235     {
236       return(STATUS_INSUFFICIENT_RESOURCES);
237     }
238
239   Irp->UserIosb = &IoStatusBlock;
240   DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
241   Irp->UserEvent = &Event;
242   Irp->Tail.Overlay.Thread = PsGetCurrentThread();
243
244   StackPtr = IoGetNextIrpStackLocation(Irp);
245   StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
246   StackPtr->MinorFunction = IRP_MN_MOUNT_VOLUME;
247   StackPtr->Flags = 0;
248   StackPtr->Control = 0;
249   StackPtr->DeviceObject = DeviceObject;
250   StackPtr->FileObject = NULL;
251   StackPtr->CompletionRoutine = NULL;
252
253   StackPtr->Parameters.MountVolume.Vpb = DeviceToMount->Vpb;
254   StackPtr->Parameters.MountVolume.DeviceObject = DeviceToMount;
255
256   Status = IoCallDriver(DeviceObject,Irp);
257   if (Status==STATUS_PENDING)
258     {
259       KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
260       Status = IoStatusBlock.Status;
261     }
262
263   return(Status);
264 }
265
266
267 static NTSTATUS
268 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject)
269 {
270   IO_STATUS_BLOCK IoStatusBlock;
271   PIO_STACK_LOCATION StackPtr;
272   KEVENT Event;
273   PIRP Irp;
274   NTSTATUS Status;
275
276   DPRINT("IopLoadFileSystem(DeviceObject %x)\n", DeviceObject);
277
278   assert_irql(PASSIVE_LEVEL);
279
280   KeInitializeEvent(&Event, NotificationEvent, FALSE);
281   Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
282   if (Irp==NULL)
283     {
284       return(STATUS_INSUFFICIENT_RESOURCES);
285     }
286
287   Irp->UserIosb = &IoStatusBlock;
288   DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
289   Irp->UserEvent = &Event;
290   Irp->Tail.Overlay.Thread = PsGetCurrentThread();
291
292   StackPtr = IoGetNextIrpStackLocation(Irp);
293   StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
294   StackPtr->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM;
295   StackPtr->Flags = 0;
296   StackPtr->Control = 0;
297   StackPtr->DeviceObject = DeviceObject;
298   StackPtr->FileObject = NULL;
299   StackPtr->CompletionRoutine = NULL;
300
301   Status = IoCallDriver(DeviceObject,Irp);
302   if (Status==STATUS_PENDING)
303     {
304       KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
305       Status = IoStatusBlock.Status;
306     }
307
308   return(Status);
309 }
310
311
312 NTSTATUS
313 IoMountVolume(IN PDEVICE_OBJECT DeviceObject,
314               IN BOOLEAN AllowRawMount)
315 /*
316  * FUNCTION: Mounts a logical volume
317  * ARGUMENTS:
318  *         DeviceObject = Device to mount
319  * RETURNS: Status
320  */
321 {
322   PLIST_ENTRY current_entry;
323   FILE_SYSTEM_OBJECT* current;
324   NTSTATUS Status;
325   DEVICE_TYPE MatchingDeviceType;
326   PDEVICE_OBJECT DevObject;
327
328   assert_irql(PASSIVE_LEVEL);
329
330   DPRINT("IoMountVolume(DeviceObject %x  AllowRawMount %x)\n",
331          DeviceObject, AllowRawMount);
332
333   switch (DeviceObject->DeviceType)
334     {
335       case FILE_DEVICE_DISK:
336       case FILE_DEVICE_VIRTUAL_DISK: /* ?? */
337         MatchingDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
338         break;
339
340       case FILE_DEVICE_CD_ROM:
341         MatchingDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
342         break;
343
344       case FILE_DEVICE_NETWORK:
345         MatchingDeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
346         break;
347
348       case FILE_DEVICE_TAPE:
349         MatchingDeviceType = FILE_DEVICE_TAPE_FILE_SYSTEM;
350         break;
351
352       default:
353         CPRINT("No matching file system type found for device type: %x\n",
354                DeviceObject->DeviceType);
355         return(STATUS_UNRECOGNIZED_VOLUME);
356     }
357
358   ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
359   current_entry = FileSystemListHead.Flink;
360   while (current_entry!=(&FileSystemListHead))
361     {
362       current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
363       if (current->DeviceObject->DeviceType != MatchingDeviceType)
364         {
365           current_entry = current_entry->Flink;
366           continue;
367         }
368       Status = IopMountFileSystem(current->DeviceObject,
369                                   DeviceObject);
370       switch (Status)
371         {
372           case STATUS_FS_DRIVER_REQUIRED:
373             DevObject = current->DeviceObject;
374             ExReleaseResourceLite(&FileSystemListLock);
375             Status = IopLoadFileSystem(DevObject);
376             if (!NT_SUCCESS(Status))
377               {
378                 return(Status);
379               }
380             ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
381             current_entry = FileSystemListHead.Flink;
382             continue;
383
384           case STATUS_SUCCESS:
385             DeviceObject->Vpb->Flags = DeviceObject->Vpb->Flags |
386                                        VPB_MOUNTED;
387             ExReleaseResourceLite(&FileSystemListLock);
388             return(STATUS_SUCCESS);
389
390           case STATUS_UNRECOGNIZED_VOLUME:
391           default:
392             current_entry = current_entry->Flink;
393         }
394     }
395   ExReleaseResourceLite(&FileSystemListLock);
396
397   return(STATUS_UNRECOGNIZED_VOLUME);
398 }
399
400
401 /**********************************************************************
402  * NAME                                                 EXPORTED
403  *      IoVerifyVolume
404  *
405  * DESCRIPTION
406  *      Verify the file system type and volume information or mount
407  *      a file system.
408  *
409  * ARGUMENTS
410  *      DeviceObject
411  *              Device to verify or mount
412  *
413  *      AllowRawMount
414  *              ...
415  *
416  * RETURN VALUE
417  *      Status
418  */
419 NTSTATUS STDCALL
420 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject,
421                IN BOOLEAN AllowRawMount)
422 {
423   IO_STATUS_BLOCK IoStatusBlock;
424   PIO_STACK_LOCATION StackPtr;
425   KEVENT Event;
426   PIRP Irp;
427   NTSTATUS Status;
428
429   DPRINT("IoVerifyVolume(DeviceObject %x  AllowRawMount %x)\n",
430          DeviceObject, AllowRawMount);
431
432   Status = STATUS_SUCCESS;
433
434   KeWaitForSingleObject(&DeviceObject->DeviceLock,
435                         Executive,
436                         KernelMode,
437                         FALSE,
438                         NULL);
439
440   DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
441
442   if (DeviceObject->Vpb->Flags & VPB_MOUNTED)
443     {
444       /* Issue verify request to the FSD */
445
446       KeInitializeEvent(&Event,
447                         NotificationEvent,
448                         FALSE);
449
450       Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
451       if (Irp==NULL)
452         {
453           return(STATUS_INSUFFICIENT_RESOURCES);
454         }
455
456       Irp->UserIosb = &IoStatusBlock;
457       Irp->UserEvent = &Event;
458       Irp->Tail.Overlay.Thread = PsGetCurrentThread();
459
460       StackPtr = IoGetNextIrpStackLocation(Irp);
461       StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
462       StackPtr->MinorFunction = IRP_MN_VERIFY_VOLUME;
463       StackPtr->Flags = 0;
464       StackPtr->Control = 0;
465       StackPtr->DeviceObject = DeviceObject;
466       StackPtr->FileObject = NULL;
467       StackPtr->CompletionRoutine = NULL;
468
469       StackPtr->Parameters.VerifyVolume.Vpb = DeviceObject->Vpb;
470       StackPtr->Parameters.VerifyVolume.DeviceObject = DeviceObject;
471
472       Status = IoCallDriver(DeviceObject,
473                             Irp);
474       if (Status==STATUS_PENDING)
475         {
476           KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
477           Status = IoStatusBlock.Status;
478         }
479
480       if (NT_SUCCESS(Status))
481         {
482           KeSetEvent(&DeviceObject->DeviceLock,
483                      IO_NO_INCREMENT,
484                      FALSE);
485           return(STATUS_SUCCESS);
486         }
487     }
488
489   if (Status == STATUS_WRONG_VOLUME)
490     {
491       /* Clean existing VPB. This unmounts the filesystem (in an ugly way). */
492       DPRINT("Wrong volume!\n");
493
494       DeviceObject->Vpb->DeviceObject = NULL;
495       DeviceObject->Vpb->Flags &= ~VPB_MOUNTED;
496     }
497
498   /* Start mount sequence */
499   Status = IoMountVolume(DeviceObject,
500                          AllowRawMount);
501
502   KeSetEvent(&DeviceObject->DeviceLock,
503              IO_NO_INCREMENT,
504              FALSE);
505
506   return(Status);
507 }
508
509
510 PDEVICE_OBJECT STDCALL
511 IoGetDeviceToVerify(IN PETHREAD Thread)
512 /*
513  * FUNCTION: Returns a pointer to the device, representing a removable-media
514  * device, that is the target of the given thread's I/O request
515  */
516 {
517   return(Thread->DeviceToVerify);
518 }
519
520
521 VOID STDCALL
522 IoSetDeviceToVerify(IN PETHREAD Thread,
523                     IN PDEVICE_OBJECT DeviceObject)
524 {
525   Thread->DeviceToVerify = DeviceObject;
526 }
527
528
529 VOID STDCALL
530 IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
531                              IN PDEVICE_OBJECT DeviceObject)
532 {
533   Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
534 }
535
536
537 VOID STDCALL
538 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
539 {
540   PFILE_SYSTEM_OBJECT Fs;
541
542   DPRINT("IoRegisterFileSystem(DeviceObject %x)\n",DeviceObject);
543
544   Fs = ExAllocatePoolWithTag(NonPagedPool,
545                              sizeof(FILE_SYSTEM_OBJECT),
546                              TAG_FILE_SYSTEM);
547   assert(Fs!=NULL);
548
549   Fs->DeviceObject = DeviceObject;
550   ExAcquireResourceExclusiveLite(&FileSystemListLock, TRUE);
551
552   InsertTailList(&FileSystemListHead,
553                  &Fs->Entry);
554
555   ExReleaseResourceLite(&FileSystemListLock);
556
557   IopNotifyFileSystemChange(DeviceObject,
558                             TRUE);
559 }
560
561
562 VOID STDCALL
563 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
564 {
565   PLIST_ENTRY current_entry;
566   PFILE_SYSTEM_OBJECT current;
567
568   DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject);
569
570   ExAcquireResourceExclusiveLite(&FileSystemListLock, TRUE);
571   current_entry = FileSystemListHead.Flink;
572   while (current_entry!=(&FileSystemListHead))
573     {
574       current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
575       if (current->DeviceObject == DeviceObject)
576         {
577           RemoveEntryList(current_entry);
578           ExFreePool(current);
579           ExReleaseResourceLite(&FileSystemListLock);
580           IopNotifyFileSystemChange(DeviceObject, FALSE);
581           return;
582         }
583       current_entry = current_entry->Flink;
584     }
585   ExReleaseResourceLite(&FileSystemListLock);
586 }
587
588
589 /**********************************************************************
590  * NAME                                                 EXPORTED
591  *      IoGetBaseFileSystemDeviceObject@4
592  *
593  * DESCRIPTION
594  *      Get the DEVICE_OBJECT associated to
595  *      a FILE_OBJECT.
596  *
597  * ARGUMENTS
598  *      FileObject
599  *
600  * RETURN VALUE
601  *
602  * NOTE
603  *      From Bo Branten's ntifs.h v13.
604  */
605 PDEVICE_OBJECT STDCALL
606 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
607 {
608         PDEVICE_OBJECT  DeviceObject = NULL;
609         PVPB            Vpb = NULL;
610
611         /*
612          * If the FILE_OBJECT's VPB is defined,
613          * get the device from it.
614          */
615         if (NULL != (Vpb = FileObject->Vpb)) 
616         {
617                 if (NULL != (DeviceObject = Vpb->DeviceObject))
618                 {
619                         /* Vpb->DeviceObject DEFINED! */
620                         return DeviceObject;
621                 }
622         }
623         /*
624          * If that failed, try the VPB
625          * in the FILE_OBJECT's DeviceObject.
626          */
627         DeviceObject = FileObject->DeviceObject;
628         if (NULL == (Vpb = DeviceObject->Vpb)) 
629         {
630                 /* DeviceObject->Vpb UNDEFINED! */
631                 return DeviceObject;
632         }
633         /*
634          * If that pointer to the VPB is again
635          * undefined, return directly the
636          * device object from the FILE_OBJECT.
637          */
638         return (
639                 (NULL == Vpb->DeviceObject)
640                         ? DeviceObject
641                         : Vpb->DeviceObject
642                 );
643 }
644
645
646 static VOID
647 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
648                           BOOLEAN DriverActive)
649 {
650   PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
651   PLIST_ENTRY Entry;
652   KIRQL oldlvl;
653
654   KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
655   Entry = FsChangeNotifyListHead.Flink;
656   while (Entry != &FsChangeNotifyListHead)
657     {
658       ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
659
660       (ChangeEntry->FSDNotificationProc)(DeviceObject, DriverActive);
661
662       Entry = Entry->Flink;
663     }
664   KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
665 }
666
667
668 NTSTATUS STDCALL
669 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
670                                IN PFSDNOTIFICATIONPROC FSDNotificationProc)
671 {
672   PFS_CHANGE_NOTIFY_ENTRY Entry;
673
674   Entry = ExAllocatePoolWithTag(NonPagedPool,
675                                 sizeof(FS_CHANGE_NOTIFY_ENTRY),
676                                 TAG_FS_CHANGE_NOTIFY);
677   if (Entry == NULL)
678     return(STATUS_INSUFFICIENT_RESOURCES);
679
680   Entry->DriverObject = DriverObject;
681   Entry->FSDNotificationProc = FSDNotificationProc;
682
683   ExInterlockedInsertHeadList(&FsChangeNotifyListHead,
684                               &Entry->FsChangeNotifyList,
685                               &FsChangeNotifyListLock);
686
687   return(STATUS_SUCCESS);
688 }
689
690
691 VOID STDCALL
692 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
693                                  IN PFSDNOTIFICATIONPROC FSDNotificationProc)
694 {
695   PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
696   PLIST_ENTRY Entry;
697   KIRQL oldlvl;
698
699   Entry = FsChangeNotifyListHead.Flink;
700   while (Entry != &FsChangeNotifyListHead)
701     {
702       ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
703       if (ChangeEntry->DriverObject == DriverObject &&
704           ChangeEntry->FSDNotificationProc == FSDNotificationProc)
705         {
706           KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
707           RemoveEntryList(Entry);
708           KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
709
710           ExFreePool(Entry);
711           return;
712         }
713
714       Entry = Entry->Flink;
715     }
716 }
717
718 /* EOF */