xref: /reactos/drivers/filesystems/ext2/src/memory.c (revision aaeb131b)
1 /*
2  * COPYRIGHT:        See COPYRIGHT.TXT
3  * PROJECT:          Ext2 File System Driver for WinNT/2K/XP
4  * FILE:             memory.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 #ifdef ALLOC_PRAGMA
21 #pragma alloc_text(PAGE, Ext2AllocateInode)
22 #pragma alloc_text(PAGE, Ext2DestroyInode)
23 #pragma alloc_text(PAGE, Ext2CheckBitmapConsistency)
24 #pragma alloc_text(PAGE, Ext2CheckSetBlock)
25 #pragma alloc_text(PAGE, Ext2InitializeVcb)
26 #pragma alloc_text(PAGE, Ext2TearDownStream)
27 #pragma alloc_text(PAGE, Ext2DestroyVcb)
28 #pragma alloc_text(PAGE, Ext2SyncUninitializeCacheMap)
29 #pragma alloc_text(PAGE, Ext2ReaperThread)
30 #pragma alloc_text(PAGE, Ext2StartReaper)
31 #pragma alloc_text(PAGE, Ext2StopReaper)
32 #endif
33 
34 PEXT2_IRP_CONTEXT
Ext2AllocateIrpContext(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)35 Ext2AllocateIrpContext (IN PDEVICE_OBJECT   DeviceObject,
36                         IN PIRP             Irp )
37 {
38     PIO_STACK_LOCATION   irpSp;
39     PEXT2_IRP_CONTEXT    IrpContext;
40 
41     ASSERT(DeviceObject != NULL);
42     ASSERT(Irp != NULL);
43 
44     irpSp = IoGetCurrentIrpStackLocation(Irp);
45 
46     IrpContext = (PEXT2_IRP_CONTEXT) (
47                      ExAllocateFromNPagedLookasideList(
48                          &(Ext2Global->Ext2IrpContextLookasideList)));
49 
50     if (IrpContext == NULL) {
51         return NULL;
52     }
53 
54     RtlZeroMemory(IrpContext, sizeof(EXT2_IRP_CONTEXT) );
55 
56     IrpContext->Identifier.Type = EXT2ICX;
57     IrpContext->Identifier.Size = sizeof(EXT2_IRP_CONTEXT);
58 
59     IrpContext->Irp = Irp;
60     IrpContext->MajorFunction = irpSp->MajorFunction;
61     IrpContext->MinorFunction = irpSp->MinorFunction;
62     IrpContext->DeviceObject = DeviceObject;
63     IrpContext->FileObject = irpSp->FileObject;
64     if (NULL != IrpContext->FileObject) {
65         IrpContext->Fcb = (PEXT2_FCB)IrpContext->FileObject->FsContext;
66         IrpContext->Ccb = (PEXT2_CCB)IrpContext->FileObject->FsContext2;
67     }
68 
69     if (IrpContext->FileObject != NULL) {
70         IrpContext->RealDevice = IrpContext->FileObject->DeviceObject;
71     } else if (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) {
72         if (irpSp->Parameters.MountVolume.Vpb) {
73             IrpContext->RealDevice = irpSp->Parameters.MountVolume.Vpb->RealDevice;
74         }
75     }
76 
77     if (IsFlagOn(irpSp->Flags, SL_WRITE_THROUGH)) {
78         SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH);
79     }
80 
81     if (IsFlagOn(irpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME)) {
82         SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ);
83     }
84 
85     if (IrpContext->MajorFunction == IRP_MJ_CLEANUP ||
86         IrpContext->MajorFunction == IRP_MJ_CLOSE ||
87         IrpContext->MajorFunction == IRP_MJ_SHUTDOWN ||
88         IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL ||
89         IrpContext->MajorFunction == IRP_MJ_PNP ) {
90 
91         if (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL ||
92             IrpContext->MajorFunction == IRP_MJ_PNP) {
93             if (IoGetCurrentIrpStackLocation(Irp)->FileObject == NULL ||
94                 IoIsOperationSynchronous(Irp)) {
95                 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
96             }
97         } else {
98             SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
99         }
100 
101     } else if (IoIsOperationSynchronous(Irp)) {
102 
103         SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
104     }
105 
106     IrpContext->IsTopLevel = (IoGetTopLevelIrp() == Irp);
107     IrpContext->ExceptionInProgress = FALSE;
108     INC_IRP_COUNT(IrpContext);
109 
110     return IrpContext;
111 }
112 
113 VOID
Ext2FreeIrpContext(IN PEXT2_IRP_CONTEXT IrpContext)114 Ext2FreeIrpContext (IN PEXT2_IRP_CONTEXT IrpContext)
115 {
116     ASSERT(IrpContext != NULL);
117 
118     ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
119            (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
120 
121     /* free the IrpContext to NonPagedList */
122     IrpContext->Identifier.Type = 0;
123     IrpContext->Identifier.Size = 0;
124 
125     DEC_IRP_COUNT(IrpContext);
126     ExFreeToNPagedLookasideList(&(Ext2Global->Ext2IrpContextLookasideList), IrpContext);
127 }
128 
129 
130 PEXT2_FCB
Ext2AllocateFcb(IN PEXT2_VCB Vcb,IN PEXT2_MCB Mcb)131 Ext2AllocateFcb (
132     IN PEXT2_VCB   Vcb,
133     IN PEXT2_MCB   Mcb
134 )
135 {
136     PEXT2_FCB Fcb;
137 
138     ASSERT(ExIsResourceAcquiredExclusiveLite(&Vcb->FcbLock));
139 
140     Fcb = (PEXT2_FCB) ExAllocateFromNPagedLookasideList(
141               &(Ext2Global->Ext2FcbLookasideList));
142 
143     if (!Fcb) {
144         return NULL;
145     }
146 
147     RtlZeroMemory(Fcb, sizeof(EXT2_FCB));
148     Fcb->Identifier.Type = EXT2FCB;
149     Fcb->Identifier.Size = sizeof(EXT2_FCB);
150 
151 #ifndef _WIN2K_TARGET_
152     ExInitializeFastMutex(&Fcb->Mutex);
153     FsRtlSetupAdvancedHeader(&Fcb->Header,  &Fcb->Mutex);
154 #endif
155 
156     FsRtlInitializeOplock(&Fcb->Oplock);
157     FsRtlInitializeFileLock (
158         &Fcb->FileLockAnchor,
159         NULL,
160         NULL );
161 
162     Fcb->OpenHandleCount = 0;
163     Fcb->ReferenceCount = 0;
164     Fcb->Vcb = Vcb;
165     Fcb->Inode = &Mcb->Inode;
166 
167     ASSERT(Mcb->Fcb == NULL);
168     Ext2ReferMcb(Mcb);
169     Fcb->Mcb = Mcb;
170     Mcb->Fcb = Fcb;
171 
172     DEBUG(DL_RES, ("Ext2AllocateFcb: Fcb %p created: %wZ.\n",
173                    Fcb, &Fcb->Mcb->FullName));
174 
175     RtlZeroMemory(&Fcb->Header, sizeof(FSRTL_COMMON_FCB_HEADER));
176     Fcb->Header.NodeTypeCode = (USHORT) EXT2FCB;
177     Fcb->Header.NodeByteSize = sizeof(EXT2_FCB);
178     Fcb->Header.IsFastIoPossible = FastIoIsNotPossible;
179     Fcb->Header.Resource = &(Fcb->MainResource);
180     Fcb->Header.PagingIoResource = &(Fcb->PagingIoResource);
181 
182     Fcb->Header.FileSize.QuadPart = Mcb->Inode.i_size;
183     Fcb->Header.ValidDataLength.QuadPart = Mcb->Inode.i_size;
184     Fcb->Header.AllocationSize.QuadPart = CEILING_ALIGNED(ULONGLONG,
185                                           Fcb->Header.FileSize.QuadPart, (ULONGLONG)Vcb->BlockSize);
186 
187     Fcb->SectionObject.DataSectionObject = NULL;
188     Fcb->SectionObject.SharedCacheMap = NULL;
189     Fcb->SectionObject.ImageSectionObject = NULL;
190 
191     ExInitializeResourceLite(&(Fcb->MainResource));
192     ExInitializeResourceLite(&(Fcb->PagingIoResource));
193 
194     Ext2InsertFcb(Vcb, Fcb);
195 
196     INC_MEM_COUNT(PS_FCB, Fcb, sizeof(EXT2_FCB));
197 
198     return Fcb;
199 }
200 
201 VOID
Ext2UnlinkFcb(IN PEXT2_FCB Fcb)202 Ext2UnlinkFcb(IN PEXT2_FCB Fcb)
203 {
204     PEXT2_VCB  Vcb = Fcb->Vcb;
205     PEXT2_MCB  Mcb;
206 
207     ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
208     Mcb = Fcb->Mcb;
209 
210     DEBUG(DL_INF, ("Ext2FreeFcb: Fcb (%p) to be unlinked: %wZ.\n",
211                     Fcb, Mcb ? &Mcb->FullName : NULL));
212 
213     if ((Mcb != NULL) &&
214         (Mcb->Identifier.Type == EXT2MCB) &&
215         (Mcb->Identifier.Size == sizeof(EXT2_MCB))) {
216 
217         ASSERT (Mcb->Fcb == Fcb);
218         if (IsMcbSpecialFile(Mcb) ||
219             IsFileDeleted(Mcb)) {
220 
221             ASSERT(!IsRoot(Fcb));
222             Ext2RemoveMcb(Vcb, Mcb);
223             Mcb->Fcb = NULL;
224 
225             Ext2UnlinkMcb(Vcb, Mcb);
226             Ext2DerefMcb(Mcb);
227             Ext2LinkHeadMcb(Vcb, Mcb);
228 
229         } else {
230             Mcb->Fcb = NULL;
231             Ext2DerefMcb(Mcb);
232         }
233         Fcb->Mcb = NULL;
234     }
235 
236     ExReleaseResourceLite(&Vcb->McbLock);
237 }
238 
239 VOID
Ext2FreeFcb(IN PEXT2_FCB Fcb)240 Ext2FreeFcb (IN PEXT2_FCB Fcb)
241 {
242     PEXT2_VCB   Vcb = Fcb->Vcb;
243 
244     _SEH2_TRY {
245 
246         ASSERT((Fcb != NULL) && (Fcb->Identifier.Type == EXT2FCB) &&
247                (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
248         ASSERT(0 == Fcb->ReferenceCount);
249 
250 #ifndef _WIN2K_TARGET_
251         FsRtlTeardownPerStreamContexts(&Fcb->Header);
252 #endif
253 
254         FsRtlUninitializeFileLock(&Fcb->FileLockAnchor);
255         FsRtlUninitializeOplock(&Fcb->Oplock);
256         ExDeleteResourceLite(&Fcb->MainResource);
257         ExDeleteResourceLite(&Fcb->PagingIoResource);
258 
259         Fcb->Identifier.Type = 0;
260         Fcb->Identifier.Size = 0;
261 
262         ExFreeToNPagedLookasideList(&(Ext2Global->Ext2FcbLookasideList), Fcb);
263         DEC_MEM_COUNT(PS_FCB, Fcb, sizeof(EXT2_FCB));
264 
265         if (0 == Ext2DerefXcb(&Vcb->ReferenceCount)) {
266             if (!IsMounted(Vcb) || IsDispending(Vcb)) {
267                 Ext2CheckDismount(NULL, Vcb, FALSE);
268             }
269         }
270 
271     } _SEH2_FINALLY {
272     } _SEH2_END;
273 }
274 
275 VOID
Ext2ReleaseFcb(IN PEXT2_FCB Fcb)276 Ext2ReleaseFcb (IN PEXT2_FCB Fcb)
277 {
278     PEXT2_VCB   Vcb = Fcb->Vcb;
279     PEXT2_MCB   Mcb;
280 
281     if (0 != Ext2DerefXcb(&Fcb->ReferenceCount))
282         return;
283 
284     ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
285     ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE);
286 
287     Mcb = Fcb->Mcb;
288     RemoveEntryList(&Fcb->Next);
289 
290     if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING) ||
291         NULL == Mcb || IsFileDeleted(Mcb)) {
292         InsertHeadList(&Vcb->FcbList, &Fcb->Next);
293         Fcb->TsDrop.QuadPart = 0;
294     } else {
295         InsertTailList(&Vcb->FcbList, &Fcb->Next);
296         KeQuerySystemTime(&Fcb->TsDrop);
297     }
298     ExReleaseResourceLite(&Fcb->MainResource);
299     ExReleaseResourceLite(&Vcb->FcbLock);
300 
301     if ((Vcb->FcbCount >> 6) > (ULONG)(Ext2Global->MaxDepth)) {
302         KeSetEvent(&Ext2Global->FcbReaper.Wait, 0, FALSE);
303     }
304 }
305 
306 /* Insert Fcb to Vcb->FcbList queue, with Vcb->FcbLock Acquired. */
307 
308 VOID
Ext2InsertFcb(PEXT2_VCB Vcb,PEXT2_FCB Fcb)309 Ext2InsertFcb(PEXT2_VCB Vcb, PEXT2_FCB Fcb)
310 {
311     ASSERT(ExIsResourceAcquiredExclusiveLite(&Vcb->FcbLock));
312 
313     KeQuerySystemTime(&Fcb->TsDrop);
314     Ext2ReferXcb(&Vcb->FcbCount);
315     Ext2ReferXcb(&Vcb->ReferenceCount);
316     InsertTailList(&Vcb->FcbList, &Fcb->Next);
317 }
318 
319 PEXT2_CCB
Ext2AllocateCcb(ULONG Flags,PEXT2_MCB SymLink)320 Ext2AllocateCcb (ULONG Flags, PEXT2_MCB SymLink)
321 {
322     PEXT2_CCB Ccb;
323 
324     Ccb = (PEXT2_CCB) (ExAllocateFromNPagedLookasideList(
325                            &(Ext2Global->Ext2CcbLookasideList)));
326     if (!Ccb) {
327         return NULL;
328     }
329 
330     DEBUG(DL_RES, ( "ExtAllocateCcb: Ccb created: %ph.\n", Ccb));
331 
332     RtlZeroMemory(Ccb, sizeof(EXT2_CCB));
333 
334     Ccb->Identifier.Type = EXT2CCB;
335     Ccb->Identifier.Size = sizeof(EXT2_CCB);
336     Ccb->Flags = Flags;
337 
338     Ccb->SymLink = SymLink;
339     if (SymLink) {
340         ASSERT(SymLink->Refercount > 0);
341         Ext2ReferMcb(SymLink);
342         DEBUG(DL_INF, ( "ExtAllocateCcb: Ccb SymLink: %wZ.\n",
343                         &Ccb->SymLink->FullName));
344     }
345 
346     Ccb->DirectorySearchPattern.Length = 0;
347     Ccb->DirectorySearchPattern.MaximumLength = 0;
348     Ccb->DirectorySearchPattern.Buffer = 0;
349 
350     INC_MEM_COUNT(PS_CCB, Ccb, sizeof(EXT2_CCB));
351 
352     return Ccb;
353 }
354 
355 VOID
Ext2FreeCcb(IN PEXT2_VCB Vcb,IN PEXT2_CCB Ccb)356 Ext2FreeCcb (IN PEXT2_VCB Vcb, IN PEXT2_CCB Ccb)
357 {
358     ASSERT(Ccb != NULL);
359     ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
360            (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
361 
362     DEBUG(DL_RES, ( "Ext2FreeCcb: Ccb = %ph.\n", Ccb));
363 
364     if (Ccb->SymLink) {
365         DEBUG(DL_INF, ( "Ext2FreeCcb: Ccb SymLink: %wZ.\n",
366                         &Ccb->SymLink->FullName));
367         if (IsFileDeleted(Ccb->SymLink->Target)) {
368             Ext2UnlinkMcb(Vcb, Ccb->SymLink);
369             Ext2DerefMcb(Ccb->SymLink);
370             Ext2LinkHeadMcb(Vcb, Ccb->SymLink);
371         } else {
372             Ext2DerefMcb(Ccb->SymLink);
373         }
374     }
375 
376     if (Ccb->DirectorySearchPattern.Buffer != NULL) {
377         DEC_MEM_COUNT(PS_DIR_PATTERN, Ccb->DirectorySearchPattern.Buffer,
378                       Ccb->DirectorySearchPattern.MaximumLength );
379         Ext2FreePool(Ccb->DirectorySearchPattern.Buffer, EXT2_DIRSP_MAGIC);
380     }
381 
382     ExFreeToNPagedLookasideList(&(Ext2Global->Ext2CcbLookasideList), Ccb);
383     DEC_MEM_COUNT(PS_CCB, Ccb, sizeof(EXT2_CCB));
384 }
385 
386 PEXT2_INODE
Ext2AllocateInode(PEXT2_VCB Vcb)387 Ext2AllocateInode (PEXT2_VCB  Vcb)
388 {
389     PVOID inode = NULL;
390 
391     inode = ExAllocateFromNPagedLookasideList(
392                 &(Vcb->InodeLookasideList));
393     if (!inode) {
394         return NULL;
395     }
396 
397     RtlZeroMemory(inode, INODE_SIZE);
398 
399     DEBUG(DL_INF, ("ExtAllocateInode: Inode created: %ph.\n", inode));
400     INC_MEM_COUNT(PS_EXT2_INODE, inode, INODE_SIZE);
401 
402     return inode;
403 }
404 
405 VOID
Ext2DestroyInode(IN PEXT2_VCB Vcb,IN PEXT2_INODE inode)406 Ext2DestroyInode (IN PEXT2_VCB Vcb, IN PEXT2_INODE inode)
407 {
408     ASSERT(inode != NULL);
409 
410     DEBUG(DL_INF, ("Ext2FreeInode: Inode = %ph.\n", inode));
411 
412     ExFreeToNPagedLookasideList(&(Vcb->InodeLookasideList), inode);
413     DEC_MEM_COUNT(PS_EXT2_INODE, inode, INODE_SIZE);
414 }
415 
Ext2AllocateEntry()416 struct dentry * Ext2AllocateEntry()
417 {
418     struct dentry *de;
419 
420     de = (struct dentry *)ExAllocateFromNPagedLookasideList(
421              &(Ext2Global->Ext2DentryLookasideList));
422     if (!de) {
423         return NULL;
424     }
425 
426     RtlZeroMemory(de, sizeof(struct dentry));
427     INC_MEM_COUNT(PS_DENTRY, de, sizeof(struct dentry));
428 
429     return de;
430 }
431 
Ext2FreeEntry(IN struct dentry * de)432 VOID Ext2FreeEntry (IN struct dentry *de)
433 {
434     ASSERT(de != NULL);
435 
436     if (de->d_name.name)
437         ExFreePool(de->d_name.name);
438 
439     ExFreeToNPagedLookasideList(&(Ext2Global->Ext2DentryLookasideList), de);
440     DEC_MEM_COUNT(PS_DENTRY, de, sizeof(struct dentry));
441 }
442 
443 
Ext2BuildEntry(PEXT2_VCB Vcb,PEXT2_MCB Dcb,PUNICODE_STRING FileName)444 struct dentry *Ext2BuildEntry(PEXT2_VCB Vcb, PEXT2_MCB Dcb, PUNICODE_STRING FileName)
445 {
446     OEM_STRING      Oem = { 0 };
447     struct dentry  *de = NULL;
448     NTSTATUS        Status = STATUS_INSUFFICIENT_RESOURCES;
449 
450     _SEH2_TRY {
451 
452         de = Ext2AllocateEntry();
453         if (!de) {
454             DEBUG(DL_ERR, ("Ext2BuildEntry: failed to allocate dentry.\n"));
455             _SEH2_LEAVE;
456         }
457         de->d_sb = &Vcb->sb;
458         if (Dcb)
459             de->d_parent = Dcb->de;
460 
461         Oem.MaximumLength = (USHORT)Ext2UnicodeToOEMSize(Vcb, FileName) + 1;
462         Oem.Buffer = ExAllocatePool(PagedPool, Oem.MaximumLength);
463         if (!Oem.Buffer) {
464             DEBUG(DL_ERR, ( "Ex2BuildEntry: failed to allocate OEM name.\n"));
465             _SEH2_LEAVE;
466         }
467         de->d_name.name = Oem.Buffer;
468         RtlZeroMemory(Oem.Buffer, Oem.MaximumLength);
469         Status = Ext2UnicodeToOEM(Vcb, &Oem, FileName);
470         if (!NT_SUCCESS(Status)) {
471             DEBUG(DL_CP, ("Ext2BuildEntry: failed to convert %S to OEM.\n", FileName->Buffer));
472             _SEH2_LEAVE;
473         }
474         de->d_name.len  = Oem.Length;
475 
476     } _SEH2_FINALLY {
477 
478         if (!NT_SUCCESS(Status)) {
479             if (de)
480                 Ext2FreeEntry(de);
481         }
482     } _SEH2_END;
483 
484     return de;
485 }
486 
487 PEXT2_EXTENT
Ext2AllocateExtent()488 Ext2AllocateExtent ()
489 {
490     PEXT2_EXTENT Extent;
491 
492     Extent = (PEXT2_EXTENT)ExAllocateFromNPagedLookasideList(
493                  &(Ext2Global->Ext2ExtLookasideList));
494     if (!Extent) {
495         return NULL;
496     }
497 
498     RtlZeroMemory(Extent, sizeof(EXT2_EXTENT));
499     INC_MEM_COUNT(PS_EXTENT, Extent, sizeof(EXT2_EXTENT));
500 
501     return Extent;
502 }
503 
504 VOID
Ext2FreeExtent(IN PEXT2_EXTENT Extent)505 Ext2FreeExtent (IN PEXT2_EXTENT Extent)
506 {
507     ASSERT(Extent != NULL);
508     ExFreeToNPagedLookasideList(&(Ext2Global->Ext2ExtLookasideList), Extent);
509     DEC_MEM_COUNT(PS_EXTENT, Extent, sizeof(EXT2_EXTENT));
510 }
511 
512 ULONG
Ext2CountExtents(IN PEXT2_EXTENT Chain)513 Ext2CountExtents(IN PEXT2_EXTENT Chain)
514 {
515     ULONG        count = 0;
516     PEXT2_EXTENT List = Chain;
517 
518     while (List) {
519         count += 1;
520         List = List->Next;
521     }
522 
523     return count;
524 }
525 
526 VOID
Ext2JointExtents(IN PEXT2_EXTENT Chain,IN PEXT2_EXTENT Extent)527 Ext2JointExtents(
528     IN PEXT2_EXTENT Chain,
529     IN PEXT2_EXTENT Extent
530 )
531 {
532 #ifndef __REACTOS__
533     ULONG        count = 0;
534 #endif
535     PEXT2_EXTENT List = Chain;
536 
537     while (List->Next) {
538         List = List->Next;
539     }
540 
541     List->Next = Extent;
542 }
543 
544 
545 VOID
Ext2DestroyExtentChain(IN PEXT2_EXTENT Chain)546 Ext2DestroyExtentChain(IN PEXT2_EXTENT Chain)
547 {
548     PEXT2_EXTENT Extent = NULL, List = Chain;
549 
550     while (List) {
551         Extent = List->Next;
552         Ext2FreeExtent(List);
553         List = Extent;
554     }
555 }
556 
557 BOOLEAN
Ext2ListExtents(PLARGE_MCB Extents)558 Ext2ListExtents(PLARGE_MCB  Extents)
559 {
560     if (FsRtlNumberOfRunsInLargeMcb(Extents) != 0) {
561 
562         LONGLONG            DirtyVba;
563         LONGLONG            DirtyLba;
564         LONGLONG            DirtyLength;
565         int                 i, n = 0;
566 
567         for (i = 0; FsRtlGetNextLargeMcbEntry(
568                     Extents, i, &DirtyVba,
569                     &DirtyLba, &DirtyLength); i++)  {
570             if (DirtyVba > 0 && DirtyLba != -1) {
571                 DEBUG(DL_EXT, ("Vba:%I64xh Lba:%I64xh Len:%I64xh.\n", DirtyVba, DirtyLba, DirtyLength));
572                 n++;
573             }
574         }
575 
576         return n ? TRUE : FALSE;
577     }
578 
579     return FALSE;
580 }
581 
582 VOID
Ext2CheckExtent(PLARGE_MCB Zone,LONGLONG Vbn,LONGLONG Lbn,LONGLONG Length,BOOLEAN bAdded)583 Ext2CheckExtent(
584     PLARGE_MCB  Zone,
585     LONGLONG    Vbn,
586     LONGLONG    Lbn,
587     LONGLONG    Length,
588     BOOLEAN     bAdded
589 )
590 {
591 #if EXT2_DEBUG
592     LONGLONG    DirtyLbn;
593     LONGLONG    DirtyLen;
594     LONGLONG    RunStart;
595     LONGLONG    RunLength;
596     ULONG       Index;
597     BOOLEAN     bFound = FALSE;
598 
599     bFound = FsRtlLookupLargeMcbEntry(
600                  Zone,
601                  Vbn,
602                  &DirtyLbn,
603                  &DirtyLen,
604                  &RunStart,
605                  &RunLength,
606                  &Index );
607 
608     if (!bAdded && (!bFound || DirtyLbn == -1)) {
609         return;
610     }
611 
612     if ( !bFound || (DirtyLbn == -1) ||
613             (DirtyLbn != Lbn) ||
614             (DirtyLen < Length)) {
615 
616         DbgBreak();
617 
618         for (Index = 0; TRUE; Index++) {
619 
620             if (!FsRtlGetNextLargeMcbEntry(
621                         Zone,
622                         Index,
623                         &Vbn,
624                         &Lbn,
625                         &Length)) {
626                 break;
627             }
628 
629             DEBUG(DL_EXT, ("Index = %xh Vbn = %I64xh Lbn = %I64xh Len = %I64xh\n",
630                            Index, Vbn, Lbn, Length ));
631         }
632     }
633 #endif
634 }
635 
636 VOID
Ext2ClearAllExtents(PLARGE_MCB Zone)637 Ext2ClearAllExtents(PLARGE_MCB  Zone)
638 {
639     _SEH2_TRY {
640         FsRtlTruncateLargeMcb(Zone, (LONGLONG)0);
641     } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
642         DbgBreak();
643     } _SEH2_END;
644 }
645 
646 
647 BOOLEAN
Ext2AddVcbExtent(IN PEXT2_VCB Vcb,IN LONGLONG Vbn,IN LONGLONG Length)648 Ext2AddVcbExtent (
649     IN PEXT2_VCB Vcb,
650     IN LONGLONG  Vbn,
651     IN LONGLONG  Length
652 )
653 {
654     ULONG       TriedTimes = 0;
655 
656     LONGLONG    Offset = 0;
657     BOOLEAN     rc = FALSE;
658 
659     Offset = Vbn & (~(Vcb->IoUnitSize - 1));
660     Length = (Vbn - Offset + Length + Vcb->IoUnitSize - 1) &
661              ~(Vcb->IoUnitSize - 1);
662 
663     ASSERT ((Offset & (Vcb->IoUnitSize - 1)) == 0);
664     ASSERT ((Length & (Vcb->IoUnitSize - 1)) == 0);
665 
666     Offset = (Offset >> Vcb->IoUnitBits) + 1;
667     Length = (Length >> Vcb->IoUnitBits);
668 
669 Again:
670 
671     _SEH2_TRY {
672         rc = FsRtlAddLargeMcbEntry(
673                 &Vcb->Extents,
674                 Offset,
675                 Offset,
676                 Length
677                 );
678     } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
679         DbgBreak();
680         rc = FALSE;
681     } _SEH2_END;
682 
683     if (!rc && ++TriedTimes < 10) {
684         Ext2Sleep(TriedTimes * 100);
685         goto Again;
686     }
687 
688     DEBUG(DL_EXT, ("Ext2AddVcbExtent: Vbn=%I64xh Length=%I64xh,"
689                    " rc=%d Runs=%u\n", Offset, Length, rc,
690                    FsRtlNumberOfRunsInLargeMcb(&Vcb->Extents)));
691 
692     if (rc) {
693         Ext2CheckExtent(&Vcb->Extents, Offset, Offset, Length, TRUE);
694     }
695 
696     return rc;
697 }
698 
699 BOOLEAN
Ext2RemoveVcbExtent(IN PEXT2_VCB Vcb,IN LONGLONG Vbn,IN LONGLONG Length)700 Ext2RemoveVcbExtent (
701     IN PEXT2_VCB Vcb,
702     IN LONGLONG  Vbn,
703     IN LONGLONG  Length
704 )
705 {
706     ULONG       TriedTimes = 0;
707     LONGLONG    Offset = 0;
708     BOOLEAN     rc = TRUE;
709 
710     Offset =  Vbn & (~(Vcb->IoUnitSize - 1));
711     Length = (Length + Vbn - Offset + Vcb->IoUnitSize - 1) & (~(Vcb->IoUnitSize - 1));
712 
713     ASSERT ((Offset & (Vcb->IoUnitSize - 1)) == 0);
714     ASSERT ((Length & (Vcb->IoUnitSize - 1)) == 0);
715 
716     Offset = (Offset >> Vcb->IoUnitBits) + 1;
717     Length = (Length >> Vcb->IoUnitBits);
718 
719 Again:
720 
721     _SEH2_TRY {
722         FsRtlRemoveLargeMcbEntry(
723             &Vcb->Extents,
724             Offset,
725             Length
726         );
727     } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
728         DbgBreak();
729         rc = FALSE;
730     } _SEH2_END;
731 
732     if (!rc && ++TriedTimes < 10) {
733         Ext2Sleep(TriedTimes * 100);
734         goto Again;
735     }
736 
737     DEBUG(DL_EXT, ("Ext2RemoveVcbExtent: Vbn=%I64xh Length=%I64xh Runs=%u\n",
738                    Offset, Length, FsRtlNumberOfRunsInLargeMcb(&Vcb->Extents)));
739     if (rc) {
740         Ext2CheckExtent(&Vcb->Extents, Offset, 0, Length, FALSE);
741     }
742 
743     return rc;
744 }
745 
746 BOOLEAN
Ext2LookupVcbExtent(IN PEXT2_VCB Vcb,IN LONGLONG Vbn,OUT PLONGLONG Lbn,OUT PLONGLONG Length)747 Ext2LookupVcbExtent (
748     IN PEXT2_VCB    Vcb,
749     IN LONGLONG     Vbn,
750     OUT PLONGLONG   Lbn,
751     OUT PLONGLONG   Length
752 )
753 {
754     LONGLONG    offset;
755     BOOLEAN     rc;
756 
757     offset = Vbn & (~(Vcb->IoUnitSize - 1));
758     ASSERT ((offset & (Vcb->IoUnitSize - 1)) == 0);
759     offset = (offset >> Vcb->IoUnitBits) + 1;
760 
761     rc = FsRtlLookupLargeMcbEntry(
762              &(Vcb->Extents),
763              offset,
764              Lbn,
765              Length,
766              NULL,
767              NULL,
768              NULL
769          );
770 
771     if (rc) {
772 
773         if (Lbn && ((*Lbn) != -1)) {
774             ASSERT((*Lbn) > 0);
775             (*Lbn) = (((*Lbn) - 1) << Vcb->IoUnitBits);
776             (*Lbn) += ((Vbn) & (Vcb->IoUnitSize - 1));
777         }
778 
779         if (Length && *Length) {
780             (*Length) <<= Vcb->IoUnitBits;
781             (*Length)  -= ((Vbn) & (Vcb->IoUnitSize - 1));
782         }
783     }
784 
785     return rc;
786 }
787 
788 
789 BOOLEAN
Ext2AddMcbExtent(IN PEXT2_VCB Vcb,IN PEXT2_MCB Mcb,IN LONGLONG Vbn,IN LONGLONG Lbn,IN LONGLONG Length)790 Ext2AddMcbExtent (
791     IN PEXT2_VCB Vcb,
792     IN PEXT2_MCB Mcb,
793     IN LONGLONG  Vbn,
794     IN LONGLONG  Lbn,
795     IN LONGLONG  Length
796 )
797 {
798     ULONG       TriedTimes = 0;
799     LONGLONG    Base = 0;
800     UCHAR       Bits = 0;
801     BOOLEAN     rc = FALSE;
802 
803     Base = (LONGLONG)BLOCK_SIZE;
804     Bits = (UCHAR)BLOCK_BITS;
805 
806     ASSERT ((Vbn & (Base - 1)) == 0);
807     ASSERT ((Lbn & (Base - 1)) == 0);
808     ASSERT ((Length & (Base - 1)) == 0);
809 
810     Vbn = (Vbn >> Bits) + 1;
811     Lbn =  (Lbn >> Bits) + 1;
812     Length = (Length >> Bits);
813 
814 Again:
815 
816     _SEH2_TRY {
817 
818         rc = FsRtlAddLargeMcbEntry(
819             &Mcb->Extents,
820             Vbn,
821             Lbn,
822             Length
823         );
824 
825     } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
826 
827         DbgBreak();
828         rc = FALSE;
829     } _SEH2_END;
830 
831     if (!rc && ++TriedTimes < 10) {
832         Ext2Sleep(TriedTimes * 100);
833         goto Again;
834     }
835 
836     DEBUG(DL_EXT, ("Ext2AddMcbExtent: Vbn=%I64xh Lbn=%I64xh Length=%I64xh,"
837                    " rc=%d Runs=%u\n", Vbn, Lbn, Length, rc,
838                    FsRtlNumberOfRunsInLargeMcb(&Mcb->Extents)));
839 
840     if (rc) {
841         Ext2CheckExtent(&Mcb->Extents, Vbn, Lbn, Length, TRUE);
842     }
843 
844     return rc;
845 }
846 
847 BOOLEAN
Ext2RemoveMcbExtent(IN PEXT2_VCB Vcb,IN PEXT2_MCB Mcb,IN LONGLONG Vbn,IN LONGLONG Length)848 Ext2RemoveMcbExtent (
849     IN PEXT2_VCB Vcb,
850     IN PEXT2_MCB Mcb,
851     IN LONGLONG  Vbn,
852     IN LONGLONG  Length
853 )
854 {
855     ULONG       TriedTimes = 0;
856     LONGLONG    Base = 0;
857     UCHAR       Bits = 0;
858     BOOLEAN     rc = TRUE;
859 
860     Base = (LONGLONG)BLOCK_SIZE;
861     Bits = (UCHAR)BLOCK_BITS;
862 
863     ASSERT ((Vbn & (Base - 1)) == 0);
864     ASSERT ((Length & (Base - 1)) == 0);
865 
866     Vbn = (Vbn >> Bits) + 1;
867     Length = (Length >> Bits);
868 
869 Again:
870 
871     _SEH2_TRY {
872         FsRtlRemoveLargeMcbEntry(
873             &Mcb->Extents,
874             Vbn,
875             Length
876         );
877     } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
878         DbgBreak();
879         rc = FALSE;
880     } _SEH2_END;
881 
882     if (!rc && ++TriedTimes < 10) {
883         Ext2Sleep(TriedTimes * 100);
884         goto Again;
885     }
886 
887     DEBUG(DL_EXT, ("Ext2RemoveMcbExtent: Vbn=%I64xh Length=%I64xh Runs=%u\n",
888                    Vbn, Length, FsRtlNumberOfRunsInLargeMcb(&Mcb->Extents)));
889     if (rc) {
890         Ext2CheckExtent(&Mcb->Extents, Vbn, 0, Length, FALSE);
891     }
892 
893     return rc;
894 }
895 
896 BOOLEAN
Ext2LookupMcbExtent(IN PEXT2_VCB Vcb,IN PEXT2_MCB Mcb,IN LONGLONG Vbn,OUT PLONGLONG Lbn,OUT PLONGLONG Length)897 Ext2LookupMcbExtent (
898     IN PEXT2_VCB    Vcb,
899     IN PEXT2_MCB    Mcb,
900     IN LONGLONG     Vbn,
901     OUT PLONGLONG   Lbn,
902     OUT PLONGLONG   Length
903 )
904 {
905     LONGLONG    offset;
906     BOOLEAN     rc;
907 
908     offset = Vbn & (~((LONGLONG)BLOCK_SIZE - 1));
909     ASSERT ((offset & (BLOCK_SIZE - 1)) == 0);
910     offset = (offset >> BLOCK_BITS) + 1;
911 
912     rc = FsRtlLookupLargeMcbEntry(
913              &(Mcb->Extents),
914              offset,
915              Lbn,
916              Length,
917              NULL,
918              NULL,
919              NULL
920          );
921 
922     if (rc) {
923 
924         if (Lbn && ((*Lbn) != -1)) {
925             ASSERT((*Lbn) > 0);
926             (*Lbn) = (((*Lbn) - 1) << BLOCK_BITS);
927             (*Lbn) += ((Vbn) & ((LONGLONG)BLOCK_SIZE - 1));
928         }
929 
930         if (Length && *Length) {
931             (*Length) <<= BLOCK_BITS;
932             (*Length)  -= ((Vbn) & ((LONGLONG)BLOCK_SIZE - 1));
933         }
934     }
935 
936     return rc;
937 }
938 
939 
940 BOOLEAN
Ext2AddMcbMetaExts(IN PEXT2_VCB Vcb,IN PEXT2_MCB Mcb,IN ULONG Block,IN ULONG Length)941 Ext2AddMcbMetaExts (
942     IN PEXT2_VCB Vcb,
943     IN PEXT2_MCB Mcb,
944     IN ULONG     Block,
945     IN ULONG     Length
946 )
947 {
948     ULONG       TriedTimes = 0;
949     LONGLONG    Lbn = Block + 1;
950     BOOLEAN     rc = TRUE;
951 
952 Again:
953 
954     _SEH2_TRY {
955 
956         rc = FsRtlAddLargeMcbEntry(
957                 &Mcb->MetaExts,
958                 Lbn,
959                 Lbn,
960                 Length
961              );
962 
963     } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
964 
965         DbgBreak();
966         rc = FALSE;
967     } _SEH2_END;
968 
969     if (!rc && ++TriedTimes < 10) {
970         Ext2Sleep(TriedTimes * 100);
971         goto Again;
972     }
973 
974     DEBUG(DL_EXT, ("Ext2AddMcbMetaExts: Block: %xh-%xh rc=%d Runs=%u\n", Block,
975                    Length, rc, FsRtlNumberOfRunsInLargeMcb(&Mcb->MetaExts)));
976 
977     if (rc) {
978         Ext2CheckExtent(&Mcb->MetaExts, Lbn, Lbn, Length, TRUE);
979     }
980 
981     return rc;
982 }
983 
984 BOOLEAN
Ext2RemoveMcbMetaExts(IN PEXT2_VCB Vcb,IN PEXT2_MCB Mcb,IN ULONG Block,IN ULONG Length)985 Ext2RemoveMcbMetaExts (
986     IN PEXT2_VCB Vcb,
987     IN PEXT2_MCB Mcb,
988     IN ULONG     Block,
989     IN ULONG     Length
990 )
991 {
992     ULONG       TriedTimes = 0;
993     LONGLONG    Lbn = Block + 1;
994     BOOLEAN     rc = TRUE;
995 
996 Again:
997 
998     _SEH2_TRY {
999 
1000         FsRtlRemoveLargeMcbEntry(
1001             &Mcb->MetaExts,
1002             Lbn,
1003             Length
1004         );
1005 
1006     } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
1007         DbgBreak();
1008         rc = FALSE;
1009     } _SEH2_END;
1010 
1011     if (!rc && ++TriedTimes < 10) {
1012         Ext2Sleep(TriedTimes * 100);
1013         goto Again;
1014     }
1015 
1016     DEBUG(DL_EXT, ("Ext2RemoveMcbMetaExts: Block: %xh-%xhh Runs=%u\n", Block,
1017                     Length, FsRtlNumberOfRunsInLargeMcb(&Mcb->MetaExts)));
1018     if (rc) {
1019         Ext2CheckExtent(&Mcb->MetaExts, Lbn, 0, Length, FALSE);
1020     }
1021 
1022     return rc;
1023 }
1024 
1025 
1026 BOOLEAN
Ext2AddBlockExtent(IN PEXT2_VCB Vcb,IN PEXT2_MCB Mcb,IN ULONG Start,IN ULONG Block,IN ULONG Number)1027 Ext2AddBlockExtent(
1028     IN PEXT2_VCB    Vcb,
1029     IN PEXT2_MCB    Mcb,
1030     IN ULONG        Start,
1031     IN ULONG        Block,
1032     IN ULONG        Number
1033 )
1034 {
1035     LONGLONG    Vbn = 0;
1036     LONGLONG    Lbn = 0;
1037     LONGLONG    Length = 0;
1038 
1039     Vbn = ((LONGLONG) Start) << BLOCK_BITS;
1040     Lbn = ((LONGLONG) Block) << BLOCK_BITS;
1041     Length = ((LONGLONG)Number << BLOCK_BITS);
1042 
1043     if (Mcb) {
1044 #if EXT2_DEBUG
1045         ULONG   _block = 0, _mapped = 0;
1046         BOOLEAN _rc = Ext2LookupBlockExtent(Vcb, Mcb, Start, &_block, &_mapped);
1047         if (_rc && _block != 0 && (_block != Block)) {
1048             DbgBreak();
1049         }
1050 #endif
1051         return Ext2AddMcbExtent(Vcb, Mcb, Vbn, Lbn, Length);
1052 
1053     }
1054 
1055     ASSERT(Start == Block);
1056     return Ext2AddVcbExtent(Vcb, Vbn, Length);
1057 }
1058 
1059 
1060 BOOLEAN
Ext2LookupBlockExtent(IN PEXT2_VCB Vcb,IN PEXT2_MCB Mcb,IN ULONG Start,IN PULONG Block,IN PULONG Mapped)1061 Ext2LookupBlockExtent(
1062     IN PEXT2_VCB    Vcb,
1063     IN PEXT2_MCB    Mcb,
1064     IN ULONG        Start,
1065     IN PULONG       Block,
1066     IN PULONG       Mapped
1067 )
1068 {
1069     LONGLONG    Vbn = 0;
1070     LONGLONG    Lbn = 0;
1071     LONGLONG    Length = 0;
1072 
1073     BOOLEAN     rc = FALSE;
1074 
1075     Vbn = ((LONGLONG) Start) << BLOCK_BITS;
1076 
1077     if (Mcb) {
1078         rc = Ext2LookupMcbExtent(Vcb, Mcb, Vbn, &Lbn, &Length);
1079     } else {
1080         rc = Ext2LookupVcbExtent(Vcb, Vbn, &Lbn, &Length);
1081     }
1082 
1083     if (rc) {
1084         *Mapped = (ULONG)(Length >> BLOCK_BITS);
1085         if (Lbn != -1 && Length > 0) {
1086             *Block = (ULONG)(Lbn >> BLOCK_BITS);
1087         } else {
1088             *Block = 0;
1089         }
1090     }
1091 
1092     return rc;
1093 }
1094 
1095 
1096 BOOLEAN
Ext2RemoveBlockExtent(IN PEXT2_VCB Vcb,IN PEXT2_MCB Mcb,IN ULONG Start,IN ULONG Number)1097 Ext2RemoveBlockExtent(
1098     IN PEXT2_VCB    Vcb,
1099     IN PEXT2_MCB    Mcb,
1100     IN ULONG        Start,
1101     IN ULONG        Number
1102 )
1103 {
1104     LONGLONG    Vbn = 0;
1105     LONGLONG    Length = 0;
1106     BOOLEAN     rc;
1107 
1108     Vbn = ((LONGLONG) Start) << BLOCK_BITS;
1109     Length = ((LONGLONG)Number << BLOCK_BITS);
1110 
1111     if (Mcb) {
1112         rc = Ext2RemoveMcbExtent(Vcb, Mcb, Vbn, Length);
1113     } else {
1114         rc = Ext2RemoveVcbExtent(Vcb, Vbn, Length);
1115     }
1116 
1117     return rc;
1118 }
1119 
1120 NTSTATUS
Ext2InitializeZone(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN PEXT2_MCB Mcb)1121 Ext2InitializeZone(
1122     IN PEXT2_IRP_CONTEXT    IrpContext,
1123     IN PEXT2_VCB            Vcb,
1124     IN PEXT2_MCB            Mcb
1125 )
1126 {
1127     NTSTATUS    Status = STATUS_SUCCESS;
1128 
1129     ULONG       Start = 0;
1130     ULONG       End;
1131     ULONG       Block;
1132     ULONG       Mapped;
1133 
1134     Ext2ClearAllExtents(&Mcb->Extents);
1135     Ext2ClearAllExtents(&Mcb->MetaExts);
1136 
1137     ASSERT(Mcb != NULL);
1138     End = (ULONG)((Mcb->Inode.i_size + BLOCK_SIZE - 1) >> BLOCK_BITS);
1139 
1140     while (Start < End) {
1141 
1142         Block = Mapped = 0;
1143 
1144         /* mapping file offset to ext2 block */
1145         if (INODE_HAS_EXTENT(&Mcb->Inode)) {
1146             Status = Ext2MapExtent(
1147                          IrpContext,
1148                          Vcb,
1149                          Mcb,
1150                          Start,
1151                          FALSE,
1152                          &Block,
1153                          &Mapped
1154                      );
1155         } else {
1156             Status = Ext2MapIndirect(
1157                          IrpContext,
1158                          Vcb,
1159                          Mcb,
1160                          Start,
1161                          FALSE,
1162                          &Block,
1163                          &Mapped
1164                      );
1165         }
1166 
1167         if (!NT_SUCCESS(Status)) {
1168             goto errorout;
1169         }
1170 
1171         /* skip wrong blocks, in case wrongly treating symlink
1172            target names as blocks, silly  */
1173         if (Block >= TOTAL_BLOCKS) {
1174             Block = 0;
1175         }
1176 
1177         if (Block) {
1178             if (!Ext2AddBlockExtent(Vcb, Mcb, Start, Block, Mapped)) {
1179                 DbgBreak();
1180                 ClearFlag(Mcb->Flags, MCB_ZONE_INITED);
1181                 Ext2ClearAllExtents(&Mcb->Extents);
1182                 Status = STATUS_INSUFFICIENT_RESOURCES;
1183                 goto errorout;
1184             }
1185             DEBUG(DL_MAP, ("Ext2InitializeZone %wZ: Block = %xh Mapped = %xh\n",
1186                            &Mcb->FullName, Block, Mapped));
1187         }
1188 
1189         /* Mapped is total number of continous blocks or NULL blocks */
1190         Start += Mapped;
1191     }
1192 
1193     /* set mcb zone as initialized */
1194     SetLongFlag(Mcb->Flags, MCB_ZONE_INITED);
1195 
1196 errorout:
1197 
1198     if (!IsZoneInited(Mcb)) {
1199         Ext2ClearAllExtents(&Mcb->Extents);
1200         Ext2ClearAllExtents(&Mcb->MetaExts);
1201     }
1202 
1203     return Status;
1204 }
1205 
1206 NTSTATUS
Ext2BuildExtents(IN PEXT2_IRP_CONTEXT IrpContext,IN PEXT2_VCB Vcb,IN PEXT2_MCB Mcb,IN ULONGLONG Offset,IN ULONG Size,IN BOOLEAN bAlloc,OUT PEXT2_EXTENT * Chain)1207 Ext2BuildExtents(
1208     IN PEXT2_IRP_CONTEXT    IrpContext,
1209     IN PEXT2_VCB            Vcb,
1210     IN PEXT2_MCB            Mcb,
1211     IN ULONGLONG            Offset,
1212     IN ULONG                Size,
1213     IN BOOLEAN              bAlloc,
1214     OUT PEXT2_EXTENT *      Chain
1215 )
1216 {
1217     ULONG       Start, End;
1218     ULONG       Total = 0;
1219 
1220     LONGLONG    Lba = 0;
1221     NTSTATUS    Status = STATUS_SUCCESS;
1222 
1223     PEXT2_EXTENT  Extent = NULL;
1224     PEXT2_EXTENT  List = *Chain = NULL;
1225 
1226     if (!IsZoneInited(Mcb)) {
1227         Status = Ext2InitializeZone(IrpContext, Vcb, Mcb);
1228         if (!NT_SUCCESS(Status)) {
1229             DbgBreak();
1230         }
1231     }
1232 
1233     if ((IrpContext && IrpContext->Irp) &&
1234             ((IrpContext->Irp->Flags & IRP_NOCACHE) ||
1235              (IrpContext->Irp->Flags & IRP_PAGING_IO))) {
1236         Size = (Size + SECTOR_SIZE - 1) & (~(SECTOR_SIZE - 1));
1237     }
1238 
1239     Start = (ULONG)(Offset >> BLOCK_BITS);
1240     End = (ULONG)((Size + Offset + BLOCK_SIZE - 1) >> BLOCK_BITS);
1241 
1242     if (End > (ULONG)((Mcb->Inode.i_size + BLOCK_SIZE - 1) >> BLOCK_BITS) ) {
1243         End = (ULONG)((Mcb->Inode.i_size + BLOCK_SIZE - 1) >> BLOCK_BITS);
1244     }
1245 
1246     while (Size > 0 && Start < End) {
1247 
1248         ULONG   Mapped = 0;
1249         ULONG   Length = 0;
1250         ULONG   Block = 0;
1251 
1252         BOOLEAN rc = FALSE;
1253 
1254         /* try to map file offset to ext2 block upon Extents cache */
1255         if (IsZoneInited(Mcb)) {
1256             rc = Ext2LookupBlockExtent(
1257                      Vcb,
1258                      Mcb,
1259                      Start,
1260                      &Block,
1261                      &Mapped);
1262 
1263             if (!rc) {
1264                 /* we likely get a sparse file here */
1265                 Mapped = 1;
1266                 Block = 0;
1267             }
1268         }
1269 
1270         /* try to BlockMap in case failed to access Extents cache */
1271         if (!IsZoneInited(Mcb) || (bAlloc && Block == 0)) {
1272 
1273             Status = Ext2BlockMap(
1274                              IrpContext,
1275                              Vcb,
1276                              Mcb,
1277                              Start,
1278                              bAlloc,
1279                              &Block,
1280                              &Mapped
1281                      );
1282             if (!NT_SUCCESS(Status)) {
1283                 break;
1284             }
1285 
1286             /* skip wrong blocks, in case wrongly treating symlink
1287                target names as blocks, silly  */
1288             if (Block >= TOTAL_BLOCKS) {
1289                 Block = 0;
1290             }
1291 
1292             /* add new allocated blocks to Mcb zone */
1293             if (IsZoneInited(Mcb) && Block) {
1294                 if (!Ext2AddBlockExtent(Vcb, Mcb, Start, Block, Mapped)) {
1295                     DbgBreak();
1296                     ClearFlag(Mcb->Flags, MCB_ZONE_INITED);
1297                     Ext2ClearAllExtents(&Mcb->Extents);
1298                 }
1299             }
1300         }
1301 
1302         /* calculate i/o extent */
1303         Lba = ((LONGLONG)Block << BLOCK_BITS) + Offset - ((LONGLONG)Start << BLOCK_BITS);
1304         Length = (ULONG)(((LONGLONG)(Start + Mapped) << BLOCK_BITS) - Offset);
1305         if (Length > Size) {
1306             Length = Size;
1307         }
1308 
1309         if (0 == Length) {
1310             DbgBreak();
1311             break;
1312         }
1313 
1314         Start += Mapped;
1315         Offset = (ULONGLONG)Start << BLOCK_BITS;
1316 
1317         if (Block != 0) {
1318 
1319             if (List && List->Lba + List->Length == Lba) {
1320 
1321                 /* it's continuous upon previous Extent */
1322                 List->Length += Length;
1323 
1324             } else {
1325 
1326                 /* have to allocate a new Extent */
1327                 Extent = Ext2AllocateExtent();
1328                 if (!Extent) {
1329                     Status = STATUS_INSUFFICIENT_RESOURCES;
1330                     DbgBreak();
1331                     break;
1332                 }
1333 
1334                 Extent->Lba = Lba;
1335                 Extent->Length = Length;
1336                 Extent->Offset = Total;
1337 
1338                 /* insert new Extent to chain */
1339                 if (List) {
1340                     List->Next = Extent;
1341                     List = Extent;
1342                 } else {
1343                     *Chain = List = Extent;
1344                 }
1345             }
1346         } else {
1347             if (bAlloc) {
1348                 DbgBreak();
1349             }
1350         }
1351 
1352         Total += Length;
1353         Size  -= Length;
1354     }
1355 
1356     return Status;
1357 }
1358 
1359 
1360 BOOLEAN
Ext2BuildName(IN OUT PUNICODE_STRING Target,IN PUNICODE_STRING File,IN PUNICODE_STRING Parent)1361 Ext2BuildName(
1362     IN OUT PUNICODE_STRING  Target,
1363     IN PUNICODE_STRING      File,
1364     IN PUNICODE_STRING      Parent
1365 )
1366 {
1367     USHORT  Length = 0;
1368     USHORT  ParentLen = 0;
1369     BOOLEAN bBackslash = TRUE;
1370 
1371     /* free the original buffer */
1372     if (Target->Buffer) {
1373         DEC_MEM_COUNT(PS_MCB_NAME, Target->Buffer, Target->MaximumLength);
1374         Ext2FreePool(Target->Buffer, EXT2_FNAME_MAGIC);
1375         Target->Length = Target->MaximumLength = 0;
1376     }
1377 
1378     /* check the parent directory's name and backslash */
1379     if (Parent && Parent->Buffer && Parent->Length > 0) {
1380         ParentLen = Parent->Length / sizeof(WCHAR);
1381         if (Parent->Buffer[ParentLen - 1] == L'\\') {
1382             bBackslash = FALSE;
1383         }
1384     }
1385 
1386     if (Parent == NULL || File->Buffer[0] == L'\\') {
1387         /* must be root inode */
1388         ASSERT(ParentLen == 0);
1389         bBackslash = FALSE;
1390     }
1391 
1392     /* allocate and initialize new name buffer */
1393     Length  = File->Length;
1394     Length += (ParentLen + (bBackslash ? 1 : 0)) * sizeof(WCHAR);
1395 
1396     Target->Buffer = Ext2AllocatePool(
1397                          PagedPool,
1398                          Length + 2,
1399                          EXT2_FNAME_MAGIC
1400                      );
1401 
1402     if (!Target->Buffer) {
1403         DEBUG(DL_ERR, ( "Ex2BuildName: failed to allocate name bufer.\n"));
1404         return FALSE;
1405     }
1406     RtlZeroMemory(Target->Buffer, Length + 2);
1407 
1408     if (ParentLen) {
1409         RtlCopyMemory(&Target->Buffer[0],
1410                       Parent->Buffer,
1411                       ParentLen * sizeof(WCHAR));
1412     }
1413 
1414     if (bBackslash) {
1415         Target->Buffer[ParentLen++] = L'\\';
1416     }
1417 
1418     RtlCopyMemory( &Target->Buffer[ParentLen],
1419                    File->Buffer,
1420                    File->Length);
1421 
1422     INC_MEM_COUNT(PS_MCB_NAME, Target->Buffer, Length + 2);
1423     Target->Length = Length;
1424     Target->MaximumLength = Length + 2;
1425 
1426     return TRUE;
1427 }
1428 
1429 PEXT2_MCB
Ext2AllocateMcb(IN PEXT2_VCB Vcb,IN PUNICODE_STRING FileName,IN PUNICODE_STRING Parent,IN ULONG FileAttr)1430 Ext2AllocateMcb (
1431     IN PEXT2_VCB        Vcb,
1432     IN PUNICODE_STRING  FileName,
1433     IN PUNICODE_STRING  Parent,
1434     IN ULONG            FileAttr
1435 )
1436 {
1437     PEXT2_MCB   Mcb = NULL;
1438     NTSTATUS    Status = STATUS_SUCCESS;
1439 
1440     /* need wake the reaper thread if there are many Mcb allocated */
1441     if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 4)) {
1442         KeSetEvent(&Ext2Global->McbReaper.Wait, 0, FALSE);
1443     }
1444 
1445     /* allocate Mcb from LookasideList */
1446     Mcb = (PEXT2_MCB) (ExAllocateFromNPagedLookasideList(
1447                            &(Ext2Global->Ext2McbLookasideList)));
1448 
1449     if (Mcb == NULL) {
1450         return NULL;
1451     }
1452 
1453     /* initialize Mcb header */
1454     RtlZeroMemory(Mcb, sizeof(EXT2_MCB));
1455     Mcb->Identifier.Type = EXT2MCB;
1456     Mcb->Identifier.Size = sizeof(EXT2_MCB);
1457     Mcb->FileAttr = FileAttr;
1458 
1459     Mcb->Inode.i_priv = (PVOID)Mcb;
1460     Mcb->Inode.i_sb = &Vcb->sb;
1461 
1462     /* initialize Mcb names */
1463     if (FileName) {
1464 
1465 #if EXT2_DEBUG
1466         if ( FileName->Length == 2 &&
1467                 FileName->Buffer[0] == L'\\') {
1468             DEBUG(DL_RES, ( "Ext2AllocateMcb: Root Mcb is to be created !\n"));
1469         }
1470 
1471         if ( FileName->Length == 2 &&
1472                 FileName->Buffer[0] == L'.') {
1473             DbgBreak();
1474         }
1475 
1476         if ( FileName->Length == 4 &&
1477                 FileName->Buffer[0] == L'.' &&
1478                 FileName->Buffer[1] == L'.' ) {
1479             DbgBreak();
1480         }
1481 #endif
1482 
1483         if (( FileName->Length >= 4 && FileName->Buffer[0] == L'.') &&
1484                 ((FileName->Length == 4 && FileName->Buffer[1] != L'.') ||
1485                  FileName->Length >= 6 )) {
1486             SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_HIDDEN);
1487         }
1488 
1489         if (!Ext2BuildName(&Mcb->ShortName, FileName, NULL)) {
1490             goto errorout;
1491         }
1492         if (!Ext2BuildName(&Mcb->FullName, FileName, Parent)) {
1493             goto errorout;
1494         }
1495     }
1496 
1497     /* initialize Mcb Extents, it will raise an expcetion if failed */
1498     _SEH2_TRY {
1499         FsRtlInitializeLargeMcb(&(Mcb->Extents), NonPagedPool);
1500         FsRtlInitializeLargeMcb(&(Mcb->MetaExts), NonPagedPool);
1501     } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
1502         Status = STATUS_INSUFFICIENT_RESOURCES;
1503         DbgBreak();
1504     } _SEH2_END;
1505 
1506     if (!NT_SUCCESS(Status)) {
1507         goto errorout;
1508     }
1509 
1510     INC_MEM_COUNT(PS_MCB, Mcb, sizeof(EXT2_MCB));
1511     DEBUG(DL_INF, ( "Ext2AllocateMcb: Mcb %wZ created.\n", &Mcb->FullName));
1512 
1513     return Mcb;
1514 
1515 errorout:
1516 
1517     if (Mcb) {
1518 
1519         if (Mcb->ShortName.Buffer) {
1520             DEC_MEM_COUNT(PS_MCB_NAME, Mcb->ShortName.Buffer,
1521                           Mcb->ShortName.MaximumLength);
1522             Ext2FreePool(Mcb->ShortName.Buffer, EXT2_FNAME_MAGIC);
1523         }
1524 
1525         if (Mcb->FullName.Buffer) {
1526             DEC_MEM_COUNT(PS_MCB_NAME, Mcb->FullName.Buffer,
1527                           Mcb->FullName.MaximumLength);
1528             Ext2FreePool(Mcb->FullName.Buffer, EXT2_FNAME_MAGIC);
1529         }
1530 
1531         ExFreeToNPagedLookasideList(&(Ext2Global->Ext2McbLookasideList), Mcb);
1532     }
1533 
1534     return NULL;
1535 }
1536 
1537 VOID
Ext2FreeMcb(IN PEXT2_VCB Vcb,IN PEXT2_MCB Mcb)1538 Ext2FreeMcb (IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb)
1539 {
1540 #ifndef __REACTOS__
1541     PEXT2_MCB   Parent = Mcb->Parent;
1542 #endif
1543 
1544     ASSERT(Mcb != NULL);
1545 
1546     ASSERT((Mcb->Identifier.Type == EXT2MCB) &&
1547            (Mcb->Identifier.Size == sizeof(EXT2_MCB)));
1548 
1549     if ((Mcb->Identifier.Type != EXT2MCB) ||
1550             (Mcb->Identifier.Size != sizeof(EXT2_MCB))) {
1551         return;
1552     }
1553 
1554     DEBUG(DL_INF, ( "Ext2FreeMcb: Mcb %wZ will be freed.\n", &Mcb->FullName));
1555 
1556     if (IsMcbSymLink(Mcb) && Mcb->Target) {
1557         Ext2DerefMcb(Mcb->Target);
1558     }
1559 
1560     if (FsRtlNumberOfRunsInLargeMcb(&Mcb->Extents)) {
1561         DEBUG(DL_EXT, ("List data extents for: %wZ\n", &Mcb->FullName));
1562         Ext2ListExtents(&Mcb->Extents);
1563     }
1564     FsRtlUninitializeLargeMcb(&(Mcb->Extents));
1565     if (FsRtlNumberOfRunsInLargeMcb(&Mcb->MetaExts)) {
1566         DEBUG(DL_EXT, ("List meta extents for: %wZ\n", &Mcb->FullName));
1567         Ext2ListExtents(&Mcb->MetaExts);
1568     }
1569     FsRtlUninitializeLargeMcb(&(Mcb->MetaExts));
1570     ClearLongFlag(Mcb->Flags, MCB_ZONE_INITED);
1571 
1572     if (Mcb->ShortName.Buffer) {
1573         DEC_MEM_COUNT(PS_MCB_NAME, Mcb->ShortName.Buffer,
1574                       Mcb->ShortName.MaximumLength);
1575         Ext2FreePool(Mcb->ShortName.Buffer, EXT2_FNAME_MAGIC);
1576     }
1577 
1578     if (Mcb->FullName.Buffer) {
1579         DEC_MEM_COUNT(PS_MCB_NAME, Mcb->FullName.Buffer,
1580                       Mcb->FullName.MaximumLength);
1581         Ext2FreePool(Mcb->FullName.Buffer, EXT2_FNAME_MAGIC);
1582     }
1583 
1584     /* free dentry */
1585     if (Mcb->de) {
1586         Ext2FreeEntry(Mcb->de);
1587     }
1588 
1589     Mcb->Identifier.Type = 0;
1590     Mcb->Identifier.Size = 0;
1591 
1592     ExFreeToNPagedLookasideList(&(Ext2Global->Ext2McbLookasideList), Mcb);
1593     DEC_MEM_COUNT(PS_MCB, Mcb, sizeof(EXT2_MCB));
1594 }
1595 
1596 
1597 PEXT2_MCB
Ext2SearchMcb(PEXT2_VCB Vcb,PEXT2_MCB Parent,PUNICODE_STRING FileName)1598 Ext2SearchMcb(
1599     PEXT2_VCB           Vcb,
1600     PEXT2_MCB           Parent,
1601     PUNICODE_STRING     FileName
1602 )
1603 {
1604     BOOLEAN   LockAcquired = FALSE;
1605     PEXT2_MCB Mcb = NULL;
1606 
1607     _SEH2_TRY {
1608         ExAcquireResourceSharedLite(&Vcb->McbLock, TRUE);
1609         LockAcquired = TRUE;
1610         Mcb = Ext2SearchMcbWithoutLock(Parent, FileName);
1611     } _SEH2_FINALLY {
1612         if (LockAcquired) {
1613             ExReleaseResourceLite(&Vcb->McbLock);
1614         }
1615     } _SEH2_END;
1616 
1617     return Mcb;
1618 }
1619 
1620 
1621 PEXT2_MCB
Ext2SearchMcbWithoutLock(PEXT2_MCB Parent,PUNICODE_STRING FileName)1622 Ext2SearchMcbWithoutLock(
1623     PEXT2_MCB       Parent,
1624     PUNICODE_STRING FileName
1625 )
1626 {
1627     PEXT2_MCB TmpMcb = NULL;
1628 
1629     DEBUG(DL_RES, ("Ext2SearchMcb: %wZ\n", FileName));
1630 
1631     _SEH2_TRY {
1632 
1633         Ext2ReferMcb(Parent);
1634 
1635         if (Ext2IsDot(FileName)) {
1636             TmpMcb = Parent;
1637             Ext2ReferMcb(Parent);
1638             _SEH2_LEAVE;
1639         }
1640 
1641         if (Ext2IsDotDot(FileName)) {
1642             if (IsMcbRoot(Parent)) {
1643                 TmpMcb = Parent;
1644             } else {
1645                 TmpMcb = Parent->Parent;
1646             }
1647             if (TmpMcb) {
1648                 Ext2ReferMcb(TmpMcb);
1649             }
1650             _SEH2_LEAVE;
1651         }
1652 
1653         if (IsMcbSymLink(Parent)) {
1654             if (Parent->Target) {
1655                 TmpMcb = Parent->Target->Child;
1656                 ASSERT(!IsMcbSymLink(Parent->Target));
1657             } else {
1658                 TmpMcb = NULL;
1659                 _SEH2_LEAVE;
1660             }
1661         } else {
1662             TmpMcb = Parent->Child;
1663         }
1664 
1665         while (TmpMcb) {
1666 
1667             if (!RtlCompareUnicodeString(
1668                         &(TmpMcb->ShortName),
1669                         FileName, TRUE )) {
1670                 Ext2ReferMcb(TmpMcb);
1671                 break;
1672             }
1673 
1674             TmpMcb = TmpMcb->Next;
1675         }
1676 
1677     } _SEH2_FINALLY {
1678 
1679         Ext2DerefMcb(Parent);
1680     } _SEH2_END;
1681 
1682     return TmpMcb;
1683 }
1684 
1685 VOID
Ext2InsertMcb(PEXT2_VCB Vcb,PEXT2_MCB Parent,PEXT2_MCB Child)1686 Ext2InsertMcb (
1687     PEXT2_VCB Vcb,
1688     PEXT2_MCB Parent,
1689     PEXT2_MCB Child
1690 )
1691 {
1692     BOOLEAN     LockAcquired = FALSE;
1693     PEXT2_MCB   Mcb = NULL;
1694 
1695     _SEH2_TRY {
1696 
1697         ExAcquireResourceExclusiveLite(
1698             &Vcb->McbLock,
1699             TRUE );
1700         LockAcquired = TRUE;
1701 
1702         /* use it's target if it's a symlink */
1703         if (IsMcbSymLink(Parent)) {
1704             Parent = Parent->Target;
1705             ASSERT(!IsMcbSymLink(Parent));
1706         }
1707 
1708         Mcb = Parent->Child;
1709         while (Mcb) {
1710             if (Mcb == Child) {
1711                 break;
1712             }
1713             Mcb = Mcb->Next;
1714         }
1715 
1716         if (Mcb) {
1717             /* already attached in the list */
1718             DEBUG(DL_ERR, ( "Ext2InsertMcb: Child Mcb is alreay attached.\n"));
1719             if (!IsFlagOn(Mcb->Flags, MCB_ENTRY_TREE)) {
1720                 SetLongFlag(Child->Flags, MCB_ENTRY_TREE);
1721                 DEBUG(DL_ERR, ( "Ext2InsertMcb: Child Mcb's flag isn't set.\n"));
1722             }
1723 
1724             DbgBreak();
1725 
1726         } else {
1727 
1728             /* insert this Mcb into the head */
1729             Child->Next = Parent->Child;
1730             Parent->Child = Child;
1731             Child->Parent = Parent;
1732             Child->de->d_parent = Parent->de;
1733             Ext2ReferMcb(Parent);
1734             SetLongFlag(Child->Flags, MCB_ENTRY_TREE);
1735         }
1736 
1737     } _SEH2_FINALLY {
1738 
1739         if (LockAcquired) {
1740             ExReleaseResourceLite(&Vcb->McbLock);
1741         }
1742     } _SEH2_END;
1743 }
1744 
1745 BOOLEAN
Ext2RemoveMcb(PEXT2_VCB Vcb,PEXT2_MCB Mcb)1746 Ext2RemoveMcb (
1747     PEXT2_VCB Vcb,
1748     PEXT2_MCB Mcb
1749 )
1750 {
1751     PEXT2_MCB   TmpMcb = NULL;
1752     BOOLEAN     LockAcquired = FALSE;
1753     BOOLEAN     bLinked = FALSE;
1754 
1755     _SEH2_TRY {
1756 
1757         ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
1758         LockAcquired = TRUE;
1759 
1760         if (Mcb->Parent) {
1761 
1762             if (Mcb->Parent->Child == Mcb) {
1763                 Mcb->Parent->Child = Mcb->Next;
1764                 bLinked = TRUE;
1765             } else {
1766                 TmpMcb = Mcb->Parent->Child;
1767 
1768                 while (TmpMcb && TmpMcb->Next != Mcb) {
1769                     TmpMcb = TmpMcb->Next;
1770                 }
1771 
1772                 if (TmpMcb) {
1773                     TmpMcb->Next = Mcb->Next;
1774                     bLinked = TRUE;
1775                 } else {
1776                     /* we got errors: link broken */
1777                 }
1778             }
1779 
1780             if (bLinked) {
1781                 if (IsFlagOn(Mcb->Flags, MCB_ENTRY_TREE)) {
1782                     DEBUG(DL_RES, ("Mcb %p %wZ removed from Mcb %p %wZ\n", Mcb,
1783                                    &Mcb->FullName, Mcb->Parent, &Mcb->Parent->FullName));
1784                     Ext2DerefMcb(Mcb->Parent);
1785                     ClearLongFlag(Mcb->Flags, MCB_ENTRY_TREE);
1786                 } else {
1787                     DbgBreak();
1788                 }
1789             } else {
1790                 if (IsFlagOn(Mcb->Flags, MCB_ENTRY_TREE)) {
1791                     ClearLongFlag(Mcb->Flags, MCB_ENTRY_TREE);
1792                 }
1793                 DbgBreak();
1794             }
1795             Mcb->Parent = NULL;
1796             Mcb->de->d_parent = NULL;
1797         }
1798 
1799     } _SEH2_FINALLY {
1800 
1801         if (LockAcquired) {
1802             ExReleaseResourceLite(&Vcb->McbLock);
1803         }
1804     } _SEH2_END;
1805 
1806     return TRUE;
1807 }
1808 
1809 VOID
Ext2CleanupAllMcbs(PEXT2_VCB Vcb)1810 Ext2CleanupAllMcbs(PEXT2_VCB Vcb)
1811 {
1812     BOOLEAN   LockAcquired = FALSE;
1813     PEXT2_MCB Mcb = NULL;
1814 
1815     _SEH2_TRY {
1816 
1817         ExAcquireResourceExclusiveLite(
1818             &Vcb->McbLock,
1819             TRUE );
1820         LockAcquired = TRUE;
1821 
1822 #ifdef __REACTOS__
1823         while ((Mcb = Ext2FirstUnusedMcb(Vcb, TRUE, Vcb->NumOfMcb)) != 0) {
1824 #else
1825         while (Mcb = Ext2FirstUnusedMcb(Vcb, TRUE, Vcb->NumOfMcb)) {
1826 #endif
1827             while (Mcb) {
1828                 PEXT2_MCB Next = Mcb->Next;
1829                 if (IsMcbSymLink(Mcb)) {
1830                     Mcb->Target = NULL;
1831                 }
1832                 Ext2FreeMcb(Vcb, Mcb);
1833                 Mcb = Next;
1834             }
1835         }
1836         Ext2FreeMcb(Vcb, Vcb->McbTree);
1837         Vcb->McbTree = NULL;
1838 
1839     } _SEH2_FINALLY {
1840 
1841         if (LockAcquired) {
1842             ExReleaseResourceLite(&Vcb->McbLock);
1843         }
1844     } _SEH2_END;
1845 }
1846 
1847 BOOLEAN
1848 Ext2CheckSetBlock(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb, LONGLONG Block)
1849 {
1850     PEXT2_GROUP_DESC    gd;
1851     struct buffer_head *gb = NULL;
1852     struct buffer_head *bh = NULL;
1853     ULONG               group, dwBlk, Length;
1854     RTL_BITMAP          bitmap;
1855     BOOLEAN             bModified = FALSE;
1856 
1857     group = (ULONG)(Block - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
1858     dwBlk = (ULONG)(Block - EXT2_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
1859 
1860     gd = ext4_get_group_desc(&Vcb->sb, group, &gb);
1861     if (!gd) {
1862         return FALSE;
1863     }
1864     bh = sb_getblk(&Vcb->sb, ext4_block_bitmap(&Vcb->sb, gd));
1865 
1866     if (group == Vcb->sbi.s_groups_count - 1) {
1867         Length = (ULONG)(TOTAL_BLOCKS % BLOCKS_PER_GROUP);
1868 
1869         /* s_blocks_count is integer multiple of s_blocks_per_group */
1870         if (Length == 0)
1871             Length = BLOCKS_PER_GROUP;
1872     } else {
1873         Length = BLOCKS_PER_GROUP;
1874     }
1875 
1876     if (dwBlk >= Length) {
1877         fini_bh(&gb);
1878         fini_bh(&bh);
1879         return FALSE;
1880     }
1881 
1882 
1883     RtlInitializeBitMap(&bitmap, (PULONG)bh->b_data, Length);
1884 
1885     if (RtlCheckBit(&bitmap, dwBlk) == 0) {
1886         DbgBreak();
1887         RtlSetBits(&bitmap, dwBlk, 1);
1888         bModified = TRUE;
1889         mark_buffer_dirty(bh);
1890     }
1891 
1892     fini_bh(&gb);
1893     fini_bh(&bh);
1894 
1895     return (!bModified);
1896 }
1897 
1898 BOOLEAN
1899 Ext2CheckBitmapConsistency(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb)
1900 {
1901     ULONG i, j, InodeBlocks;
1902 
1903     for (i = 0; i < Vcb->sbi.s_groups_count; i++) {
1904 
1905         PEXT2_GROUP_DESC    gd;
1906         struct buffer_head  *bh = NULL;
1907 
1908         gd = ext4_get_group_desc(&Vcb->sb, i, &bh);
1909         if (!gd)
1910             continue;
1911         Ext2CheckSetBlock(IrpContext, Vcb, ext4_block_bitmap(&Vcb->sb, gd));
1912         Ext2CheckSetBlock(IrpContext, Vcb, ext4_inode_bitmap(&Vcb->sb, gd));
1913 
1914 
1915         if (i == Vcb->sbi.s_groups_count - 1) {
1916             InodeBlocks = ((INODES_COUNT % INODES_PER_GROUP) *
1917                            Vcb->InodeSize + Vcb->BlockSize - 1) /
1918                           (Vcb->BlockSize);
1919         } else {
1920             InodeBlocks = (INODES_PER_GROUP * Vcb->InodeSize +
1921                            Vcb->BlockSize - 1) / (Vcb->BlockSize);
1922         }
1923 
1924         for (j = 0; j < InodeBlocks; j++ )
1925             Ext2CheckSetBlock(IrpContext, Vcb, ext4_inode_table(&Vcb->sb, gd) + j);
1926 
1927         fini_bh(&bh);
1928     }
1929 
1930     return TRUE;
1931 }
1932 
1933 /* Ext2Global->Resource should be already acquired */
1934 VOID
1935 Ext2InsertVcb(PEXT2_VCB Vcb)
1936 {
1937     InsertTailList(&(Ext2Global->VcbList), &Vcb->Next);
1938 }
1939 
1940 
1941 /* Ext2Global->Resource should be already acquired */
1942 VOID
1943 Ext2RemoveVcb(PEXT2_VCB Vcb)
1944 {
1945     RemoveEntryList(&Vcb->Next);
1946     InitializeListHead(&Vcb->Next);
1947 }
1948 
1949 NTSTATUS
1950 Ext2QueryVolumeParams(IN PEXT2_VCB Vcb, IN PUNICODE_STRING Params)
1951 {
1952     NTSTATUS                    Status;
1953     RTL_QUERY_REGISTRY_TABLE    QueryTable[2];
1954 
1955     UNICODE_STRING              UniName;
1956     PUSHORT                     UniBuffer = NULL;
1957 
1958     USHORT                      UUID[50];
1959 
1960     int                         i;
1961     int                         len = 0;
1962 
1963     /* zero params */
1964     RtlZeroMemory(Params, sizeof(UNICODE_STRING));
1965 
1966     /* constructing volume UUID name */
1967     memset(UUID, 0, sizeof(USHORT) * 50);
1968     for (i=0; i < 16; i++) {
1969         if (i == 0) {
1970             swprintf((wchar_t *)&UUID[len], L"{%2.2X",Vcb->SuperBlock->s_uuid[i]);
1971             len += 3;
1972         } else if (i == 15) {
1973             swprintf((wchar_t *)&UUID[len], L"-%2.2X}", Vcb->SuperBlock->s_uuid[i]);
1974             len +=4;
1975         } else {
1976             swprintf((wchar_t *)&UUID[len], L"-%2.2X", Vcb->SuperBlock->s_uuid[i]);
1977             len += 3;
1978         }
1979     }
1980 
1981     /* allocating memory for UniBuffer */
1982     UniBuffer = Ext2AllocatePool(PagedPool, 1024, EXT2_PARAM_MAGIC);
1983     if (NULL == UniBuffer) {
1984         Status = STATUS_INSUFFICIENT_RESOURCES;
1985         goto errorout;
1986     }
1987     RtlZeroMemory(UniBuffer, 1024);
1988 
1989     /* querying volume parameter string */
1990     RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2);
1991     QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
1992     QueryTable[0].Name = UUID;
1993     QueryTable[0].EntryContext = &(UniName);
1994     UniName.MaximumLength = 1024;
1995     UniName.Length = 0;
1996     UniName.Buffer = UniBuffer;
1997 
1998     Status = RtlQueryRegistryValues(
1999                  RTL_REGISTRY_ABSOLUTE,
2000                  Ext2Global->RegistryPath.Buffer,
2001                  &QueryTable[0],
2002                  NULL,
2003                  NULL
2004              );
2005 
2006     if (!NT_SUCCESS(Status)) {
2007         goto errorout;
2008     }
2009 
2010 errorout:
2011 
2012     if (NT_SUCCESS(Status)) {
2013         *Params = UniName;
2014     } else {
2015         if (UniBuffer) {
2016             Ext2FreePool(UniBuffer, EXT2_PARAM_MAGIC);
2017         }
2018     }
2019 
2020     return Status;
2021 }
2022 
2023 VOID
2024 Ext2ParseRegistryVolumeParams(
2025     IN  PUNICODE_STRING         Params,
2026     OUT PEXT2_VOLUME_PROPERTY3  Property
2027 )
2028 {
2029     WCHAR       Codepage[CODEPAGE_MAXLEN];
2030     WCHAR       Prefix[HIDINGPAT_LEN];
2031     WCHAR       Suffix[HIDINGPAT_LEN];
2032     USHORT      MountPoint[4];
2033     UCHAR       DrvLetter[4];
2034     WCHAR       wUID[8], wGID[8], wEUID[8], wEGID[8];
2035     CHAR        sUID[8], sGID[8], sEUID[8], sEGID[8];
2036 
2037     BOOLEAN     bWriteSupport = FALSE,
2038                 bCheckBitmap = FALSE,
2039                 bCodeName = FALSE,
2040                 bMountPoint = FALSE;
2041     BOOLEAN     bUID = 0, bGID = 0, bEUID = 0, bEGID = 0;
2042 
2043     struct {
2044         PWCHAR   Name;      /* parameters name */
2045         PBOOLEAN bExist;    /* is it contained in params */
2046         USHORT   Length;    /* parameter value length */
2047         PWCHAR   uValue;    /* value buffer in unicode */
2048         PCHAR    aValue;    /* value buffer in ansi */
2049     } ParamPattern[] = {
2050         /* writing support */
2051         {READING_ONLY, &Property->bReadonly, 0, NULL, NULL},
2052         {WRITING_SUPPORT, &bWriteSupport, 0, NULL, NULL},
2053         {EXT3_FORCEWRITING, &Property->bExt3Writable, 0, NULL, NULL},
2054 
2055         /* need check bitmap */
2056         {CHECKING_BITMAP, &bCheckBitmap, 0, NULL, NULL},
2057         /* codepage */
2058         {CODEPAGE_NAME, &bCodeName, CODEPAGE_MAXLEN,
2059          &Codepage[0], Property->Codepage},
2060         /* filter prefix and suffix */
2061         {HIDING_PREFIX, &Property->bHidingPrefix, HIDINGPAT_LEN,
2062          &Prefix[0], Property->sHidingPrefix},
2063         {HIDING_SUFFIX, &Property->bHidingSuffix, HIDINGPAT_LEN,
2064          &Suffix[0], Property->sHidingSuffix},
2065         {MOUNT_POINT, &bMountPoint, 4,
2066          &MountPoint[0], &DrvLetter[0]},
2067 
2068         {UID,  &bUID,  8, &wUID[0],  &sUID[0],},
2069         {GID,  &bGID,  8, &wGID[0],  &sGID[0]},
2070         {EUID, &bEUID, 8, &wEUID[0], &sEUID[0]},
2071         {EGID, &bEGID, 8, &wEGID[0], &sEGID[0]},
2072 
2073         /* end */
2074         {NULL, NULL, 0, NULL}
2075     };
2076 
2077     USHORT i, j, k;
2078 
2079 #ifdef __REACTOS__
2080     RtlZeroMemory(Codepage, sizeof(WCHAR) * CODEPAGE_MAXLEN);
2081     RtlZeroMemory(Prefix, sizeof(WCHAR) * HIDINGPAT_LEN);
2082     RtlZeroMemory(Suffix, sizeof(WCHAR) * HIDINGPAT_LEN);
2083 #else
2084     RtlZeroMemory(Codepage, CODEPAGE_MAXLEN);
2085     RtlZeroMemory(Prefix, HIDINGPAT_LEN);
2086     RtlZeroMemory(Suffix, HIDINGPAT_LEN);
2087 #endif
2088     RtlZeroMemory(MountPoint, sizeof(USHORT) * 4);
2089     RtlZeroMemory(DrvLetter, sizeof(CHAR) * 4);
2090 
2091     RtlZeroMemory(Property, sizeof(EXT2_VOLUME_PROPERTY3));
2092     Property->Magic = EXT2_VOLUME_PROPERTY_MAGIC;
2093     Property->Command = APP_CMD_SET_PROPERTY3;
2094 
2095     for (i=0; ParamPattern[i].Name != NULL; i++) {
2096 
2097         UNICODE_STRING  Name1=*Params, Name2;
2098         RtlInitUnicodeString(&Name2, ParamPattern[i].Name);
2099         *ParamPattern[i].bExist = FALSE;
2100 
2101         for (j=0; j * sizeof(WCHAR) + Name2.Length <= Params->Length ; j++) {
2102 
2103             Name1.MaximumLength = Params->Length - j * sizeof(WCHAR);
2104             Name1.Length = Name2.Length;
2105             Name1.Buffer = &Params->Buffer[j];
2106 
2107             if (!RtlCompareUnicodeString(&Name1, &Name2, TRUE)) {
2108                 if (j * sizeof(WCHAR) + Name2.Length == Params->Length ||
2109                         Name1.Buffer[Name2.Length/sizeof(WCHAR)] == L';' ||
2110                         Name1.Buffer[Name2.Length/sizeof(WCHAR)] == L','  ) {
2111                     *(ParamPattern[i].bExist) = TRUE;
2112                 } else if ((j * 2 + Name2.Length < Params->Length + 2) ||
2113                            (Name1.Buffer[Name2.Length/sizeof(WCHAR)] == L'=' )) {
2114                     j += Name2.Length/sizeof(WCHAR) + 1;
2115                     k = 0;
2116                     while ( j + k < Params->Length/2 &&
2117                             k < ParamPattern[i].Length &&
2118                             Params->Buffer[j+k] != L';' &&
2119                             Params->Buffer[j+k] != L',' ) {
2120 #ifdef __REACTOS__
2121                         ParamPattern[i].uValue[k] = Params->Buffer[j + k];
2122                         k++;
2123 #else
2124                         ParamPattern[i].uValue[k] = Params->Buffer[j + k++];
2125 #endif
2126                     }
2127                     if (k) {
2128                         NTSTATUS status;
2129                         ANSI_STRING AnsiName;
2130                         AnsiName.Length = 0;
2131                         AnsiName.MaximumLength =ParamPattern[i].Length;
2132                         AnsiName.Buffer = ParamPattern[i].aValue;
2133 
2134                         Name2.Buffer = ParamPattern[i].uValue;
2135                         Name2.MaximumLength = Name2.Length = k * sizeof(WCHAR);
2136                         status = RtlUnicodeStringToAnsiString(
2137                                      &AnsiName, &Name2, FALSE);
2138                         if (NT_SUCCESS(status)) {
2139                             *(ParamPattern[i].bExist) = TRUE;
2140                         } else {
2141                             *ParamPattern[i].bExist = FALSE;
2142                         }
2143                     }
2144                 }
2145                 break;
2146             }
2147         }
2148     }
2149 
2150     if (bMountPoint) {
2151         Property->DrvLetter = DrvLetter[0];
2152         Property->DrvLetter |= 0x80;
2153     }
2154 
2155     if (bUID && bGID) {
2156         SetFlag(Property->Flags2, EXT2_VPROP3_USERIDS);
2157         sUID[7] = sGID[7] = sEUID[7] = sEGID[7] = 0;
2158         Property->uid = (USHORT)atoi(sUID);
2159         Property->gid = (USHORT)atoi(sGID);
2160         if (bEUID) {
2161             Property->euid = (USHORT)atoi(sEUID);
2162             Property->egid = (USHORT)atoi(sEGID);
2163             Property->EIDS = TRUE;
2164         } else {
2165             Property->EIDS = FALSE;
2166         }
2167     } else {
2168         ClearFlag(Property->Flags2, EXT2_VPROP3_USERIDS);
2169     }
2170 }
2171 
2172 NTSTATUS
2173 Ext2PerformRegistryVolumeParams(IN PEXT2_VCB Vcb)
2174 {
2175     NTSTATUS        Status;
2176     UNICODE_STRING  VolumeParams;
2177 
2178     Status = Ext2QueryVolumeParams(Vcb, &VolumeParams);
2179     if (NT_SUCCESS(Status)) {
2180 
2181         /* set Vcb settings from registery */
2182         EXT2_VOLUME_PROPERTY3  Property;
2183         Ext2ParseRegistryVolumeParams(&VolumeParams, &Property);
2184         Ext2ProcessVolumeProperty(Vcb, &Property, sizeof(Property));
2185 
2186     } else {
2187 
2188         /* don't support auto mount */
2189         if (IsFlagOn(Ext2Global->Flags, EXT2_AUTO_MOUNT)) {
2190             Status = STATUS_SUCCESS;
2191         } else {
2192             Status = STATUS_UNSUCCESSFUL;
2193             goto errorout;
2194         }
2195 
2196         /* set Vcb settings from Ext2Global */
2197         if (IsFlagOn(Ext2Global->Flags, EXT2_SUPPORT_WRITING)) {
2198             if (Vcb->IsExt3fs) {
2199                 if (IsFlagOn(Ext2Global->Flags, EXT3_FORCE_WRITING)) {
2200                     ClearLongFlag(Vcb->Flags, VCB_READ_ONLY);
2201                 } else {
2202                     SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
2203                 }
2204             } else {
2205                 ClearLongFlag(Vcb->Flags, VCB_READ_ONLY);
2206             }
2207         } else {
2208             SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
2209         }
2210 
2211         /* set the default codepage */
2212         Vcb->Codepage.PageTable = Ext2Global->Codepage.PageTable;
2213         memcpy(Vcb->Codepage.AnsiName, Ext2Global->Codepage.AnsiName, CODEPAGE_MAXLEN);
2214         Vcb->Codepage.PageTable = Ext2Global->Codepage.PageTable;
2215 
2216 #ifdef __REACTOS__
2217         if (Vcb->bHidingPrefix == Ext2Global->bHidingPrefix) {
2218 #else
2219         if (Vcb->bHidingPrefix = Ext2Global->bHidingPrefix) {
2220 #endif
2221             RtlCopyMemory( Vcb->sHidingPrefix,
2222                            Ext2Global->sHidingPrefix,
2223                            HIDINGPAT_LEN);
2224         } else {
2225             RtlZeroMemory( Vcb->sHidingPrefix,
2226                            HIDINGPAT_LEN);
2227         }
2228 
2229 #ifdef __REACTOS__
2230         if (Vcb->bHidingSuffix == Ext2Global->bHidingSuffix) {
2231 #else
2232         if (Vcb->bHidingSuffix = Ext2Global->bHidingSuffix) {
2233 #endif
2234             RtlCopyMemory( Vcb->sHidingSuffix,
2235                            Ext2Global->sHidingSuffix,
2236                            HIDINGPAT_LEN);
2237         } else {
2238             RtlZeroMemory( Vcb->sHidingSuffix,
2239                            HIDINGPAT_LEN);
2240         }
2241     }
2242 
2243 errorout:
2244 
2245     if (VolumeParams.Buffer) {
2246         Ext2FreePool(VolumeParams.Buffer, EXT2_PARAM_MAGIC);
2247     }
2248 
2249     return Status;
2250 }
2251 
2252 NTSTATUS
2253 Ext2InitializeLabel(
2254     IN PEXT2_VCB            Vcb,
2255     IN PEXT2_SUPER_BLOCK    Sb
2256 )
2257 {
2258     NTSTATUS            status;
2259 
2260     USHORT              Length;
2261     UNICODE_STRING      Label;
2262     OEM_STRING          OemName;
2263 
2264     Label.MaximumLength = 16 * sizeof(WCHAR);
2265     Label.Length    = 0;
2266     Label.Buffer    = Vcb->Vpb->VolumeLabel;
2267     Vcb->Vpb->VolumeLabelLength = 0;
2268     RtlZeroMemory(Label.Buffer, Label.MaximumLength);
2269 
2270     Length = 16;
2271     while (  (Length > 0) &&
2272              ((Sb->s_volume_name[Length -1]  == 0x00) ||
2273               (Sb->s_volume_name[Length - 1] == 0x20)  )
2274           ) {
2275         Length--;
2276     }
2277 
2278     if (Length == 0) {
2279         return STATUS_SUCCESS;
2280     }
2281 
2282     OemName.Buffer =  Sb->s_volume_name;
2283     OemName.MaximumLength = 16;
2284     OemName.Length = Length;
2285 
2286     status = Ext2OEMToUnicode(Vcb, &Label, &OemName);
2287     if (NT_SUCCESS(status)) {
2288         Vcb->Vpb->VolumeLabelLength = Label.Length;
2289     }
2290 
2291     return status;
2292 }
2293 
2294 static __inline BOOLEAN Ext2IsNullUuid (__u8 * uuid)
2295 {
2296     int i;
2297     for (i = 0; i < 16; i++) {
2298         if (uuid[i]) {
2299             break;
2300         }
2301     }
2302 
2303     return (i >= 16);
2304 }
2305 
2306 #define is_power_of_2(x)        ((x) != 0 && (((x) & ((x) - 1)) == 0))
2307 
2308 NTSTATUS
2309 Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
2310                    IN PEXT2_VCB         Vcb,
2311                    IN PEXT2_SUPER_BLOCK sb,
2312                    IN PDEVICE_OBJECT TargetDevice,
2313                    IN PDEVICE_OBJECT VolumeDevice,
2314                    IN PVPB Vpb )
2315 {
2316     NTSTATUS                    Status = STATUS_UNRECOGNIZED_VOLUME;
2317     ULONG                       IoctlSize;
2318     LONGLONG                    DiskSize;
2319     LONGLONG                    PartSize;
2320     UNICODE_STRING              RootNode;
2321     USHORT                      Buffer[2];
2322     ULONG                       ChangeCount = 0, features;
2323     CC_FILE_SIZES               FileSizes;
2324     int                         i, has_huge_files;
2325 
2326     BOOLEAN                     VcbResourceInitialized = FALSE;
2327     BOOLEAN                     NotifySyncInitialized = FALSE;
2328     BOOLEAN                     ExtentsInitialized = FALSE;
2329     BOOLEAN                     InodeLookasideInitialized = FALSE;
2330     BOOLEAN                     GroupLoaded = FALSE;
2331 
2332     _SEH2_TRY {
2333 
2334         if (Vpb == NULL) {
2335             Status = STATUS_DEVICE_NOT_READY;
2336             _SEH2_LEAVE;
2337         }
2338 
2339         /* Reject mounting volume if we encounter unsupported incompat features */
2340         if (FlagOn(sb->s_feature_incompat, ~EXT4_FEATURE_INCOMPAT_SUPP)) {
2341             Status = STATUS_UNRECOGNIZED_VOLUME;
2342             _SEH2_LEAVE;
2343         }
2344 
2345         /* Mount the volume RO if we encounter unsupported ro_compat features */
2346         if (FlagOn(sb->s_feature_ro_compat, ~EXT4_FEATURE_RO_COMPAT_SUPP)) {
2347             SetLongFlag(Vcb->Flags, VCB_RO_COMPAT_READ_ONLY);
2348         }
2349 
2350         /* Recognize the filesystem as Ext3fs if it supports journalling */
2351         if (IsFlagOn(sb->s_feature_compat, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) {
2352             Vcb->IsExt3fs = TRUE;
2353         }
2354 
2355         /* check block size */
2356         Vcb->BlockSize  = (EXT2_MIN_BLOCK_SIZE << sb->s_log_block_size);
2357         /* we cannot handle volume with block size bigger than 64k */
2358         if (Vcb->BlockSize > EXT2_MAX_USER_BLKSIZE) {
2359             Status = STATUS_UNRECOGNIZED_VOLUME;
2360             _SEH2_LEAVE;
2361         }
2362 
2363         if (Vcb->BlockSize >= PAGE_SIZE) {
2364             Vcb->IoUnitBits = PAGE_SHIFT;
2365             Vcb->IoUnitSize = PAGE_SIZE;
2366         } else {
2367             Vcb->IoUnitSize = Vcb->BlockSize;
2368             Vcb->IoUnitBits = Ext2Log2(Vcb->BlockSize);
2369         }
2370 
2371         /* initialize vcb header members ... */
2372         Vcb->Header.IsFastIoPossible = FastIoIsNotPossible;
2373         Vcb->Header.Resource = &(Vcb->MainResource);
2374         Vcb->Header.PagingIoResource = &(Vcb->PagingIoResource);
2375         Vcb->OpenVolumeCount = 0;
2376         Vcb->OpenHandleCount = 0;
2377         Vcb->ReferenceCount = 0;
2378 
2379         /* initialize eresources */
2380         ExInitializeResourceLite(&Vcb->MainResource);
2381         ExInitializeResourceLite(&Vcb->PagingIoResource);
2382         ExInitializeResourceLite(&Vcb->MetaInode);
2383         ExInitializeResourceLite(&Vcb->MetaBlock);
2384         ExInitializeResourceLite(&Vcb->McbLock);
2385         ExInitializeResourceLite(&Vcb->FcbLock);
2386         ExInitializeResourceLite(&Vcb->sbi.s_gd_lock);
2387 #ifndef _WIN2K_TARGET_
2388         ExInitializeFastMutex(&Vcb->Mutex);
2389         FsRtlSetupAdvancedHeader(&Vcb->Header,  &Vcb->Mutex);
2390 #endif
2391         VcbResourceInitialized = TRUE;
2392 
2393         /* initialize Fcb list head */
2394         InitializeListHead(&Vcb->FcbList);
2395 
2396         /* initialize Mcb list head  */
2397         InitializeListHead(&(Vcb->McbList));
2398 
2399         /* initialize directory notify list */
2400         InitializeListHead(&Vcb->NotifyList);
2401         FsRtlNotifyInitializeSync(&Vcb->NotifySync);
2402         NotifySyncInitialized = TRUE;
2403 
2404         /* superblock checking */
2405         Vcb->SuperBlock = sb;
2406 
2407         /* initialize Vpb and Label */
2408         Vcb->DeviceObject = VolumeDevice;
2409         Vcb->TargetDeviceObject = TargetDevice;
2410         Vcb->Vpb = Vpb;
2411         Vcb->RealDevice = Vpb->RealDevice;
2412         Vpb->DeviceObject = VolumeDevice;
2413 
2414         /* set inode size */
2415         Vcb->InodeSize = (ULONG)sb->s_inode_size;
2416         if (Vcb->InodeSize == 0) {
2417             Vcb->InodeSize = EXT2_GOOD_OLD_INODE_SIZE;
2418         }
2419 
2420         /* initialize inode lookaside list */
2421         ExInitializeNPagedLookasideList(&(Vcb->InodeLookasideList),
2422                                         NULL, NULL, 0, Vcb->InodeSize,
2423                                         'SNIE', 0);
2424 
2425         InodeLookasideInitialized = TRUE;
2426 
2427         /* initialize label in Vpb */
2428         Status = Ext2InitializeLabel(Vcb, sb);
2429         if (!NT_SUCCESS(Status)) {
2430             DbgBreak();
2431         }
2432 
2433         /* check device characteristics flags */
2434         if (IsFlagOn(Vpb->RealDevice->Characteristics, FILE_REMOVABLE_MEDIA)) {
2435             SetLongFlag(Vcb->Flags, VCB_REMOVABLE_MEDIA);
2436         }
2437 
2438         if (IsFlagOn(Vpb->RealDevice->Characteristics, FILE_FLOPPY_DISKETTE)) {
2439             SetLongFlag(Vcb->Flags, VCB_FLOPPY_DISK);
2440         }
2441 
2442         if (IsFlagOn(Vpb->RealDevice->Characteristics, FILE_READ_ONLY_DEVICE)) {
2443             SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
2444         }
2445 
2446         if (IsFlagOn(TargetDevice->Characteristics, FILE_READ_ONLY_DEVICE)) {
2447             SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
2448         }
2449 
2450         /* verify device is writable ? */
2451         if (Ext2IsMediaWriteProtected(IrpContext, TargetDevice)) {
2452             SetFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
2453         }
2454 
2455         /* initialize UUID and serial number */
2456         if (Ext2IsNullUuid(sb->s_uuid)) {
2457             ExUuidCreate((UUID *)sb->s_uuid);
2458         }
2459         Vpb->SerialNumber = ((ULONG*)sb->s_uuid)[0] +
2460                             ((ULONG*)sb->s_uuid)[1] +
2461                             ((ULONG*)sb->s_uuid)[2] +
2462                             ((ULONG*)sb->s_uuid)[3];
2463 
2464         /* query partition size and disk geometry parameters */
2465         DiskSize =  Vcb->DiskGeometry.Cylinders.QuadPart *
2466                     Vcb->DiskGeometry.TracksPerCylinder *
2467                     Vcb->DiskGeometry.SectorsPerTrack *
2468                     Vcb->DiskGeometry.BytesPerSector;
2469 
2470         IoctlSize = sizeof(PARTITION_INFORMATION);
2471         Status = Ext2DiskIoControl(
2472                      TargetDevice,
2473                      IOCTL_DISK_GET_PARTITION_INFO,
2474                      NULL,
2475                      0,
2476                      &Vcb->PartitionInformation,
2477                      &IoctlSize );
2478         if (NT_SUCCESS(Status)) {
2479             PartSize = Vcb->PartitionInformation.PartitionLength.QuadPart;
2480         } else {
2481             Vcb->PartitionInformation.StartingOffset.QuadPart = 0;
2482             Vcb->PartitionInformation.PartitionLength.QuadPart = DiskSize;
2483             PartSize = DiskSize;
2484             Status = STATUS_SUCCESS;
2485         }
2486         Vcb->Header.AllocationSize.QuadPart =
2487             Vcb->Header.FileSize.QuadPart = PartSize;
2488 
2489         Vcb->Header.ValidDataLength.QuadPart =
2490             Vcb->Header.FileSize.QuadPart;
2491 
2492         /* verify count */
2493         IoctlSize = sizeof(ULONG);
2494         Status = Ext2DiskIoControl(
2495                      TargetDevice,
2496                      IOCTL_DISK_CHECK_VERIFY,
2497                      NULL,
2498                      0,
2499                      &ChangeCount,
2500                      &IoctlSize );
2501 
2502         if (!NT_SUCCESS(Status)) {
2503             _SEH2_LEAVE;
2504         }
2505         Vcb->ChangeCount = ChangeCount;
2506 
2507         /* create the stream object for ext2 volume */
2508         Vcb->Volume = IoCreateStreamFileObject(NULL, Vcb->Vpb->RealDevice);
2509         if (!Vcb->Volume) {
2510             Status = STATUS_UNRECOGNIZED_VOLUME;
2511             _SEH2_LEAVE;
2512         }
2513 
2514         /* initialize streaming object file */
2515         Vcb->Volume->SectionObjectPointer = &(Vcb->SectionObject);
2516         Vcb->Volume->ReadAccess = TRUE;
2517         Vcb->Volume->WriteAccess = TRUE;
2518         Vcb->Volume->DeleteAccess = TRUE;
2519         Vcb->Volume->FsContext = (PVOID) Vcb;
2520         Vcb->Volume->FsContext2 = NULL;
2521         Vcb->Volume->Vpb = Vcb->Vpb;
2522 
2523         FileSizes.AllocationSize.QuadPart =
2524             FileSizes.FileSize.QuadPart =
2525                 FileSizes.ValidDataLength.QuadPart =
2526                     Vcb->Header.AllocationSize.QuadPart;
2527 
2528         CcInitializeCacheMap( Vcb->Volume,
2529                               &FileSizes,
2530                               TRUE,
2531                               &(Ext2Global->CacheManagerNoOpCallbacks),
2532                               Vcb );
2533 
2534         /* initialize disk block LargetMcb and entry Mcb,
2535            it will raise an expcetion if failed */
2536         _SEH2_TRY {
2537             FsRtlInitializeLargeMcb(&(Vcb->Extents), PagedPool);
2538         } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
2539             Status = STATUS_INSUFFICIENT_RESOURCES;
2540             DbgBreak();
2541         } _SEH2_END;
2542         if (!NT_SUCCESS(Status)) {
2543             _SEH2_LEAVE;
2544         }
2545         ExtentsInitialized = TRUE;
2546 
2547         /* set block device */
2548         Vcb->bd.bd_dev = Vcb->RealDevice;
2549         Vcb->bd.bd_geo = Vcb->DiskGeometry;
2550         Vcb->bd.bd_part = Vcb->PartitionInformation;
2551         Vcb->bd.bd_volume = Vcb->Volume;
2552         Vcb->bd.bd_priv = (void *) Vcb;
2553         memset(&Vcb->bd.bd_bh_root, 0, sizeof(struct rb_root));
2554         InitializeListHead(&Vcb->bd.bd_bh_free);
2555         ExInitializeResourceLite(&Vcb->bd.bd_bh_lock);
2556         KeInitializeEvent(&Vcb->bd.bd_bh_notify,
2557                            NotificationEvent, TRUE);
2558         Vcb->bd.bd_bh_cache = kmem_cache_create("bd_bh_buffer",
2559                                                 Vcb->BlockSize, 0, 0, NULL);
2560         if (!Vcb->bd.bd_bh_cache) {
2561             Status = STATUS_INSUFFICIENT_RESOURCES;
2562             _SEH2_LEAVE;
2563         }
2564 
2565         Vcb->SectorBits = Ext2Log2(SECTOR_SIZE);
2566         Vcb->sb.s_magic = sb->s_magic;
2567         Vcb->sb.s_bdev = &Vcb->bd;
2568         Vcb->sb.s_blocksize = BLOCK_SIZE;
2569         Vcb->sb.s_blocksize_bits = BLOCK_BITS;
2570         Vcb->sb.s_priv = (void *) Vcb;
2571         Vcb->sb.s_fs_info = &Vcb->sbi;
2572 
2573         Vcb->sbi.s_es = sb;
2574         Vcb->sbi.s_blocks_per_group = sb->s_blocks_per_group;
2575         Vcb->sbi.s_first_ino = sb->s_first_ino;
2576         Vcb->sbi.s_desc_size = sb->s_desc_size;
2577 
2578         if (EXT3_HAS_INCOMPAT_FEATURE(&Vcb->sb, EXT4_FEATURE_INCOMPAT_64BIT)) {
2579             if (Vcb->sbi.s_desc_size < EXT4_MIN_DESC_SIZE_64BIT ||
2580                     Vcb->sbi.s_desc_size > EXT4_MAX_DESC_SIZE ||
2581                     !is_power_of_2(Vcb->sbi.s_desc_size)) {
2582                 DEBUG(DL_ERR, ("EXT4-fs: unsupported descriptor size %lu\n", Vcb->sbi.s_desc_size));
2583                 Status = STATUS_DISK_CORRUPT_ERROR;
2584                 _SEH2_LEAVE;
2585             }
2586         } else {
2587             Vcb->sbi.s_desc_size = EXT4_MIN_DESC_SIZE;
2588         }
2589 
2590         Vcb->sbi.s_blocks_per_group = sb->s_blocks_per_group;
2591         Vcb->sbi.s_inodes_per_group = sb->s_inodes_per_group;
2592         if (EXT3_INODES_PER_GROUP(&Vcb->sb) == 0) {
2593             Status = STATUS_DISK_CORRUPT_ERROR;
2594             _SEH2_LEAVE;
2595         }
2596         Vcb->sbi.s_inodes_per_block = BLOCK_SIZE / Vcb->InodeSize;
2597         if (Vcb->sbi.s_inodes_per_block == 0) {
2598             Status = STATUS_DISK_CORRUPT_ERROR;
2599             _SEH2_LEAVE;
2600         }
2601         Vcb->sbi.s_itb_per_group = Vcb->sbi.s_inodes_per_group /
2602                                    Vcb->sbi.s_inodes_per_block;
2603 
2604 
2605         Vcb->sbi.s_desc_per_block = BLOCK_SIZE / GROUP_DESC_SIZE;
2606         Vcb->sbi.s_desc_per_block_bits = ilog2(Vcb->sbi.s_desc_per_block);
2607 
2608         for (i=0; i < 4; i++) {
2609             Vcb->sbi.s_hash_seed[i] = sb->s_hash_seed[i];
2610         }
2611         Vcb->sbi.s_def_hash_version = sb->s_def_hash_version;
2612 
2613         if (le32_to_cpu(sb->s_rev_level) == EXT3_GOOD_OLD_REV &&
2614                 (EXT3_HAS_COMPAT_FEATURE(&Vcb->sb, ~0U) ||
2615                  EXT3_HAS_RO_COMPAT_FEATURE(&Vcb->sb, ~0U) ||
2616                  EXT3_HAS_INCOMPAT_FEATURE(&Vcb->sb, ~0U))) {
2617             printk(KERN_WARNING
2618                    "EXT3-fs warning: feature flags set on rev 0 fs, "
2619                    "running e2fsck is recommended\n");
2620         }
2621 
2622         /*
2623          * Check feature flags regardless of the revision level, since we
2624          * previously didn't change the revision level when setting the flags,
2625          * so there is a chance incompat flags are set on a rev 0 filesystem.
2626          */
2627         features = EXT3_HAS_INCOMPAT_FEATURE(&Vcb->sb, ~EXT4_FEATURE_INCOMPAT_SUPP);
2628         if (features & EXT4_FEATURE_INCOMPAT_DIRDATA) {
2629             SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
2630             ClearFlag(features, EXT4_FEATURE_INCOMPAT_DIRDATA);
2631         }
2632         if (features) {
2633             printk(KERN_ERR "EXT3-fs: %s: couldn't mount because of "
2634                    "unsupported optional features (%x).\n",
2635                    Vcb->sb.s_id, le32_to_cpu(features));
2636             Status = STATUS_UNRECOGNIZED_VOLUME;
2637             _SEH2_LEAVE;
2638         }
2639 
2640         features = EXT3_HAS_RO_COMPAT_FEATURE(&Vcb->sb, ~EXT4_FEATURE_RO_COMPAT_SUPP);
2641         if (features) {
2642             printk(KERN_ERR "EXT3-fs: %s: unsupported optional features in this volume: (%x).\n",
2643                    Vcb->sb.s_id, le32_to_cpu(features));
2644             if (CanIWrite(Vcb)) {
2645             } else {
2646                 SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
2647             }
2648         }
2649 
2650         has_huge_files = EXT3_HAS_RO_COMPAT_FEATURE(&Vcb->sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE);
2651 
2652         Vcb->sb.s_maxbytes = ext3_max_size(BLOCK_BITS, has_huge_files);
2653         Vcb->max_bitmap_bytes = ext3_max_bitmap_size(BLOCK_BITS,
2654                                 has_huge_files);
2655         Vcb->max_bytes = ext3_max_size(BLOCK_BITS, has_huge_files);
2656 
2657         /* calculate maximum file bocks ... */
2658         {
2659             ULONG  dwData[EXT2_BLOCK_TYPES] = {EXT2_NDIR_BLOCKS, 1, 1, 1};
2660             ULONG  i;
2661 
2662             ASSERT(BLOCK_BITS == Ext2Log2(BLOCK_SIZE));
2663 
2664             Vcb->sbi.s_groups_count = (ULONG)(ext3_blocks_count(sb) - sb->s_first_data_block +
2665                                               sb->s_blocks_per_group - 1) / sb->s_blocks_per_group;
2666 
2667             Vcb->max_data_blocks = 0;
2668             for (i = 0; i < EXT2_BLOCK_TYPES; i++) {
2669                 if (BLOCK_BITS >= 12 && i == (EXT2_BLOCK_TYPES - 1)) {
2670                     dwData[i] = 0x40000000;
2671                 } else {
2672                     dwData[i] = dwData[i] << ((BLOCK_BITS - 2) * i);
2673                 }
2674                 Vcb->max_blocks_per_layer[i] = dwData[i];
2675                 Vcb->max_data_blocks += Vcb->max_blocks_per_layer[i];
2676             }
2677         }
2678 
2679         Vcb->sbi.s_gdb_count = (Vcb->sbi.s_groups_count + Vcb->sbi.s_desc_per_block - 1) /
2680                                Vcb->sbi.s_desc_per_block;
2681         /* load all gorup desc */
2682         if (!Ext2LoadGroup(Vcb)) {
2683             Status = STATUS_UNSUCCESSFUL;
2684             _SEH2_LEAVE;
2685         }
2686         GroupLoaded = TRUE;
2687 
2688         /* recovery journal since it's ext3 */
2689         if (Vcb->IsExt3fs) {
2690             Ext2RecoverJournal(IrpContext, Vcb);
2691             if (IsFlagOn(Vcb->Flags, VCB_JOURNAL_RECOVER)) {
2692                 SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
2693             }
2694         }
2695 
2696         /* Now allocating the mcb for root ... */
2697         Buffer[0] = L'\\';
2698         Buffer[1] = 0;
2699         RootNode.Buffer = Buffer;
2700         RootNode.MaximumLength = RootNode.Length = 2;
2701         Vcb->McbTree = Ext2AllocateMcb(
2702                            Vcb, &RootNode, NULL,
2703                            FILE_ATTRIBUTE_DIRECTORY
2704                        );
2705         if (!Vcb->McbTree) {
2706             DbgBreak();
2707             Status = STATUS_UNSUCCESSFUL;
2708             _SEH2_LEAVE;
2709         }
2710 
2711         Vcb->sb.s_root = Ext2BuildEntry(Vcb, NULL, &RootNode);
2712         if (!Vcb->sb.s_root) {
2713             DbgBreak();
2714             Status = STATUS_UNSUCCESSFUL;
2715             _SEH2_LEAVE;
2716         }
2717         Vcb->sb.s_root->d_sb = &Vcb->sb;
2718         Vcb->sb.s_root->d_inode = &Vcb->McbTree->Inode;
2719         Vcb->McbTree->de = Vcb->sb.s_root;
2720 
2721         /* load root inode */
2722         Vcb->McbTree->Inode.i_ino = EXT2_ROOT_INO;
2723         Vcb->McbTree->Inode.i_sb = &Vcb->sb;
2724         if (!Ext2LoadInode(Vcb, &Vcb->McbTree->Inode)) {
2725             DbgBreak();
2726             Status = STATUS_CANT_WAIT;
2727             _SEH2_LEAVE;
2728         }
2729 
2730         /* initializeroot node */
2731         Vcb->McbTree->CreationTime = Ext2NtTime(Vcb->McbTree->Inode.i_ctime);
2732         Vcb->McbTree->LastAccessTime = Ext2NtTime(Vcb->McbTree->Inode.i_atime);
2733         Vcb->McbTree->LastWriteTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime);
2734         Vcb->McbTree->ChangeTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime);
2735 
2736         /* check bitmap if user specifies it */
2737         if (IsFlagOn(Ext2Global->Flags, EXT2_CHECKING_BITMAP)) {
2738             Ext2CheckBitmapConsistency(IrpContext, Vcb);
2739         }
2740 
2741         /* get anything doen, then refer target device */
2742         ObReferenceObject(Vcb->TargetDeviceObject);
2743 
2744         /* query parameters from registry */
2745         Ext2PerformRegistryVolumeParams(Vcb);
2746 
2747         SetLongFlag(Vcb->Flags, VCB_INITIALIZED);
2748 
2749     } _SEH2_FINALLY {
2750 
2751         if (!NT_SUCCESS(Status)) {
2752 
2753             if (Vcb->McbTree) {
2754                 Ext2FreeMcb(Vcb, Vcb->McbTree);
2755             }
2756 
2757             if (InodeLookasideInitialized) {
2758                 ExDeleteNPagedLookasideList(&(Vcb->InodeLookasideList));
2759             }
2760 
2761             if (ExtentsInitialized) {
2762                 if (Vcb->bd.bd_bh_cache) {
2763                     if (GroupLoaded)
2764                         Ext2PutGroup(Vcb);
2765                     kmem_cache_destroy(Vcb->bd.bd_bh_cache);
2766                 }
2767                 FsRtlUninitializeLargeMcb(&(Vcb->Extents));
2768             }
2769 
2770             if (Vcb->Volume) {
2771                 if (Vcb->Volume->PrivateCacheMap) {
2772                     Ext2SyncUninitializeCacheMap(Vcb->Volume);
2773                 }
2774                 ObDereferenceObject(Vcb->Volume);
2775             }
2776 
2777             if (NotifySyncInitialized) {
2778                 FsRtlNotifyUninitializeSync(&Vcb->NotifySync);
2779             }
2780 
2781             if (VcbResourceInitialized) {
2782                 ExDeleteResourceLite(&Vcb->FcbLock);
2783                 ExDeleteResourceLite(&Vcb->McbLock);
2784                 ExDeleteResourceLite(&Vcb->MetaInode);
2785                 ExDeleteResourceLite(&Vcb->MetaBlock);
2786                 ExDeleteResourceLite(&Vcb->sbi.s_gd_lock);
2787                 ExDeleteResourceLite(&Vcb->MainResource);
2788                 ExDeleteResourceLite(&Vcb->PagingIoResource);
2789             }
2790         }
2791     } _SEH2_END;
2792 
2793     return Status;
2794 }
2795 
2796 
2797 VOID
2798 Ext2TearDownStream(IN PEXT2_VCB Vcb)
2799 {
2800     PFILE_OBJECT    Stream = Vcb->Volume;
2801     IO_STATUS_BLOCK IoStatus;
2802 
2803     ASSERT(Vcb != NULL);
2804     ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
2805            (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
2806 
2807     if (Stream) {
2808 
2809         Vcb->Volume = NULL;
2810 
2811         if (IsFlagOn(Stream->Flags, FO_FILE_MODIFIED)) {
2812             CcFlushCache(&(Vcb->SectionObject), NULL, 0, &IoStatus);
2813             ClearFlag(Stream->Flags, FO_FILE_MODIFIED);
2814         }
2815 
2816         if (Stream->PrivateCacheMap) {
2817             Ext2SyncUninitializeCacheMap(Stream);
2818         }
2819 
2820         ObDereferenceObject(Stream);
2821     }
2822 }
2823 
2824 VOID
2825 Ext2DestroyVcb (IN PEXT2_VCB Vcb)
2826 {
2827     ASSERT(Vcb != NULL);
2828     ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
2829            (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
2830 
2831     DEBUG(DL_FUN, ("Ext2DestroyVcb ...\n"));
2832 
2833     if (Vcb->Volume) {
2834         Ext2TearDownStream(Vcb);
2835     }
2836     ASSERT(NULL == Vcb->Volume);
2837 
2838     FsRtlNotifyUninitializeSync(&Vcb->NotifySync);
2839     Ext2ListExtents(&Vcb->Extents);
2840     FsRtlUninitializeLargeMcb(&(Vcb->Extents));
2841 
2842     Ext2CleanupAllMcbs(Vcb);
2843 
2844     Ext2DropBH(Vcb);
2845 
2846     if (Vcb->bd.bd_bh_cache)
2847         kmem_cache_destroy(Vcb->bd.bd_bh_cache);
2848     ExDeleteResourceLite(&Vcb->bd.bd_bh_lock);
2849 
2850     if (Vcb->SuperBlock) {
2851         Ext2FreePool(Vcb->SuperBlock, EXT2_SB_MAGIC);
2852         Vcb->SuperBlock = NULL;
2853     }
2854 
2855     if (IsFlagOn(Vcb->Flags, VCB_NEW_VPB)) {
2856         ASSERT(Vcb->Vpb2 != NULL);
2857         DEBUG(DL_DBG, ("Ext2DestroyVcb: Vpb2 to be freed: %p\n", Vcb->Vpb2));
2858         ExFreePoolWithTag(Vcb->Vpb2, TAG_VPB);
2859         DEC_MEM_COUNT(PS_VPB, Vcb->Vpb2, sizeof(VPB));
2860         Vcb->Vpb2 = NULL;
2861     }
2862 
2863     ObDereferenceObject(Vcb->TargetDeviceObject);
2864 
2865     ExDeleteNPagedLookasideList(&(Vcb->InodeLookasideList));
2866     ExDeleteResourceLite(&Vcb->FcbLock);
2867     ExDeleteResourceLite(&Vcb->McbLock);
2868     ExDeleteResourceLite(&Vcb->MetaInode);
2869     ExDeleteResourceLite(&Vcb->MetaBlock);
2870     ExDeleteResourceLite(&Vcb->sbi.s_gd_lock);
2871     ExDeleteResourceLite(&Vcb->PagingIoResource);
2872     ExDeleteResourceLite(&Vcb->MainResource);
2873 
2874     DEBUG(DL_DBG, ("Ext2DestroyVcb: DevObject=%p Vcb=%p\n", Vcb->DeviceObject, Vcb));
2875     IoDeleteDevice(Vcb->DeviceObject);
2876     DEC_MEM_COUNT(PS_VCB, Vcb->DeviceObject, sizeof(EXT2_VCB));
2877 }
2878 
2879 
2880 /* uninitialize cache map */
2881 
2882 VOID
2883 Ext2SyncUninitializeCacheMap (
2884     IN PFILE_OBJECT FileObject
2885 )
2886 {
2887     CACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent;
2888     NTSTATUS WaitStatus;
2889     LARGE_INTEGER Ext2LargeZero = {0,0};
2890 
2891 
2892     KeInitializeEvent( &UninitializeCompleteEvent.Event,
2893                        SynchronizationEvent,
2894                        FALSE);
2895 
2896     CcUninitializeCacheMap( FileObject,
2897                             &Ext2LargeZero,
2898                             &UninitializeCompleteEvent );
2899 
2900     WaitStatus = KeWaitForSingleObject( &UninitializeCompleteEvent.Event,
2901                                         Executive,
2902                                         KernelMode,
2903                                         FALSE,
2904                                         NULL);
2905 
2906     ASSERT (NT_SUCCESS(WaitStatus));
2907 }
2908 
2909 /* Link Mcb to tail of Vcb->McbList queue */
2910 
2911 VOID
2912 Ext2LinkTailMcb(PEXT2_VCB Vcb, PEXT2_MCB Mcb)
2913 {
2914     if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
2915         return;
2916     }
2917 
2918     ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
2919 
2920     if (IsFlagOn(Mcb->Flags, MCB_VCB_LINK)) {
2921         DEBUG(DL_RES, ( "Ext2LinkTailMcb: %wZ already linked.\n",
2922                         &Mcb->FullName));
2923     } else {
2924         InsertTailList(&Vcb->McbList, &Mcb->Link);
2925         SetLongFlag(Mcb->Flags, MCB_VCB_LINK);
2926         Ext2ReferXcb(&Vcb->NumOfMcb);
2927     }
2928 
2929     ExReleaseResourceLite(&Vcb->McbLock);
2930 }
2931 
2932 /* Link Mcb to head of Vcb->McbList queue */
2933 
2934 VOID
2935 Ext2LinkHeadMcb(PEXT2_VCB Vcb, PEXT2_MCB Mcb)
2936 {
2937     if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
2938         return;
2939     }
2940 
2941     ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
2942 
2943     if (!IsFlagOn(Mcb->Flags, MCB_VCB_LINK)) {
2944         InsertHeadList(&Vcb->McbList, &Mcb->Link);
2945         SetLongFlag(Mcb->Flags, MCB_VCB_LINK);
2946         Ext2ReferXcb(&Vcb->NumOfMcb);
2947     } else {
2948         DEBUG(DL_RES, ( "Ext2LinkHeadMcb: %wZ already linked.\n",
2949                         &Mcb->FullName));
2950     }
2951     ExReleaseResourceLite(&Vcb->McbLock);
2952 }
2953 
2954 /* Unlink Mcb from Vcb->McbList queue */
2955 
2956 VOID
2957 Ext2UnlinkMcb(PEXT2_VCB Vcb, PEXT2_MCB Mcb)
2958 {
2959     if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
2960         return;
2961     }
2962 
2963     ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
2964 
2965     if (IsFlagOn(Mcb->Flags, MCB_VCB_LINK)) {
2966         RemoveEntryList(&(Mcb->Link));
2967         ClearLongFlag(Mcb->Flags, MCB_VCB_LINK);
2968         Ext2DerefXcb(&Vcb->NumOfMcb);
2969     } else {
2970         DEBUG(DL_RES, ( "Ext2UnlinkMcb: %wZ already unlinked.\n",
2971                         &Mcb->FullName));
2972     }
2973     ExReleaseResourceLite(&Vcb->McbLock);
2974 }
2975 
2976 /* get the first Mcb record in Vcb->McbList */
2977 
2978 PEXT2_MCB
2979 Ext2FirstUnusedMcb(PEXT2_VCB Vcb, BOOLEAN Wait, ULONG Number)
2980 {
2981     PEXT2_MCB   Head = NULL;
2982     PEXT2_MCB   Tail = NULL;
2983     PEXT2_MCB   Mcb = NULL;
2984     PLIST_ENTRY List = NULL;
2985     ULONG       i = 0;
2986     LARGE_INTEGER   start, now;
2987 
2988     if (!ExAcquireResourceExclusiveLite(&Vcb->McbLock, Wait)) {
2989         return NULL;
2990     }
2991 
2992     KeQuerySystemTime(&start);
2993 
2994     while (Number--) {
2995 
2996         BOOLEAN     Skip = TRUE;
2997 
2998         if (IsListEmpty(&Vcb->McbList)) {
2999             break;
3000         }
3001 
3002         while (i++ < Vcb->NumOfMcb) {
3003 
3004             KeQuerySystemTime(&now);
3005             if (now.QuadPart > start.QuadPart + (LONGLONG)10*1000*1000) {
3006                 break;
3007             }
3008 
3009             List = RemoveHeadList(&Vcb->McbList);
3010             Mcb = CONTAINING_RECORD(List, EXT2_MCB, Link);
3011             ASSERT(IsFlagOn(Mcb->Flags, MCB_VCB_LINK));
3012 
3013             if (Mcb->Fcb == NULL && !IsMcbRoot(Mcb) &&
3014                     Mcb->Refercount == 0 &&
3015                     (Mcb->Child == NULL || IsMcbSymLink(Mcb))) {
3016 
3017                 Ext2RemoveMcb(Vcb, Mcb);
3018                 ClearLongFlag(Mcb->Flags, MCB_VCB_LINK);
3019                 Ext2DerefXcb(&Vcb->NumOfMcb);
3020 
3021                 /* attach all Mcb into a chain*/
3022                 if (Head) {
3023                     ASSERT(Tail != NULL);
3024                     Tail->Next = Mcb;
3025                     Tail = Mcb;
3026                 } else {
3027                     Head = Tail = Mcb;
3028                 }
3029                 Tail->Next = NULL;
3030                 Skip = FALSE;
3031 
3032             } else {
3033 
3034                 InsertTailList(&Vcb->McbList, &Mcb->Link);
3035                 Mcb = NULL;
3036             }
3037         }
3038 
3039         if (Skip)
3040             break;
3041     }
3042 
3043     ExReleaseResourceLite(&Vcb->McbLock);
3044 
3045     return Head;
3046 }
3047 
3048 
3049 /* Reaper thread to release unused Mcb blocks */
3050 #ifdef __REACTOS__
3051 VOID NTAPI
3052 #else
3053 VOID
3054 #endif
3055 Ext2McbReaperThread(
3056     PVOID   Context
3057 )
3058 {
3059     PEXT2_REAPER    Reaper = Context;
3060     PLIST_ENTRY     List = NULL;
3061     LARGE_INTEGER   Timeout;
3062 
3063     PEXT2_VCB       Vcb = NULL;
3064     PEXT2_MCB       Mcb  = NULL;
3065 
3066     ULONG           i, NumOfMcbs;
3067 
3068     BOOLEAN         GlobalAcquired = FALSE;
3069 
3070     BOOLEAN         DidNothing = TRUE;
3071     BOOLEAN         LastState  = TRUE;
3072     BOOLEAN         WaitLock;
3073 
3074     _SEH2_TRY {
3075 
3076         Reaper->Thread = PsGetCurrentThread();
3077 
3078         /* wake up DirverEntry */
3079         KeSetEvent(&Reaper->Engine, 0, FALSE);
3080 
3081         /* now process looping */
3082         while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) {
3083 
3084             WaitLock = FALSE;
3085 
3086             /* calculate how long we need wait */
3087             if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 128)) {
3088                 Timeout.QuadPart = (LONGLONG)-1000*1000; /* 0.1 second */
3089                 NumOfMcbs = Ext2Global->MaxDepth * 4;
3090                 WaitLock = TRUE;
3091             } else if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 32)) {
3092                 Timeout.QuadPart = (LONGLONG)-1000*1000*5; /* 0.5 second */
3093                 NumOfMcbs = Ext2Global->MaxDepth * 2;
3094                 WaitLock = TRUE;
3095             } else if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 8)) {
3096                 Timeout.QuadPart = (LONGLONG)-1000*1000*10; /* 1 second */
3097                 NumOfMcbs = Ext2Global->MaxDepth;
3098             } else if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 2)) {
3099                 Timeout.QuadPart = (LONGLONG)-2*1000*1000*10; /* 2 second */
3100                 NumOfMcbs = Ext2Global->MaxDepth / 4;
3101             } else if (Ext2Global->PerfStat.Current.Mcb > (ULONG)Ext2Global->MaxDepth) {
3102                 Timeout.QuadPart = (LONGLONG)-4*1000*1000*10; /* 4 seconds */
3103                 NumOfMcbs = Ext2Global->MaxDepth / 8;
3104             } else if (DidNothing) {
3105                 Timeout.QuadPart = (LONGLONG)-8*1000*1000*10; /* 8 seconds */
3106                 if (LastState) {
3107                     Timeout.QuadPart *= 2;
3108                 }
3109                 NumOfMcbs = Ext2Global->MaxDepth / 16;
3110             } else {
3111                 Timeout.QuadPart = (LONGLONG)-5*1000*1000*10; /* 5 seconds */
3112                 if (LastState) {
3113                     Timeout.QuadPart *= 2;
3114                 }
3115                 NumOfMcbs = Ext2Global->MaxDepth / 32;
3116             }
3117 
3118             if (NumOfMcbs == 0)
3119                 NumOfMcbs = 1;
3120 
3121             LastState = DidNothing;
3122 
3123             /* wait until it is waken or it times out */
3124             KeWaitForSingleObject(
3125                 &Reaper->Wait,
3126                 Executive,
3127                 KernelMode,
3128                 FALSE,
3129                 &Timeout
3130             );
3131 
3132             if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP))
3133                 break;
3134 
3135             DidNothing = TRUE;
3136 
3137             /* acquire global exclusive lock */
3138             if (!ExAcquireResourceSharedLite(&Ext2Global->Resource, WaitLock)) {
3139                 continue;
3140             }
3141             GlobalAcquired = TRUE;
3142 
3143             /* search all Vcb to get unused resources freed to system */
3144             for (List = Ext2Global->VcbList.Flink;
3145                     List != &(Ext2Global->VcbList);
3146                     List = List->Flink ) {
3147 
3148                 Vcb = CONTAINING_RECORD(List, EXT2_VCB, Next);
3149 
3150                 Mcb = Ext2FirstUnusedMcb(Vcb, WaitLock, NumOfMcbs);
3151                 while (Mcb) {
3152                     PEXT2_MCB   Next = Mcb->Next;
3153                     DEBUG(DL_RES, ( "Ext2ReaperThread: releasing Mcb (%p): %wZ"
3154                                     " Total: %xh\n", Mcb, &Mcb->FullName,
3155                                     Ext2Global->PerfStat.Current.Mcb));
3156                     Ext2FreeMcb(Vcb, Mcb);
3157                     Mcb = Next;
3158                     LastState = DidNothing = FALSE;
3159                 }
3160             }
3161             if (DidNothing) {
3162                 KeClearEvent(&Reaper->Wait);
3163             }
3164             if (GlobalAcquired) {
3165                 ExReleaseResourceLite(&Ext2Global->Resource);
3166                 GlobalAcquired = FALSE;
3167             }
3168         }
3169 
3170     } _SEH2_FINALLY {
3171 
3172         if (GlobalAcquired) {
3173             ExReleaseResourceLite(&Ext2Global->Resource);
3174         }
3175 
3176         KeSetEvent(&Reaper->Engine, 0, FALSE);
3177     } _SEH2_END;
3178 
3179     PsTerminateSystemThread(STATUS_SUCCESS);
3180 }
3181 
3182 
3183 /* get buffer heads from global Vcb BH list */
3184 
3185 BOOLEAN
3186 Ext2QueryUnusedBH(PEXT2_VCB Vcb, PLIST_ENTRY head)
3187 {
3188     struct buffer_head *bh = NULL;
3189     PLIST_ENTRY         next = NULL;
3190     LARGE_INTEGER       start, now;
3191     BOOLEAN             wake = FALSE;
3192 
3193     KeQuerySystemTime(&start);
3194 
3195     ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
3196 
3197     while (!IsListEmpty(&Vcb->bd.bd_bh_free)) {
3198 
3199         KeQuerySystemTime(&now);
3200         if (now.QuadPart > start.QuadPart + (LONGLONG)10*1000*1000) {
3201             break;
3202         }
3203 
3204         next = RemoveHeadList(&Vcb->bd.bd_bh_free);
3205         bh = CONTAINING_RECORD(next, struct buffer_head, b_link);
3206         if (atomic_read(&bh->b_count)) {
3207             InitializeListHead(&bh->b_link);
3208             /* to be inserted by brelse */
3209             continue;
3210         }
3211 
3212         if ( IsFlagOn(Vcb->Flags, VCB_BEING_DROPPED) ||
3213             (bh->b_ts_drop.QuadPart + (LONGLONG)10*1000*1000*15) > now.QuadPart ||
3214             (bh->b_ts_creat.QuadPart + (LONGLONG)10*1000*1000*180) > now.QuadPart) {
3215             InsertTailList(head, &bh->b_link);
3216             buffer_head_remove(&Vcb->bd, bh);
3217         } else {
3218             InsertHeadList(&Vcb->bd.bd_bh_free, &bh->b_link);
3219             break;
3220         }
3221     }
3222 
3223     wake = IsListEmpty(&Vcb->bd.bd_bh_free);
3224     ExReleaseResourceLite(&Vcb->bd.bd_bh_lock);
3225 
3226     if (wake)
3227         KeSetEvent(&Vcb->bd.bd_bh_notify, 0, FALSE);
3228 
3229     return IsFlagOn(Vcb->Flags, VCB_BEING_DROPPED);
3230 }
3231 
3232 
3233 /* Reaper thread to release unused buffer heads */
3234 #ifdef __REACTOS__
3235 VOID NTAPI
3236 #else
3237 VOID
3238 #endif
3239 Ext2bhReaperThread(
3240     PVOID   Context
3241 )
3242 {
3243     PEXT2_REAPER    Reaper = Context;
3244     PEXT2_VCB       Vcb = NULL;
3245     LIST_ENTRY      List, *Link;
3246     LARGE_INTEGER   Timeout;
3247 
3248     BOOLEAN         GlobalAcquired = FALSE;
3249     BOOLEAN         DidNothing = FALSE;
3250     BOOLEAN         NonWait = FALSE;
3251 
3252     _SEH2_TRY {
3253 
3254         Reaper->Thread = PsGetCurrentThread();
3255 
3256         /* wake up DirverEntry */
3257         KeSetEvent(&Reaper->Engine, 0, FALSE);
3258 
3259         /* now process looping */
3260         while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) {
3261 
3262             /* wait until it is waken or it times out */
3263             if (NonWait) {
3264                 Timeout.QuadPart = (LONGLONG)-10*1000*10;
3265                 NonWait = FALSE;
3266             } else if (DidNothing) {
3267                 Timeout.QuadPart = Timeout.QuadPart * 2;
3268             } else {
3269                 Timeout.QuadPart = (LONGLONG)-10*1000*1000*10; /* 10 seconds */
3270             }
3271             KeWaitForSingleObject(
3272                 &Reaper->Wait,
3273                 Executive,
3274                 KernelMode,
3275                 FALSE,
3276                 &Timeout
3277             );
3278 
3279             if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP))
3280                 break;
3281 
3282             InitializeListHead(&List);
3283 
3284             /* acquire global exclusive lock */
3285             ExAcquireResourceSharedLite(&Ext2Global->Resource, TRUE);
3286             GlobalAcquired = TRUE;
3287             /* search all Vcb to get unused resources freed to system */
3288             for (Link = Ext2Global->VcbList.Flink;
3289                  Link != &(Ext2Global->VcbList);
3290                  Link = Link->Flink ) {
3291 
3292                 Vcb = CONTAINING_RECORD(Link, EXT2_VCB, Next);
3293                 NonWait = Ext2QueryUnusedBH(Vcb, &List);
3294             }
3295             DidNothing = IsListEmpty(&List);
3296             if (DidNothing) {
3297                 KeClearEvent(&Reaper->Wait);
3298             }
3299             if (GlobalAcquired) {
3300                 ExReleaseResourceLite(&Ext2Global->Resource);
3301                 GlobalAcquired = FALSE;
3302             }
3303 
3304             while (!IsListEmpty(&List)) {
3305                 struct buffer_head *bh;
3306                 Link = RemoveHeadList(&List);
3307                 bh = CONTAINING_RECORD(Link, struct buffer_head, b_link);
3308                 ASSERT(0 == atomic_read(&bh->b_count));
3309                 free_buffer_head(bh);
3310             }
3311         }
3312 
3313     } _SEH2_FINALLY {
3314 
3315         if (GlobalAcquired) {
3316             ExReleaseResourceLite(&Ext2Global->Resource);
3317         }
3318 
3319         KeSetEvent(&Reaper->Engine, 0, FALSE);
3320     } _SEH2_END;
3321 
3322     PsTerminateSystemThread(STATUS_SUCCESS);
3323 }
3324 
3325 /* get unused Fcbs to free */
3326 
3327 BOOLEAN
3328 Ext2QueryUnusedFcb(PEXT2_VCB Vcb, PLIST_ENTRY list)
3329 {
3330     PEXT2_FCB       Fcb;
3331     PLIST_ENTRY     next = NULL;
3332     LARGE_INTEGER   start, now;
3333 
3334     ULONG           count = 0;
3335     ULONG           tries = 0;
3336     BOOLEAN         wake = FALSE;
3337     BOOLEAN         retry = TRUE;
3338 
3339     KeQuerySystemTime(&start);
3340 
3341     ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
3342 
3343 again:
3344 
3345     KeQuerySystemTime(&now);
3346     while (!IsListEmpty(&Vcb->FcbList)) {
3347 
3348         next = RemoveHeadList(&Vcb->FcbList);
3349         Fcb = CONTAINING_RECORD(next, EXT2_FCB, Next);
3350 
3351         if (Fcb->ReferenceCount > 0) {
3352             InsertTailList(&Vcb->FcbList, &Fcb->Next);
3353             break;
3354         }
3355 
3356         retry = FALSE;
3357 
3358         if (now.QuadPart < Fcb->TsDrop.QuadPart + 10*1000*1000*120) {
3359             InsertHeadList(&Vcb->FcbList, &Fcb->Next);
3360             break;
3361         }
3362 
3363         Ext2UnlinkFcb(Fcb);
3364         Ext2DerefXcb(&Vcb->FcbCount);
3365         InsertTailList(list, &Fcb->Next);
3366         if (++count >= Ext2Global->MaxDepth) {
3367             break;
3368         }
3369     }
3370 
3371     if (start.QuadPart + 10*1000*1000 > now.QuadPart) {
3372         retry = FALSE;
3373     }
3374 
3375     if (retry) {
3376         if (++tries < (Vcb->FcbCount >> 4) )
3377             goto again;
3378     }
3379 
3380     ExReleaseResourceLite(&Vcb->FcbLock);
3381 
3382     return 0;
3383 }
3384 
3385 /* Reaper thread to release Fcb */
3386 #ifdef __REACTOS__
3387 VOID NTAPI
3388 #else
3389 VOID
3390 #endif
3391 Ext2FcbReaperThread(
3392     PVOID   Context
3393 )
3394 {
3395     PEXT2_REAPER    Reaper = Context;
3396     PEXT2_VCB       Vcb = NULL;
3397     LIST_ENTRY      List, *Link;
3398     LARGE_INTEGER   Timeout;
3399 
3400     BOOLEAN         GlobalAcquired = FALSE;
3401     BOOLEAN         DidNothing = FALSE;
3402     BOOLEAN         NonWait = FALSE;
3403 
3404     _SEH2_TRY {
3405 
3406         Reaper->Thread = PsGetCurrentThread();
3407 
3408         /* wake up DirverEntry */
3409         KeSetEvent(&Reaper->Engine, 0, FALSE);
3410 
3411         /* now process looping */
3412         while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) {
3413 
3414             /* wait until it is waken or it times out */
3415             if (NonWait) {
3416                 Timeout.QuadPart = (LONGLONG)-10*1000*100;
3417                 NonWait = FALSE;
3418             } else if (DidNothing) {
3419                 Timeout.QuadPart = Timeout.QuadPart * 2;
3420             } else {
3421                 Timeout.QuadPart = (LONGLONG)-10*1000*1000*20; /* 20 seconds */
3422             }
3423             KeWaitForSingleObject(
3424                 &Reaper->Wait,
3425                 Executive,
3426                 KernelMode,
3427                 FALSE,
3428                 &Timeout
3429             );
3430 
3431             if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP))
3432                 break;
3433 
3434             InitializeListHead(&List);
3435 
3436             /* acquire global exclusive lock */
3437             ExAcquireResourceSharedLite(&Ext2Global->Resource, TRUE);
3438             GlobalAcquired = TRUE;
3439             /* search all Vcb to get unused resources freed to system */
3440             for (Link  = Ext2Global->VcbList.Flink;
3441                  Link != &(Ext2Global->VcbList);
3442                  Link  = Link->Flink ) {
3443 
3444                 Vcb = CONTAINING_RECORD(Link, EXT2_VCB, Next);
3445                 NonWait = Ext2QueryUnusedFcb(Vcb, &List);
3446             }
3447             DidNothing = IsListEmpty(&List);
3448             if (DidNothing) {
3449                 KeClearEvent(&Reaper->Wait);
3450             }
3451             if (GlobalAcquired) {
3452                 ExReleaseResourceLite(&Ext2Global->Resource);
3453                 GlobalAcquired = FALSE;
3454             }
3455 
3456             while (!IsListEmpty(&List)) {
3457                 PEXT2_FCB  Fcb;
3458                 Link = RemoveHeadList(&List);
3459                 Fcb = CONTAINING_RECORD(Link, EXT2_FCB, Next);
3460                 ASSERT(0 == Fcb->ReferenceCount);
3461                 Ext2FreeFcb(Fcb);
3462             }
3463         }
3464 
3465     } _SEH2_FINALLY {
3466 
3467         if (GlobalAcquired) {
3468             ExReleaseResourceLite(&Ext2Global->Resource);
3469         }
3470 
3471         KeSetEvent(&Reaper->Engine, 0, FALSE);
3472     } _SEH2_END;
3473 
3474     PsTerminateSystemThread(STATUS_SUCCESS);
3475 }
3476 
3477 NTSTATUS
3478 Ext2StartReaper(PEXT2_REAPER Reaper, EXT2_REAPER_RELEASE Free)
3479 {
3480     NTSTATUS status = STATUS_SUCCESS;
3481     OBJECT_ATTRIBUTES  oa;
3482     HANDLE   handle = 0;
3483     LARGE_INTEGER timeout;
3484 
3485     Reaper->Free = Free;
3486 
3487     /* initialize wait event */
3488     KeInitializeEvent(
3489         &Reaper->Wait,
3490         SynchronizationEvent, FALSE
3491     );
3492 
3493     /* Reaper thread engine event */
3494     KeInitializeEvent(
3495         &Reaper->Engine,
3496         SynchronizationEvent, FALSE
3497     );
3498 
3499     /* initialize oa */
3500     InitializeObjectAttributes(
3501         &oa,
3502         NULL,
3503         OBJ_CASE_INSENSITIVE |
3504         OBJ_KERNEL_HANDLE,
3505         NULL,
3506         NULL
3507     );
3508 
3509     /* start a new system thread */
3510     status = PsCreateSystemThread(
3511                  &handle,
3512                  0,
3513                  &oa,
3514                  NULL,
3515                  NULL,
3516                  Free,
3517                  (PVOID)Reaper
3518              );
3519 
3520     if (NT_SUCCESS(status)) {
3521         ZwClose(handle);
3522 
3523         /* make sure Reaperthread is started */
3524         timeout.QuadPart = (LONGLONG)-10*1000*1000*2; /* 2 seconds */
3525         status = KeWaitForSingleObject(
3526                      &Reaper->Engine,
3527                      Executive,
3528                      KernelMode,
3529                      FALSE,
3530                      &timeout
3531                  );
3532         if (status != STATUS_SUCCESS) {
3533             status = STATUS_INSUFFICIENT_RESOURCES;
3534         }
3535     }
3536 
3537     return status;
3538 }
3539 
3540 
3541 #ifdef __REACTOS__
3542 VOID NTAPI
3543 #else
3544 VOID
3545 #endif
3546 Ext2StopReaper(PEXT2_REAPER Reaper)
3547 {
3548     LARGE_INTEGER timeout;
3549 
3550     Reaper->Flags |= EXT2_REAPER_FLAG_STOP;
3551     KeSetEvent(&Reaper->Wait, 0, FALSE);
3552 
3553     /* make sure Reaperthread is started */
3554     timeout.QuadPart = (LONGLONG)-10*1000*1000*2; /* 2 seconds */
3555     KeWaitForSingleObject(
3556                      &Reaper->Engine,
3557                      Executive,
3558                      KernelMode,
3559                      FALSE,
3560                      &timeout);
3561 }
3562