xref: /reactos/drivers/filesystems/ext2/src/block.c (revision 8a978a17)
1 /*
2  * COPYRIGHT:        See COPYRIGHT.TXT
3  * PROJECT:          Ext2 File System Driver for WinNT/2K/XP
4  * FILE:             block.c
5  * PROGRAMMER:       Matt Wu <mattwu@163.com>
6  * HOMEPAGE:         http://www.ext2fsd.com
7  * UPDATE HISTORY:
8  */
9 
10 /* INCLUDES *****************************************************************/
11 
12 #include "ext2fs.h"
13 
14 /* GLOBALS ***************************************************************/
15 
16 extern PEXT2_GLOBAL Ext2Global;
17 
18 /* DEFINITIONS *************************************************************/
19 
20 NTSTATUS NTAPI
21 Ext2ReadWriteBlockSyncCompletionRoutine (
22     IN PDEVICE_OBJECT DeviceObject,
23     IN PIRP Irp,
24     IN PVOID Context    );
25 
26 NTSTATUS NTAPI
27 Ext2ReadWriteBlockAsyncCompletionRoutine (
28     IN PDEVICE_OBJECT DeviceObject,
29     IN PIRP Irp,
30     IN PVOID Context    );
31 
32 
33 NTSTATUS NTAPI
34 Ext2MediaEjectControlCompletion (
35     IN PDEVICE_OBJECT DeviceObject,
36     IN PIRP Irp,
37     IN PVOID Contxt     );
38 
39 #ifdef ALLOC_PRAGMA
40 #pragma alloc_text(PAGE, Ext2LockUserBuffer)
41 #pragma alloc_text(PAGE, Ext2ReadSync)
42 #pragma alloc_text(PAGE, Ext2ReadDisk)
43 #pragma alloc_text(PAGE, Ext2DiskIoControl)
44 #pragma alloc_text(PAGE, Ext2MediaEjectControl)
45 #pragma alloc_text(PAGE, Ext2DiskShutDown)
46 #endif
47 
48 
49 /* FUNCTIONS ***************************************************************/
50 
51 PMDL
52 Ext2CreateMdl (
53     IN PVOID Buffer,
54     IN ULONG Length,
55     IN LOCK_OPERATION op
56 )
57 {
58     NTSTATUS Status;
59     PMDL Mdl = NULL;
60 
61     ASSERT (Buffer != NULL);
62     Mdl = IoAllocateMdl (Buffer, Length, FALSE, FALSE, NULL);
63     if (Mdl == NULL) {
64         Status = STATUS_INSUFFICIENT_RESOURCES;
65     } else {
66         _SEH2_TRY {
67             if (MmIsNonPagedSystemAddressValid(Buffer)) {
68                 MmBuildMdlForNonPagedPool(Mdl);
69             } else {
70                 MmProbeAndLockPages(Mdl, KernelMode, op);
71             }
72             Status = STATUS_SUCCESS;
73         } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
74             IoFreeMdl (Mdl);
75             Mdl = NULL;
76             DbgBreak();
77             Status = STATUS_INVALID_USER_BUFFER;
78         } _SEH2_END;
79     }
80     return Mdl;
81 }
82 
83 
84 VOID
85 Ext2DestroyMdl (IN PMDL Mdl)
86 {
87     ASSERT (Mdl != NULL);
88     while (Mdl) {
89         PMDL Next;
90         Next = Mdl->Next;
91         Mdl->Next = NULL;
92         if (IsFlagOn(Mdl->MdlFlags, MDL_PAGES_LOCKED)) {
93             MmUnlockPages (Mdl);
94         }
95         IoFreeMdl (Mdl);
96         Mdl = Next;
97     }
98 }
99 
100 NTSTATUS
101 Ext2LockUserBuffer (IN PIRP     Irp,
102                     IN ULONG            Length,
103                     IN LOCK_OPERATION   Operation)
104 {
105     NTSTATUS Status;
106     ASSERT(Irp != NULL);
107 
108     if (Irp->MdlAddress != NULL) {
109         return STATUS_SUCCESS;
110     }
111 
112     IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, Irp);
113     if (Irp->MdlAddress == NULL) {
114         return STATUS_INSUFFICIENT_RESOURCES;
115     }
116 
117     _SEH2_TRY {
118 
119         MmProbeAndLockPages(Irp->MdlAddress, Irp->RequestorMode, Operation);
120         Status = STATUS_SUCCESS;
121 
122     } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
123 
124         DbgBreak();
125         IoFreeMdl(Irp->MdlAddress);
126         Irp->MdlAddress = NULL;
127         Status = STATUS_INVALID_USER_BUFFER;
128     } _SEH2_END;
129 
130     return Status;
131 }
132 
133 PVOID
134 Ext2GetUserBuffer (IN PIRP Irp )
135 {
136     ASSERT(Irp != NULL);
137 
138     if (Irp->MdlAddress) {
139 
140 #if (_WIN32_WINNT >= 0x0500)
141         return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
142 #else
143         return MmGetSystemAddressForMdl(Irp->MdlAddress);
144 #endif
145     } else {
146 
147         return Irp->UserBuffer;
148     }
149 }
150 
151 NTSTATUS NTAPI
152 Ext2ReadWriteBlockSyncCompletionRoutine (
153     IN PDEVICE_OBJECT DeviceObject,
154     IN PIRP Irp,
155     IN PVOID Context    )
156 {
157     PEXT2_RW_CONTEXT pContext = (PEXT2_RW_CONTEXT)Context;
158 
159     if (Irp != pContext->MasterIrp) {
160 
161         if (!NT_SUCCESS(Irp->IoStatus.Status)) {
162             pContext->MasterIrp->IoStatus = Irp->IoStatus;
163         }
164 
165         IoFreeMdl(Irp->MdlAddress);
166         IoFreeIrp(Irp );
167     }
168 
169     if (InterlockedDecrement(&pContext->Blocks) == 0) {
170 
171         pContext->MasterIrp->IoStatus.Information = 0;
172         if (NT_SUCCESS(pContext->MasterIrp->IoStatus.Status)) {
173 
174             pContext->MasterIrp->IoStatus.Information =
175                 pContext->Length;
176         }
177 
178         KeSetEvent(&pContext->Event, 0, FALSE);
179     }
180 
181     return STATUS_MORE_PROCESSING_REQUIRED;
182 }
183 
184 NTSTATUS NTAPI
185 Ext2ReadWriteBlockAsyncCompletionRoutine (
186     IN PDEVICE_OBJECT DeviceObject,
187     IN PIRP Irp,
188     IN PVOID Context
189 )
190 {
191     PEXT2_RW_CONTEXT pContext = (PEXT2_RW_CONTEXT)Context;
192     PIO_STACK_LOCATION iosp;
193 
194     ASSERT(FALSE == pContext->Wait);
195 
196     if (Irp != pContext->MasterIrp && !NT_SUCCESS(Irp->IoStatus.Status)) {
197         pContext->MasterIrp->IoStatus = Irp->IoStatus;
198     }
199 
200     if (InterlockedDecrement(&pContext->Blocks) == 0) {
201 
202         if (NT_SUCCESS(pContext->MasterIrp->IoStatus.Status)) {
203 
204             /* set written bytes to status information */
205             pContext->MasterIrp->IoStatus.Information = pContext->Length;
206 
207             if (pContext->FileObject != NULL && !IsFlagOn(pContext->MasterIrp->Flags, IRP_PAGING_IO)) {
208 
209                 /* modify FileObject flags, skip this for volume direct access */
210                 SetFlag( pContext->FileObject->Flags,
211                          IsFlagOn(pContext->Flags, EXT2_RW_CONTEXT_WRITE) ?
212                          FO_FILE_MODIFIED : FO_FILE_FAST_IO_READ);
213 
214                 /* update Current Byteoffset */
215                 if (IsFlagOn(pContext->FileObject->Flags, FO_SYNCHRONOUS_IO)) {
216                     iosp = IoGetCurrentIrpStackLocation(pContext->MasterIrp);
217                     pContext->FileObject->CurrentByteOffset.QuadPart =
218                         iosp->Parameters.Read.ByteOffset.QuadPart +  pContext->Length;
219                 }
220             }
221 
222         } else {
223 
224             pContext->MasterIrp->IoStatus.Information = 0;
225         }
226 
227         /* release the locked resource acquired by the caller */
228         if (pContext->Resource) {
229             ExReleaseResourceForThread(pContext->Resource, pContext->ThreadId);
230         }
231 
232         Ext2FreePool(pContext, EXT2_RWC_MAGIC);
233         DEC_MEM_COUNT(PS_RW_CONTEXT, pContext, sizeof(EXT2_RW_CONTEXT));
234     }
235 
236     return STATUS_SUCCESS;
237 }
238 
239 NTSTATUS
240 Ext2ReadWriteBlocks(
241     IN PEXT2_IRP_CONTEXT    IrpContext,
242     IN PEXT2_VCB            Vcb,
243     IN PEXT2_EXTENT         Chain,
244     IN ULONG                Length
245     )
246 {
247     PIRP                Irp;
248     PIRP                MasterIrp = IrpContext->Irp;
249     PIO_STACK_LOCATION  IrpSp;
250     PMDL                Mdl;
251     PEXT2_RW_CONTEXT    pContext = NULL;
252     PEXT2_EXTENT        Extent;
253     KEVENT              Wait;
254     NTSTATUS            Status = STATUS_SUCCESS;
255     BOOLEAN             bMasterCompleted = FALSE;
256     BOOLEAN             bBugCheck = FALSE;
257 
258     ASSERT(MasterIrp);
259 
260     _SEH2_TRY {
261 
262         pContext = Ext2AllocatePool(NonPagedPool, sizeof(EXT2_RW_CONTEXT), EXT2_RWC_MAGIC);
263 
264         if (!pContext) {
265             DEBUG(DL_ERR, ( "Ex2ReadWriteBlocks: failed to allocate pContext.\n"));
266             Status = STATUS_INSUFFICIENT_RESOURCES;
267             _SEH2_LEAVE;
268         }
269 
270         INC_MEM_COUNT(PS_RW_CONTEXT, pContext, sizeof(EXT2_RW_CONTEXT));
271         RtlZeroMemory(pContext, sizeof(EXT2_RW_CONTEXT));
272         pContext->Wait = Ext2CanIWait();
273         pContext->MasterIrp = MasterIrp;
274         pContext->Length = Length;
275 
276         if (IrpContext->MajorFunction == IRP_MJ_WRITE) {
277             SetFlag(pContext->Flags, EXT2_RW_CONTEXT_WRITE);
278         }
279 
280         if (pContext->Wait) {
281 
282             KeInitializeEvent(&(pContext->Event), NotificationEvent, FALSE);
283 
284         } else if (IrpContext->Fcb->Identifier.Type == EXT2FCB) {
285 
286             if (IsFlagOn(MasterIrp->Flags, IRP_PAGING_IO)) {
287                 pContext->Resource = &IrpContext->Fcb->PagingIoResource;
288             } else {
289                 pContext->Resource = &IrpContext->Fcb->MainResource;
290             }
291 
292             pContext->FileObject = IrpContext->FileObject;
293             pContext->ThreadId = ExGetCurrentResourceThread();
294         }
295 
296 
297         if (NULL == Chain->Next && 0 == Chain->Offset) {
298 
299             /* we get only 1 extent to dispatch, then don't bother allocating new irps */
300 
301             /* setup the Stack location to do a read from the disk driver. */
302             IrpSp = IoGetNextIrpStackLocation(MasterIrp);
303             IrpSp->MajorFunction = IrpContext->MajorFunction;
304             IrpSp->Parameters.Read.Length = Chain->Length;
305             IrpSp->Parameters.Read.ByteOffset.QuadPart = Chain->Lba;
306             if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH)) {
307                 SetFlag(IrpSp->Flags, SL_WRITE_THROUGH);
308             }
309             if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ)) {
310                 SetFlag(IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME);
311             }
312 
313             IoSetCompletionRoutine(
314                     MasterIrp,
315                     Ext2CanIWait() ?
316                     Ext2ReadWriteBlockSyncCompletionRoutine :
317                     Ext2ReadWriteBlockAsyncCompletionRoutine,
318                     (PVOID) pContext,
319                     TRUE,
320                     TRUE,
321                     TRUE );
322 
323             /* intialize context block */
324             Chain->Irp = MasterIrp;
325             pContext->Blocks = 1;
326 
327         } else {
328 
329             for (Extent = Chain; Extent != NULL; Extent = Extent->Next) {
330 
331                 Irp = IoMakeAssociatedIrp(
332                           MasterIrp,
333                           (CCHAR)(Vcb->TargetDeviceObject->StackSize + 1) );
334 
335                 if (!Irp) {
336                     Status = STATUS_INSUFFICIENT_RESOURCES;
337                     _SEH2_LEAVE;
338                 }
339 
340                 Mdl = IoAllocateMdl( (PCHAR)MasterIrp->UserBuffer +
341                                      Extent->Offset,
342                                      Extent->Length,
343                                      FALSE,
344                                      FALSE,
345                                      Irp );
346 
347                 if (!Mdl)  {
348                     Status = STATUS_INSUFFICIENT_RESOURCES;
349                     _SEH2_LEAVE;
350                 }
351 
352                 IoBuildPartialMdl( MasterIrp->MdlAddress,
353                                    Mdl,
354                                    (PCHAR)MasterIrp->UserBuffer+Extent->Offset,
355                                    Extent->Length );
356 
357                 IoSetNextIrpStackLocation(Irp);
358                 IrpSp = IoGetCurrentIrpStackLocation(Irp);
359 
360                 IrpSp->MajorFunction = IrpContext->MajorFunction;
361                 IrpSp->Parameters.Read.Length = Extent->Length;
362                 IrpSp->Parameters.Read.ByteOffset.QuadPart = Extent->Lba;
363 
364                 IoSetCompletionRoutine(
365                     Irp,
366                     Ext2CanIWait() ?
367                     Ext2ReadWriteBlockSyncCompletionRoutine :
368                     Ext2ReadWriteBlockAsyncCompletionRoutine,
369                     (PVOID) pContext,
370                     TRUE,
371                     TRUE,
372                     TRUE );
373 
374                 IrpSp = IoGetNextIrpStackLocation(Irp);
375 
376                 IrpSp->MajorFunction = IrpContext->MajorFunction;
377                 IrpSp->Parameters.Read.Length =Extent->Length;
378                 IrpSp->Parameters.Read.ByteOffset.QuadPart = Extent->Lba;
379 
380                 /* set write through flag */
381                 if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH)) {
382                     SetFlag( IrpSp->Flags, SL_WRITE_THROUGH );
383                 }
384 
385                 /* set verify flag */
386                 if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ)) {
387                     SetFlag(IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME);
388                 }
389 
390                 Extent->Irp = Irp;
391                 pContext->Blocks += 1;
392             }
393 
394             MasterIrp->AssociatedIrp.IrpCount = pContext->Blocks;
395             if (Ext2CanIWait()) {
396                 MasterIrp->AssociatedIrp.IrpCount += 1;
397             }
398         }
399         if (!Ext2CanIWait()) {
400             /* mark MasterIrp pending */
401             IoMarkIrpPending(pContext->MasterIrp);
402         }
403 
404         bBugCheck = TRUE;
405 
406         for (Extent = Chain; Extent != NULL; Extent = Extent->Next) {
407             Status = IoCallDriver ( Vcb->TargetDeviceObject,
408                                     Extent->Irp);
409             Extent->Irp = NULL;
410         }
411 
412         if (Ext2CanIWait()) {
413             KeWaitForSingleObject( &(pContext->Event),
414                                    Executive, KernelMode, FALSE, NULL );
415             KeClearEvent( &(pContext->Event) );
416         } else {
417             bMasterCompleted = TRUE;
418         }
419 
420     } _SEH2_FINALLY {
421 
422         for (Extent = Chain; Extent != NULL; Extent = Extent->Next)  {
423             if (Extent->Irp != NULL ) {
424                 if (Extent->Irp->MdlAddress != NULL) {
425                     IoFreeMdl(Extent->Irp->MdlAddress );
426                 }
427                 IoFreeIrp(Extent->Irp);
428             }
429         }
430 
431         if (IrpContext->ExceptionInProgress) {
432 
433             if (bBugCheck) {
434                 Ext2BugCheck(EXT2_BUGCHK_BLOCK, 0, 0, 0);
435             }
436 
437         } else {
438 
439             if (Ext2CanIWait()) {
440                 if (MasterIrp) {
441                     Status = MasterIrp->IoStatus.Status;
442                 }
443                 if (pContext) {
444                     Ext2FreePool(pContext, EXT2_RWC_MAGIC);
445                     DEC_MEM_COUNT(PS_RW_CONTEXT, pContext, sizeof(EXT2_RW_CONTEXT));
446                 }
447             } else {
448                 if (bMasterCompleted) {
449                     IrpContext->Irp = NULL;
450                     Status = STATUS_PENDING;
451                 }
452             }
453         }
454     } _SEH2_END;
455 
456     return Status;
457 }
458 
459 NTSTATUS
460 Ext2ReadSync(
461     IN PEXT2_VCB        Vcb,
462     IN ULONGLONG        Offset,
463     IN ULONG            Length,
464     OUT PVOID           Buffer,
465     BOOLEAN             bVerify
466 )
467 {
468     PKEVENT         Event = NULL;
469 
470     PIRP            Irp;
471     IO_STATUS_BLOCK IoStatus;
472     NTSTATUS        Status = STATUS_INSUFFICIENT_RESOURCES;
473 
474 
475     ASSERT(Vcb != NULL);
476     ASSERT(Vcb->TargetDeviceObject != NULL);
477     ASSERT(Buffer != NULL);
478 
479     _SEH2_TRY {
480 
481         Event = Ext2AllocatePool(NonPagedPool, sizeof(KEVENT), 'EK2E');
482 
483         if (NULL == Event) {
484             DEBUG(DL_ERR, ( "Ex2ReadSync: failed to allocate Event.\n"));
485             _SEH2_LEAVE;
486         }
487 
488         INC_MEM_COUNT(PS_DISK_EVENT, Event, sizeof(KEVENT));
489 
490         KeInitializeEvent(Event, NotificationEvent, FALSE);
491 
492         Irp = IoBuildSynchronousFsdRequest(
493                   IRP_MJ_READ,
494                   Vcb->TargetDeviceObject,
495                   Buffer,
496                   Length,
497                   (PLARGE_INTEGER)(&Offset),
498                   Event,
499                   &IoStatus
500               );
501 
502         if (!Irp) {
503             Status = STATUS_INSUFFICIENT_RESOURCES;
504             _SEH2_LEAVE;
505         }
506 
507         if (bVerify) {
508             SetFlag( IoGetNextIrpStackLocation(Irp)->Flags,
509                      SL_OVERRIDE_VERIFY_VOLUME );
510         }
511 
512         Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
513 
514         if (Status == STATUS_PENDING) {
515             KeWaitForSingleObject(
516                 Event,
517                 Suspended,
518                 KernelMode,
519                 FALSE,
520                 NULL
521             );
522 
523             Status = IoStatus.Status;
524         }
525 
526     } _SEH2_FINALLY {
527 
528         if (Event) {
529             Ext2FreePool(Event, 'EK2E');
530             DEC_MEM_COUNT(PS_DISK_EVENT, Event, sizeof(KEVENT));
531         }
532     } _SEH2_END;
533 
534     return Status;
535 }
536 
537 
538 NTSTATUS
539 Ext2ReadDisk(
540     IN PEXT2_VCB   Vcb,
541     IN ULONGLONG   Offset,
542     IN ULONG       Size,
543     IN PVOID       Buffer,
544     IN BOOLEAN     bVerify )
545 {
546     NTSTATUS    Status;
547     PUCHAR      Buf;
548     ULONG       Length;
549     ULONGLONG   Lba;
550 
551     Lba = Offset & (~((ULONGLONG)SECTOR_SIZE - 1));
552     Length = (ULONG)(Size + Offset + SECTOR_SIZE - 1 - Lba) &
553              (~((ULONG)SECTOR_SIZE - 1));
554 
555     Buf = Ext2AllocatePool(PagedPool, Length, EXT2_DATA_MAGIC);
556     if (!Buf) {
557         DEBUG(DL_ERR, ( "Ext2ReadDisk: failed to allocate Buffer.\n"));
558         Status = STATUS_INSUFFICIENT_RESOURCES;
559 
560         goto errorout;
561     }
562     INC_MEM_COUNT(PS_DISK_BUFFER, Buf, Length);
563 
564     Status = Ext2ReadSync(  Vcb,
565                             Lba,
566                             Length,
567                             Buf,
568                             FALSE );
569 
570     if (!NT_SUCCESS(Status)) {
571         DEBUG(DL_ERR, ("Ext2ReadDisk: disk i/o error: %xh.\n", Status));
572         goto errorout;
573     }
574 
575     RtlCopyMemory(Buffer, &Buf[Offset - Lba], Size);
576 
577 errorout:
578 
579     if (Buf) {
580         Ext2FreePool(Buf, EXT2_DATA_MAGIC);
581         DEC_MEM_COUNT(PS_DISK_BUFFER, Buf, Length);
582     }
583 
584     return Status;
585 }
586 
587 
588 NTSTATUS
589 Ext2DiskIoControl (
590     IN PDEVICE_OBJECT   DeviceObject,
591     IN ULONG            IoctlCode,
592     IN PVOID            InputBuffer,
593     IN ULONG            InputBufferSize,
594     IN OUT PVOID        OutputBuffer,
595     IN OUT PULONG       OutputBufferSize)
596 {
597     ULONG           OutBufferSize = 0;
598     KEVENT          Event;
599     PIRP            Irp;
600     IO_STATUS_BLOCK IoStatus;
601     NTSTATUS        Status;
602 
603     ASSERT(DeviceObject != NULL);
604 
605     if (OutputBufferSize)
606     {
607         OutBufferSize = *OutputBufferSize;
608     }
609 
610     KeInitializeEvent(&Event, NotificationEvent, FALSE);
611 
612     Irp = IoBuildDeviceIoControlRequest(
613               IoctlCode,
614               DeviceObject,
615               InputBuffer,
616               InputBufferSize,
617               OutputBuffer,
618               OutBufferSize,
619               FALSE,
620               &Event,
621               &IoStatus
622           );
623 
624     if (Irp == NULL) {
625         DEBUG(DL_ERR, ( "Ext2DiskIoControl: failed to build Irp!\n"));
626         return STATUS_INSUFFICIENT_RESOURCES;
627     }
628 
629     Status = IoCallDriver(DeviceObject, Irp);
630 
631     if (Status == STATUS_PENDING)  {
632         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
633         Status = IoStatus.Status;
634     }
635 
636     if (OutputBufferSize) {
637         *OutputBufferSize = (ULONG)(IoStatus.Information);
638     }
639 
640     return Status;
641 }
642 
643 
644 NTSTATUS NTAPI
645 Ext2MediaEjectControlCompletion (
646     IN PDEVICE_OBJECT DeviceObject,
647     IN PIRP Irp,
648     IN PVOID Contxt
649 )
650 {
651     PKEVENT Event = (PKEVENT)Contxt;
652 
653     KeSetEvent( Event, 0, FALSE );
654 
655     UNREFERENCED_PARAMETER( DeviceObject );
656 
657     return STATUS_SUCCESS;
658 }
659 
660 VOID
661 Ext2MediaEjectControl (
662     IN PEXT2_IRP_CONTEXT IrpContext,
663     IN PEXT2_VCB Vcb,
664     IN BOOLEAN bPrevent
665 )
666 {
667     PIRP                    Irp;
668     KEVENT                  Event;
669     NTSTATUS                Status;
670     PREVENT_MEDIA_REMOVAL   Prevent;
671     IO_STATUS_BLOCK         IoStatus;
672 
673 
674     ExAcquireResourceExclusiveLite(
675         &Vcb->MainResource,
676         TRUE            );
677 
678     if (bPrevent != IsFlagOn(Vcb->Flags, VCB_REMOVAL_PREVENTED)) {
679         if (bPrevent) {
680             SetFlag(Vcb->Flags, VCB_REMOVAL_PREVENTED);
681         } else {
682             ClearFlag(Vcb->Flags, VCB_REMOVAL_PREVENTED);
683         }
684     }
685 
686     ExReleaseResourceLite(&Vcb->MainResource);
687 
688     Prevent.PreventMediaRemoval = bPrevent;
689 
690     KeInitializeEvent( &Event, NotificationEvent, FALSE );
691 
692     Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_MEDIA_REMOVAL,
693                                          Vcb->TargetDeviceObject,
694                                          &Prevent,
695                                          sizeof(PREVENT_MEDIA_REMOVAL),
696                                          NULL,
697                                          0,
698                                          FALSE,
699                                          NULL,
700                                          &IoStatus );
701 
702     if (Irp != NULL) {
703         IoSetCompletionRoutine( Irp,
704                                 Ext2MediaEjectControlCompletion,
705                                 &Event,
706                                 TRUE,
707                                 TRUE,
708                                 TRUE );
709 
710         Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
711 
712         if (Status == STATUS_PENDING) {
713             Status = KeWaitForSingleObject( &Event,
714                                             Executive,
715                                             KernelMode,
716                                             FALSE,
717                                             NULL );
718         }
719     }
720 }
721 
722 
723 NTSTATUS
724 Ext2DiskShutDown(PEXT2_VCB Vcb)
725 {
726     PIRP                Irp;
727     KEVENT              Event;
728 
729     NTSTATUS            Status;
730     IO_STATUS_BLOCK     IoStatus;
731 
732     KeInitializeEvent(&Event, NotificationEvent, FALSE);
733 
734     Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
735                                        Vcb->TargetDeviceObject,
736                                        NULL,
737                                        0,
738                                        NULL,
739                                        &Event,
740                                        &IoStatus);
741 
742     if (Irp) {
743         Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
744 
745         if (Status == STATUS_PENDING) {
746             KeWaitForSingleObject(&Event,
747                                   Executive,
748                                   KernelMode,
749                                   FALSE,
750                                   NULL);
751 
752             Status = IoStatus.Status;
753         }
754     } else  {
755         Status = IoStatus.Status;
756     }
757 
758     return Status;
759 }
760