xref: /reactos/drivers/filesystems/ext2/src/memory.c (revision 23373acb)
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
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
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
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
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
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
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
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
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
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
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
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 
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 
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 
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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         while ((Mcb = Ext2FirstUnusedMcb(Vcb, TRUE, Vcb->NumOfMcb)) != 0) {
1823             while (Mcb) {
1824                 PEXT2_MCB Next = Mcb->Next;
1825                 if (IsMcbSymLink(Mcb)) {
1826                     Mcb->Target = NULL;
1827                 }
1828                 Ext2FreeMcb(Vcb, Mcb);
1829                 Mcb = Next;
1830             }
1831         }
1832         Ext2FreeMcb(Vcb, Vcb->McbTree);
1833         Vcb->McbTree = NULL;
1834 
1835     } _SEH2_FINALLY {
1836 
1837         if (LockAcquired) {
1838             ExReleaseResourceLite(&Vcb->McbLock);
1839         }
1840     } _SEH2_END;
1841 }
1842 
1843 BOOLEAN
1844 Ext2CheckSetBlock(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb, LONGLONG Block)
1845 {
1846     PEXT2_GROUP_DESC    gd;
1847     struct buffer_head *gb = NULL;
1848     struct buffer_head *bh = NULL;
1849     ULONG               group, dwBlk, Length;
1850     RTL_BITMAP          bitmap;
1851     BOOLEAN             bModified = FALSE;
1852 
1853     group = (ULONG)(Block - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
1854     dwBlk = (ULONG)(Block - EXT2_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
1855 
1856     gd = ext4_get_group_desc(&Vcb->sb, group, &gb);
1857     if (!gd) {
1858         return FALSE;
1859     }
1860     bh = sb_getblk(&Vcb->sb, ext4_block_bitmap(&Vcb->sb, gd));
1861 
1862     if (group == Vcb->sbi.s_groups_count - 1) {
1863         Length = (ULONG)(TOTAL_BLOCKS % BLOCKS_PER_GROUP);
1864 
1865         /* s_blocks_count is integer multiple of s_blocks_per_group */
1866         if (Length == 0)
1867             Length = BLOCKS_PER_GROUP;
1868     } else {
1869         Length = BLOCKS_PER_GROUP;
1870     }
1871 
1872     if (dwBlk >= Length) {
1873         fini_bh(&gb);
1874         fini_bh(&bh);
1875         return FALSE;
1876     }
1877 
1878 
1879     RtlInitializeBitMap(&bitmap, (PULONG)bh->b_data, Length);
1880 
1881     if (RtlCheckBit(&bitmap, dwBlk) == 0) {
1882         DbgBreak();
1883         RtlSetBits(&bitmap, dwBlk, 1);
1884         bModified = TRUE;
1885         mark_buffer_dirty(bh);
1886     }
1887 
1888     fini_bh(&gb);
1889     fini_bh(&bh);
1890 
1891     return (!bModified);
1892 }
1893 
1894 BOOLEAN
1895 Ext2CheckBitmapConsistency(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb)
1896 {
1897     ULONG i, j, InodeBlocks;
1898 
1899     for (i = 0; i < Vcb->sbi.s_groups_count; i++) {
1900 
1901         PEXT2_GROUP_DESC    gd;
1902         struct buffer_head  *bh = NULL;
1903 
1904         gd = ext4_get_group_desc(&Vcb->sb, i, &bh);
1905         if (!gd)
1906             continue;
1907         Ext2CheckSetBlock(IrpContext, Vcb, ext4_block_bitmap(&Vcb->sb, gd));
1908         Ext2CheckSetBlock(IrpContext, Vcb, ext4_inode_bitmap(&Vcb->sb, gd));
1909 
1910 
1911         if (i == Vcb->sbi.s_groups_count - 1) {
1912             InodeBlocks = ((INODES_COUNT % INODES_PER_GROUP) *
1913                            Vcb->InodeSize + Vcb->BlockSize - 1) /
1914                           (Vcb->BlockSize);
1915         } else {
1916             InodeBlocks = (INODES_PER_GROUP * Vcb->InodeSize +
1917                            Vcb->BlockSize - 1) / (Vcb->BlockSize);
1918         }
1919 
1920         for (j = 0; j < InodeBlocks; j++ )
1921             Ext2CheckSetBlock(IrpContext, Vcb, ext4_inode_table(&Vcb->sb, gd) + j);
1922 
1923         fini_bh(&bh);
1924     }
1925 
1926     return TRUE;
1927 }
1928 
1929 /* Ext2Global->Resource should be already acquired */
1930 VOID
1931 Ext2InsertVcb(PEXT2_VCB Vcb)
1932 {
1933     InsertTailList(&(Ext2Global->VcbList), &Vcb->Next);
1934 }
1935 
1936 
1937 /* Ext2Global->Resource should be already acquired */
1938 VOID
1939 Ext2RemoveVcb(PEXT2_VCB Vcb)
1940 {
1941     RemoveEntryList(&Vcb->Next);
1942     InitializeListHead(&Vcb->Next);
1943 }
1944 
1945 NTSTATUS
1946 Ext2QueryVolumeParams(IN PEXT2_VCB Vcb, IN PUNICODE_STRING Params)
1947 {
1948     NTSTATUS                    Status;
1949     RTL_QUERY_REGISTRY_TABLE    QueryTable[2];
1950 
1951     UNICODE_STRING              UniName;
1952     PUSHORT                     UniBuffer = NULL;
1953 
1954     USHORT                      UUID[50];
1955 
1956     int                         i;
1957     int                         len = 0;
1958 
1959     /* zero params */
1960     RtlZeroMemory(Params, sizeof(UNICODE_STRING));
1961 
1962     /* constructing volume UUID name */
1963     memset(UUID, 0, sizeof(USHORT) * 50);
1964     for (i=0; i < 16; i++) {
1965         if (i == 0) {
1966             swprintf((wchar_t *)&UUID[len], L"{%2.2X",Vcb->SuperBlock->s_uuid[i]);
1967             len += 3;
1968         } else if (i == 15) {
1969             swprintf((wchar_t *)&UUID[len], L"-%2.2X}", Vcb->SuperBlock->s_uuid[i]);
1970             len +=4;
1971         } else {
1972             swprintf((wchar_t *)&UUID[len], L"-%2.2X", Vcb->SuperBlock->s_uuid[i]);
1973             len += 3;
1974         }
1975     }
1976 
1977     /* allocating memory for UniBuffer */
1978     UniBuffer = Ext2AllocatePool(PagedPool, 1024, EXT2_PARAM_MAGIC);
1979     if (NULL == UniBuffer) {
1980         Status = STATUS_INSUFFICIENT_RESOURCES;
1981         goto errorout;
1982     }
1983     RtlZeroMemory(UniBuffer, 1024);
1984 
1985     /* querying volume parameter string */
1986     RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2);
1987     QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
1988     QueryTable[0].Name = UUID;
1989     QueryTable[0].EntryContext = &(UniName);
1990     UniName.MaximumLength = 1024;
1991     UniName.Length = 0;
1992     UniName.Buffer = UniBuffer;
1993 
1994     Status = RtlQueryRegistryValues(
1995                  RTL_REGISTRY_ABSOLUTE,
1996                  Ext2Global->RegistryPath.Buffer,
1997                  &QueryTable[0],
1998                  NULL,
1999                  NULL
2000              );
2001 
2002     if (!NT_SUCCESS(Status)) {
2003         goto errorout;
2004     }
2005 
2006 errorout:
2007 
2008     if (NT_SUCCESS(Status)) {
2009         *Params = UniName;
2010     } else {
2011         if (UniBuffer) {
2012             Ext2FreePool(UniBuffer, EXT2_PARAM_MAGIC);
2013         }
2014     }
2015 
2016     return Status;
2017 }
2018 
2019 VOID
2020 Ext2ParseRegistryVolumeParams(
2021     IN  PUNICODE_STRING         Params,
2022     OUT PEXT2_VOLUME_PROPERTY3  Property
2023 )
2024 {
2025     WCHAR       Codepage[CODEPAGE_MAXLEN];
2026     WCHAR       Prefix[HIDINGPAT_LEN];
2027     WCHAR       Suffix[HIDINGPAT_LEN];
2028     USHORT      MountPoint[4];
2029     UCHAR       DrvLetter[4];
2030     WCHAR       wUID[8], wGID[8], wEUID[8], wEGID[8];
2031     CHAR        sUID[8], sGID[8], sEUID[8], sEGID[8];
2032 
2033     BOOLEAN     bWriteSupport = FALSE,
2034                 bCheckBitmap = FALSE,
2035                 bCodeName = FALSE,
2036                 bMountPoint = FALSE;
2037     BOOLEAN     bUID = 0, bGID = 0, bEUID = 0, bEGID = 0;
2038 
2039     struct {
2040         PWCHAR   Name;      /* parameters name */
2041         PBOOLEAN bExist;    /* is it contained in params */
2042         USHORT   Length;    /* parameter value length */
2043         PWCHAR   uValue;    /* value buffer in unicode */
2044         PCHAR    aValue;    /* value buffer in ansi */
2045     } ParamPattern[] = {
2046         /* writing support */
2047         {READING_ONLY, &Property->bReadonly, 0, NULL, NULL},
2048         {WRITING_SUPPORT, &bWriteSupport, 0, NULL, NULL},
2049         {EXT3_FORCEWRITING, &Property->bExt3Writable, 0, NULL, NULL},
2050 
2051         /* need check bitmap */
2052         {CHECKING_BITMAP, &bCheckBitmap, 0, NULL, NULL},
2053         /* codepage */
2054         {CODEPAGE_NAME, &bCodeName, CODEPAGE_MAXLEN,
2055          &Codepage[0], Property->Codepage},
2056         /* filter prefix and suffix */
2057         {HIDING_PREFIX, &Property->bHidingPrefix, HIDINGPAT_LEN,
2058          &Prefix[0], Property->sHidingPrefix},
2059         {HIDING_SUFFIX, &Property->bHidingSuffix, HIDINGPAT_LEN,
2060          &Suffix[0], Property->sHidingSuffix},
2061         {MOUNT_POINT, &bMountPoint, 4,
2062          &MountPoint[0], &DrvLetter[0]},
2063 
2064         {UID,  &bUID,  8, &wUID[0],  &sUID[0],},
2065         {GID,  &bGID,  8, &wGID[0],  &sGID[0]},
2066         {EUID, &bEUID, 8, &wEUID[0], &sEUID[0]},
2067         {EGID, &bEGID, 8, &wEGID[0], &sEGID[0]},
2068 
2069         /* end */
2070         {NULL, NULL, 0, NULL}
2071     };
2072 
2073     USHORT i, j, k;
2074 
2075     RtlZeroMemory(Codepage, sizeof(WCHAR) * CODEPAGE_MAXLEN);
2076     RtlZeroMemory(Prefix, sizeof(WCHAR) * HIDINGPAT_LEN);
2077     RtlZeroMemory(Suffix, sizeof(WCHAR) * HIDINGPAT_LEN);
2078     RtlZeroMemory(MountPoint, sizeof(USHORT) * 4);
2079     RtlZeroMemory(DrvLetter, sizeof(CHAR) * 4);
2080 
2081     RtlZeroMemory(Property, sizeof(EXT2_VOLUME_PROPERTY3));
2082     Property->Magic = EXT2_VOLUME_PROPERTY_MAGIC;
2083     Property->Command = APP_CMD_SET_PROPERTY3;
2084 
2085     for (i=0; ParamPattern[i].Name != NULL; i++) {
2086 
2087         UNICODE_STRING  Name1=*Params, Name2;
2088         RtlInitUnicodeString(&Name2, ParamPattern[i].Name);
2089         *ParamPattern[i].bExist = FALSE;
2090 
2091         for (j=0; j * sizeof(WCHAR) + Name2.Length <= Params->Length ; j++) {
2092 
2093             Name1.MaximumLength = Params->Length - j * sizeof(WCHAR);
2094             Name1.Length = Name2.Length;
2095             Name1.Buffer = &Params->Buffer[j];
2096 
2097             if (!RtlCompareUnicodeString(&Name1, &Name2, TRUE)) {
2098                 if (j * sizeof(WCHAR) + Name2.Length == Params->Length ||
2099                         Name1.Buffer[Name2.Length/sizeof(WCHAR)] == L';' ||
2100                         Name1.Buffer[Name2.Length/sizeof(WCHAR)] == L','  ) {
2101                     *(ParamPattern[i].bExist) = TRUE;
2102                 } else if ((j * 2 + Name2.Length < Params->Length + 2) ||
2103                            (Name1.Buffer[Name2.Length/sizeof(WCHAR)] == L'=' )) {
2104                     j += Name2.Length/sizeof(WCHAR) + 1;
2105                     k = 0;
2106                     while ( j + k < Params->Length/2 &&
2107                             k < ParamPattern[i].Length &&
2108                             Params->Buffer[j+k] != L';' &&
2109                             Params->Buffer[j+k] != L',' ) {
2110 #ifdef __REACTOS__
2111                         ParamPattern[i].uValue[k] = Params->Buffer[j + k];
2112                         k++;
2113 #else
2114                         ParamPattern[i].uValue[k] = Params->Buffer[j + k++];
2115 #endif
2116                     }
2117                     if (k) {
2118                         NTSTATUS status;
2119                         ANSI_STRING AnsiName;
2120                         AnsiName.Length = 0;
2121                         AnsiName.MaximumLength =ParamPattern[i].Length;
2122                         AnsiName.Buffer = ParamPattern[i].aValue;
2123 
2124                         Name2.Buffer = ParamPattern[i].uValue;
2125                         Name2.MaximumLength = Name2.Length = k * sizeof(WCHAR);
2126                         status = RtlUnicodeStringToAnsiString(
2127                                      &AnsiName, &Name2, FALSE);
2128                         if (NT_SUCCESS(status)) {
2129                             *(ParamPattern[i].bExist) = TRUE;
2130                         } else {
2131                             *ParamPattern[i].bExist = FALSE;
2132                         }
2133                     }
2134                 }
2135                 break;
2136             }
2137         }
2138     }
2139 
2140     if (bMountPoint) {
2141         Property->DrvLetter = DrvLetter[0];
2142         Property->DrvLetter |= 0x80;
2143     }
2144 
2145     if (bUID && bGID) {
2146         SetFlag(Property->Flags2, EXT2_VPROP3_USERIDS);
2147         sUID[7] = sGID[7] = sEUID[7] = sEGID[7] = 0;
2148         Property->uid = (USHORT)atoi(sUID);
2149         Property->gid = (USHORT)atoi(sGID);
2150         if (bEUID) {
2151             Property->euid = (USHORT)atoi(sEUID);
2152             Property->egid = (USHORT)atoi(sEGID);
2153             Property->EIDS = TRUE;
2154         } else {
2155             Property->EIDS = FALSE;
2156         }
2157     } else {
2158         ClearFlag(Property->Flags2, EXT2_VPROP3_USERIDS);
2159     }
2160 }
2161 
2162 NTSTATUS
2163 Ext2PerformRegistryVolumeParams(IN PEXT2_VCB Vcb)
2164 {
2165     NTSTATUS        Status;
2166     UNICODE_STRING  VolumeParams;
2167 
2168     Status = Ext2QueryVolumeParams(Vcb, &VolumeParams);
2169     if (NT_SUCCESS(Status)) {
2170 
2171         /* set Vcb settings from registery */
2172         EXT2_VOLUME_PROPERTY3  Property;
2173         Ext2ParseRegistryVolumeParams(&VolumeParams, &Property);
2174         Ext2ProcessVolumeProperty(Vcb, &Property, sizeof(Property));
2175 
2176     } else {
2177 
2178         /* don't support auto mount */
2179         if (IsFlagOn(Ext2Global->Flags, EXT2_AUTO_MOUNT)) {
2180             Status = STATUS_SUCCESS;
2181         } else {
2182             Status = STATUS_UNSUCCESSFUL;
2183             goto errorout;
2184         }
2185 
2186         /* set Vcb settings from Ext2Global */
2187         if (IsFlagOn(Ext2Global->Flags, EXT2_SUPPORT_WRITING)) {
2188             if (Vcb->IsExt3fs) {
2189                 if (IsFlagOn(Ext2Global->Flags, EXT3_FORCE_WRITING)) {
2190                     ClearLongFlag(Vcb->Flags, VCB_READ_ONLY);
2191                 } else {
2192                     SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
2193                 }
2194             } else {
2195                 ClearLongFlag(Vcb->Flags, VCB_READ_ONLY);
2196             }
2197         } else {
2198             SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
2199         }
2200 
2201         /* set the default codepage */
2202         Vcb->Codepage.PageTable = Ext2Global->Codepage.PageTable;
2203         memcpy(Vcb->Codepage.AnsiName, Ext2Global->Codepage.AnsiName, CODEPAGE_MAXLEN);
2204         Vcb->Codepage.PageTable = Ext2Global->Codepage.PageTable;
2205 
2206         if (Vcb->bHidingPrefix == Ext2Global->bHidingPrefix) {
2207             RtlCopyMemory( Vcb->sHidingPrefix,
2208                            Ext2Global->sHidingPrefix,
2209                            HIDINGPAT_LEN);
2210         } else {
2211             RtlZeroMemory( Vcb->sHidingPrefix,
2212                            HIDINGPAT_LEN);
2213         }
2214 
2215         if (Vcb->bHidingSuffix == Ext2Global->bHidingSuffix) {
2216             RtlCopyMemory( Vcb->sHidingSuffix,
2217                            Ext2Global->sHidingSuffix,
2218                            HIDINGPAT_LEN);
2219         } else {
2220             RtlZeroMemory( Vcb->sHidingSuffix,
2221                            HIDINGPAT_LEN);
2222         }
2223     }
2224 
2225 errorout:
2226 
2227     if (VolumeParams.Buffer) {
2228         Ext2FreePool(VolumeParams.Buffer, EXT2_PARAM_MAGIC);
2229     }
2230 
2231     return Status;
2232 }
2233 
2234 NTSTATUS
2235 Ext2InitializeLabel(
2236     IN PEXT2_VCB            Vcb,
2237     IN PEXT2_SUPER_BLOCK    Sb
2238 )
2239 {
2240     NTSTATUS            status;
2241 
2242     USHORT              Length;
2243     UNICODE_STRING      Label;
2244     OEM_STRING          OemName;
2245 
2246     Label.MaximumLength = 16 * sizeof(WCHAR);
2247     Label.Length    = 0;
2248     Label.Buffer    = Vcb->Vpb->VolumeLabel;
2249     Vcb->Vpb->VolumeLabelLength = 0;
2250     RtlZeroMemory(Label.Buffer, Label.MaximumLength);
2251 
2252     Length = 16;
2253     while (  (Length > 0) &&
2254              ((Sb->s_volume_name[Length -1]  == 0x00) ||
2255               (Sb->s_volume_name[Length - 1] == 0x20)  )
2256           ) {
2257         Length--;
2258     }
2259 
2260     if (Length == 0) {
2261         return STATUS_SUCCESS;
2262     }
2263 
2264     OemName.Buffer =  Sb->s_volume_name;
2265     OemName.MaximumLength = 16;
2266     OemName.Length = Length;
2267 
2268     status = Ext2OEMToUnicode(Vcb, &Label, &OemName);
2269     if (NT_SUCCESS(status)) {
2270         Vcb->Vpb->VolumeLabelLength = Label.Length;
2271     }
2272 
2273     return status;
2274 }
2275 
2276 static __inline BOOLEAN Ext2IsNullUuid (__u8 * uuid)
2277 {
2278     int i;
2279     for (i = 0; i < 16; i++) {
2280         if (uuid[i]) {
2281             break;
2282         }
2283     }
2284 
2285     return (i >= 16);
2286 }
2287 
2288 #define is_power_of_2(x)        ((x) != 0 && (((x) & ((x) - 1)) == 0))
2289 
2290 NTSTATUS
2291 Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
2292                    IN PEXT2_VCB         Vcb,
2293                    IN PEXT2_SUPER_BLOCK sb,
2294                    IN PDEVICE_OBJECT TargetDevice,
2295                    IN PDEVICE_OBJECT VolumeDevice,
2296                    IN PVPB Vpb )
2297 {
2298     NTSTATUS                    Status = STATUS_UNRECOGNIZED_VOLUME;
2299     ULONG                       IoctlSize;
2300     LONGLONG                    DiskSize;
2301     LONGLONG                    PartSize;
2302     UNICODE_STRING              RootNode;
2303     USHORT                      Buffer[2];
2304     ULONG                       ChangeCount = 0, features;
2305     CC_FILE_SIZES               FileSizes;
2306     int                         i, has_huge_files;
2307 
2308     BOOLEAN                     VcbResourceInitialized = FALSE;
2309     BOOLEAN                     NotifySyncInitialized = FALSE;
2310     BOOLEAN                     ExtentsInitialized = FALSE;
2311     BOOLEAN                     InodeLookasideInitialized = FALSE;
2312     BOOLEAN                     GroupLoaded = FALSE;
2313 
2314     _SEH2_TRY {
2315 
2316         if (Vpb == NULL) {
2317             Status = STATUS_DEVICE_NOT_READY;
2318             _SEH2_LEAVE;
2319         }
2320 
2321         /* Reject mounting volume if we encounter unsupported incompat features */
2322         if (FlagOn(sb->s_feature_incompat, ~EXT4_FEATURE_INCOMPAT_SUPP)) {
2323             Status = STATUS_UNRECOGNIZED_VOLUME;
2324             _SEH2_LEAVE;
2325         }
2326 
2327         /* Mount the volume RO if we encounter unsupported ro_compat features */
2328         if (FlagOn(sb->s_feature_ro_compat, ~EXT4_FEATURE_RO_COMPAT_SUPP)) {
2329             SetLongFlag(Vcb->Flags, VCB_RO_COMPAT_READ_ONLY);
2330         }
2331 
2332         /* Recognize the filesystem as Ext3fs if it supports journalling */
2333         if (IsFlagOn(sb->s_feature_compat, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) {
2334             Vcb->IsExt3fs = TRUE;
2335         }
2336 
2337         /* check block size */
2338         Vcb->BlockSize  = (EXT2_MIN_BLOCK_SIZE << sb->s_log_block_size);
2339         /* we cannot handle volume with block size bigger than 64k */
2340         if (Vcb->BlockSize > EXT2_MAX_USER_BLKSIZE) {
2341             Status = STATUS_UNRECOGNIZED_VOLUME;
2342             _SEH2_LEAVE;
2343         }
2344 
2345         if (Vcb->BlockSize >= PAGE_SIZE) {
2346             Vcb->IoUnitBits = PAGE_SHIFT;
2347             Vcb->IoUnitSize = PAGE_SIZE;
2348         } else {
2349             Vcb->IoUnitSize = Vcb->BlockSize;
2350             Vcb->IoUnitBits = Ext2Log2(Vcb->BlockSize);
2351         }
2352 
2353         /* initialize vcb header members ... */
2354         Vcb->Header.IsFastIoPossible = FastIoIsNotPossible;
2355         Vcb->Header.Resource = &(Vcb->MainResource);
2356         Vcb->Header.PagingIoResource = &(Vcb->PagingIoResource);
2357         Vcb->OpenVolumeCount = 0;
2358         Vcb->OpenHandleCount = 0;
2359         Vcb->ReferenceCount = 0;
2360 
2361         /* initialize eresources */
2362         ExInitializeResourceLite(&Vcb->MainResource);
2363         ExInitializeResourceLite(&Vcb->PagingIoResource);
2364         ExInitializeResourceLite(&Vcb->MetaInode);
2365         ExInitializeResourceLite(&Vcb->MetaBlock);
2366         ExInitializeResourceLite(&Vcb->McbLock);
2367         ExInitializeResourceLite(&Vcb->FcbLock);
2368         ExInitializeResourceLite(&Vcb->sbi.s_gd_lock);
2369 #ifndef _WIN2K_TARGET_
2370         ExInitializeFastMutex(&Vcb->Mutex);
2371         FsRtlSetupAdvancedHeader(&Vcb->Header,  &Vcb->Mutex);
2372 #endif
2373         VcbResourceInitialized = TRUE;
2374 
2375         /* initialize Fcb list head */
2376         InitializeListHead(&Vcb->FcbList);
2377 
2378         /* initialize Mcb list head  */
2379         InitializeListHead(&(Vcb->McbList));
2380 
2381         /* initialize directory notify list */
2382         InitializeListHead(&Vcb->NotifyList);
2383         FsRtlNotifyInitializeSync(&Vcb->NotifySync);
2384         NotifySyncInitialized = TRUE;
2385 
2386         /* superblock checking */
2387         Vcb->SuperBlock = sb;
2388 
2389         /* initialize Vpb and Label */
2390         Vcb->DeviceObject = VolumeDevice;
2391         Vcb->TargetDeviceObject = TargetDevice;
2392         Vcb->Vpb = Vpb;
2393         Vcb->RealDevice = Vpb->RealDevice;
2394         Vpb->DeviceObject = VolumeDevice;
2395 
2396         /* set inode size */
2397         Vcb->InodeSize = (ULONG)sb->s_inode_size;
2398         if (Vcb->InodeSize == 0) {
2399             Vcb->InodeSize = EXT2_GOOD_OLD_INODE_SIZE;
2400         }
2401 
2402         /* initialize inode lookaside list */
2403         ExInitializeNPagedLookasideList(&(Vcb->InodeLookasideList),
2404                                         NULL, NULL, 0, Vcb->InodeSize,
2405                                         'SNIE', 0);
2406 
2407         InodeLookasideInitialized = TRUE;
2408 
2409         /* initialize label in Vpb */
2410         Status = Ext2InitializeLabel(Vcb, sb);
2411         if (!NT_SUCCESS(Status)) {
2412             DbgBreak();
2413         }
2414 
2415         /* check device characteristics flags */
2416         if (IsFlagOn(Vpb->RealDevice->Characteristics, FILE_REMOVABLE_MEDIA)) {
2417             SetLongFlag(Vcb->Flags, VCB_REMOVABLE_MEDIA);
2418         }
2419 
2420         if (IsFlagOn(Vpb->RealDevice->Characteristics, FILE_FLOPPY_DISKETTE)) {
2421             SetLongFlag(Vcb->Flags, VCB_FLOPPY_DISK);
2422         }
2423 
2424         if (IsFlagOn(Vpb->RealDevice->Characteristics, FILE_READ_ONLY_DEVICE)) {
2425             SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
2426         }
2427 
2428         if (IsFlagOn(TargetDevice->Characteristics, FILE_READ_ONLY_DEVICE)) {
2429             SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
2430         }
2431 
2432         /* verify device is writable ? */
2433         if (Ext2IsMediaWriteProtected(IrpContext, TargetDevice)) {
2434             SetFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
2435         }
2436 
2437         /* initialize UUID and serial number */
2438         if (Ext2IsNullUuid(sb->s_uuid)) {
2439             ExUuidCreate((UUID *)sb->s_uuid);
2440         }
2441         Vpb->SerialNumber = ((ULONG*)sb->s_uuid)[0] +
2442                             ((ULONG*)sb->s_uuid)[1] +
2443                             ((ULONG*)sb->s_uuid)[2] +
2444                             ((ULONG*)sb->s_uuid)[3];
2445 
2446         /* query partition size and disk geometry parameters */
2447         DiskSize =  Vcb->DiskGeometry.Cylinders.QuadPart *
2448                     Vcb->DiskGeometry.TracksPerCylinder *
2449                     Vcb->DiskGeometry.SectorsPerTrack *
2450                     Vcb->DiskGeometry.BytesPerSector;
2451 
2452         IoctlSize = sizeof(PARTITION_INFORMATION);
2453         Status = Ext2DiskIoControl(
2454                      TargetDevice,
2455                      IOCTL_DISK_GET_PARTITION_INFO,
2456                      NULL,
2457                      0,
2458                      &Vcb->PartitionInformation,
2459                      &IoctlSize );
2460         if (NT_SUCCESS(Status)) {
2461             PartSize = Vcb->PartitionInformation.PartitionLength.QuadPart;
2462         } else {
2463             Vcb->PartitionInformation.StartingOffset.QuadPart = 0;
2464             Vcb->PartitionInformation.PartitionLength.QuadPart = DiskSize;
2465             PartSize = DiskSize;
2466             Status = STATUS_SUCCESS;
2467         }
2468         Vcb->Header.AllocationSize.QuadPart =
2469             Vcb->Header.FileSize.QuadPart = PartSize;
2470 
2471         Vcb->Header.ValidDataLength.QuadPart =
2472             Vcb->Header.FileSize.QuadPart;
2473 
2474         /* verify count */
2475         IoctlSize = sizeof(ULONG);
2476         Status = Ext2DiskIoControl(
2477                      TargetDevice,
2478                      IOCTL_DISK_CHECK_VERIFY,
2479                      NULL,
2480                      0,
2481                      &ChangeCount,
2482                      &IoctlSize );
2483 
2484         if (!NT_SUCCESS(Status)) {
2485             _SEH2_LEAVE;
2486         }
2487         Vcb->ChangeCount = ChangeCount;
2488 
2489         /* create the stream object for ext2 volume */
2490         Vcb->Volume = IoCreateStreamFileObject(NULL, Vcb->Vpb->RealDevice);
2491         if (!Vcb->Volume) {
2492             Status = STATUS_UNRECOGNIZED_VOLUME;
2493             _SEH2_LEAVE;
2494         }
2495 
2496         /* initialize streaming object file */
2497         Vcb->Volume->SectionObjectPointer = &(Vcb->SectionObject);
2498         Vcb->Volume->ReadAccess = TRUE;
2499         Vcb->Volume->WriteAccess = TRUE;
2500         Vcb->Volume->DeleteAccess = TRUE;
2501         Vcb->Volume->FsContext = (PVOID) Vcb;
2502         Vcb->Volume->FsContext2 = NULL;
2503         Vcb->Volume->Vpb = Vcb->Vpb;
2504 
2505         FileSizes.AllocationSize.QuadPart =
2506             FileSizes.FileSize.QuadPart =
2507                 FileSizes.ValidDataLength.QuadPart =
2508                     Vcb->Header.AllocationSize.QuadPart;
2509 
2510         CcInitializeCacheMap( Vcb->Volume,
2511                               &FileSizes,
2512                               TRUE,
2513                               &(Ext2Global->CacheManagerNoOpCallbacks),
2514                               Vcb );
2515 
2516         /* initialize disk block LargetMcb and entry Mcb,
2517            it will raise an expcetion if failed */
2518         _SEH2_TRY {
2519             FsRtlInitializeLargeMcb(&(Vcb->Extents), PagedPool);
2520         } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
2521             Status = STATUS_INSUFFICIENT_RESOURCES;
2522             DbgBreak();
2523         } _SEH2_END;
2524         if (!NT_SUCCESS(Status)) {
2525             _SEH2_LEAVE;
2526         }
2527         ExtentsInitialized = TRUE;
2528 
2529         /* set block device */
2530         Vcb->bd.bd_dev = Vcb->RealDevice;
2531         Vcb->bd.bd_geo = Vcb->DiskGeometry;
2532         Vcb->bd.bd_part = Vcb->PartitionInformation;
2533         Vcb->bd.bd_volume = Vcb->Volume;
2534         Vcb->bd.bd_priv = (void *) Vcb;
2535         memset(&Vcb->bd.bd_bh_root, 0, sizeof(struct rb_root));
2536         InitializeListHead(&Vcb->bd.bd_bh_free);
2537         ExInitializeResourceLite(&Vcb->bd.bd_bh_lock);
2538         KeInitializeEvent(&Vcb->bd.bd_bh_notify,
2539                            NotificationEvent, TRUE);
2540         Vcb->bd.bd_bh_cache = kmem_cache_create("bd_bh_buffer",
2541                                                 Vcb->BlockSize, 0, 0, NULL);
2542         if (!Vcb->bd.bd_bh_cache) {
2543             Status = STATUS_INSUFFICIENT_RESOURCES;
2544             _SEH2_LEAVE;
2545         }
2546 
2547         Vcb->SectorBits = Ext2Log2(SECTOR_SIZE);
2548         Vcb->sb.s_magic = sb->s_magic;
2549         Vcb->sb.s_bdev = &Vcb->bd;
2550         Vcb->sb.s_blocksize = BLOCK_SIZE;
2551         Vcb->sb.s_blocksize_bits = BLOCK_BITS;
2552         Vcb->sb.s_priv = (void *) Vcb;
2553         Vcb->sb.s_fs_info = &Vcb->sbi;
2554 
2555         Vcb->sbi.s_es = sb;
2556         Vcb->sbi.s_blocks_per_group = sb->s_blocks_per_group;
2557         Vcb->sbi.s_first_ino = sb->s_first_ino;
2558         Vcb->sbi.s_desc_size = sb->s_desc_size;
2559 
2560         if (EXT3_HAS_INCOMPAT_FEATURE(&Vcb->sb, EXT4_FEATURE_INCOMPAT_64BIT)) {
2561             if (Vcb->sbi.s_desc_size < EXT4_MIN_DESC_SIZE_64BIT ||
2562                     Vcb->sbi.s_desc_size > EXT4_MAX_DESC_SIZE ||
2563                     !is_power_of_2(Vcb->sbi.s_desc_size)) {
2564                 DEBUG(DL_ERR, ("EXT4-fs: unsupported descriptor size %lu\n", Vcb->sbi.s_desc_size));
2565                 Status = STATUS_DISK_CORRUPT_ERROR;
2566                 _SEH2_LEAVE;
2567             }
2568         } else {
2569             Vcb->sbi.s_desc_size = EXT4_MIN_DESC_SIZE;
2570         }
2571 
2572         Vcb->sbi.s_blocks_per_group = sb->s_blocks_per_group;
2573         Vcb->sbi.s_inodes_per_group = sb->s_inodes_per_group;
2574         if (EXT3_INODES_PER_GROUP(&Vcb->sb) == 0) {
2575             Status = STATUS_DISK_CORRUPT_ERROR;
2576             _SEH2_LEAVE;
2577         }
2578         Vcb->sbi.s_inodes_per_block = BLOCK_SIZE / Vcb->InodeSize;
2579         if (Vcb->sbi.s_inodes_per_block == 0) {
2580             Status = STATUS_DISK_CORRUPT_ERROR;
2581             _SEH2_LEAVE;
2582         }
2583         Vcb->sbi.s_itb_per_group = Vcb->sbi.s_inodes_per_group /
2584                                    Vcb->sbi.s_inodes_per_block;
2585 
2586 
2587         Vcb->sbi.s_desc_per_block = BLOCK_SIZE / GROUP_DESC_SIZE;
2588         Vcb->sbi.s_desc_per_block_bits = ilog2(Vcb->sbi.s_desc_per_block);
2589 
2590         for (i=0; i < 4; i++) {
2591             Vcb->sbi.s_hash_seed[i] = sb->s_hash_seed[i];
2592         }
2593         Vcb->sbi.s_def_hash_version = sb->s_def_hash_version;
2594 
2595         if (le32_to_cpu(sb->s_rev_level) == EXT3_GOOD_OLD_REV &&
2596                 (EXT3_HAS_COMPAT_FEATURE(&Vcb->sb, ~0U) ||
2597                  EXT3_HAS_RO_COMPAT_FEATURE(&Vcb->sb, ~0U) ||
2598                  EXT3_HAS_INCOMPAT_FEATURE(&Vcb->sb, ~0U))) {
2599             printk(KERN_WARNING
2600                    "EXT3-fs warning: feature flags set on rev 0 fs, "
2601                    "running e2fsck is recommended\n");
2602         }
2603 
2604         /*
2605          * Check feature flags regardless of the revision level, since we
2606          * previously didn't change the revision level when setting the flags,
2607          * so there is a chance incompat flags are set on a rev 0 filesystem.
2608          */
2609         features = EXT3_HAS_INCOMPAT_FEATURE(&Vcb->sb, ~EXT4_FEATURE_INCOMPAT_SUPP);
2610         if (features & EXT4_FEATURE_INCOMPAT_DIRDATA) {
2611             SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
2612             ClearFlag(features, EXT4_FEATURE_INCOMPAT_DIRDATA);
2613         }
2614         if (features) {
2615             printk(KERN_ERR "EXT3-fs: %s: couldn't mount because of "
2616                    "unsupported optional features (%x).\n",
2617                    Vcb->sb.s_id, le32_to_cpu(features));
2618             Status = STATUS_UNRECOGNIZED_VOLUME;
2619             _SEH2_LEAVE;
2620         }
2621 
2622         features = EXT3_HAS_RO_COMPAT_FEATURE(&Vcb->sb, ~EXT4_FEATURE_RO_COMPAT_SUPP);
2623         if (features) {
2624             printk(KERN_ERR "EXT3-fs: %s: unsupported optional features in this volume: (%x).\n",
2625                    Vcb->sb.s_id, le32_to_cpu(features));
2626             if (CanIWrite(Vcb)) {
2627             } else {
2628                 SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
2629             }
2630         }
2631 
2632         has_huge_files = EXT3_HAS_RO_COMPAT_FEATURE(&Vcb->sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE);
2633 
2634         Vcb->sb.s_maxbytes = ext3_max_size(BLOCK_BITS, has_huge_files);
2635         Vcb->max_bitmap_bytes = ext3_max_bitmap_size(BLOCK_BITS,
2636                                 has_huge_files);
2637         Vcb->max_bytes = ext3_max_size(BLOCK_BITS, has_huge_files);
2638 
2639         /* calculate maximum file bocks ... */
2640         {
2641             ULONG  dwData[EXT2_BLOCK_TYPES] = {EXT2_NDIR_BLOCKS, 1, 1, 1};
2642             ULONG  i;
2643 
2644             ASSERT(BLOCK_BITS == Ext2Log2(BLOCK_SIZE));
2645 
2646             Vcb->sbi.s_groups_count = (ULONG)(ext3_blocks_count(sb) - sb->s_first_data_block +
2647                                               sb->s_blocks_per_group - 1) / sb->s_blocks_per_group;
2648 
2649             Vcb->max_data_blocks = 0;
2650             for (i = 0; i < EXT2_BLOCK_TYPES; i++) {
2651                 if (BLOCK_BITS >= 12 && i == (EXT2_BLOCK_TYPES - 1)) {
2652                     dwData[i] = 0x40000000;
2653                 } else {
2654                     dwData[i] = dwData[i] << ((BLOCK_BITS - 2) * i);
2655                 }
2656                 Vcb->max_blocks_per_layer[i] = dwData[i];
2657                 Vcb->max_data_blocks += Vcb->max_blocks_per_layer[i];
2658             }
2659         }
2660 
2661         Vcb->sbi.s_gdb_count = (Vcb->sbi.s_groups_count + Vcb->sbi.s_desc_per_block - 1) /
2662                                Vcb->sbi.s_desc_per_block;
2663         /* load all gorup desc */
2664         if (!Ext2LoadGroup(Vcb)) {
2665             Status = STATUS_UNSUCCESSFUL;
2666             _SEH2_LEAVE;
2667         }
2668         GroupLoaded = TRUE;
2669 
2670         /* recovery journal since it's ext3 */
2671         if (Vcb->IsExt3fs) {
2672             Ext2RecoverJournal(IrpContext, Vcb);
2673             if (IsFlagOn(Vcb->Flags, VCB_JOURNAL_RECOVER)) {
2674                 SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
2675             }
2676         }
2677 
2678         /* Now allocating the mcb for root ... */
2679         Buffer[0] = L'\\';
2680         Buffer[1] = 0;
2681         RootNode.Buffer = Buffer;
2682         RootNode.MaximumLength = RootNode.Length = 2;
2683         Vcb->McbTree = Ext2AllocateMcb(
2684                            Vcb, &RootNode, NULL,
2685                            FILE_ATTRIBUTE_DIRECTORY
2686                        );
2687         if (!Vcb->McbTree) {
2688             DbgBreak();
2689             Status = STATUS_UNSUCCESSFUL;
2690             _SEH2_LEAVE;
2691         }
2692 
2693         Vcb->sb.s_root = Ext2BuildEntry(Vcb, NULL, &RootNode);
2694         if (!Vcb->sb.s_root) {
2695             DbgBreak();
2696             Status = STATUS_UNSUCCESSFUL;
2697             _SEH2_LEAVE;
2698         }
2699         Vcb->sb.s_root->d_sb = &Vcb->sb;
2700         Vcb->sb.s_root->d_inode = &Vcb->McbTree->Inode;
2701         Vcb->McbTree->de = Vcb->sb.s_root;
2702 
2703         /* load root inode */
2704         Vcb->McbTree->Inode.i_ino = EXT2_ROOT_INO;
2705         Vcb->McbTree->Inode.i_sb = &Vcb->sb;
2706         if (!Ext2LoadInode(Vcb, &Vcb->McbTree->Inode)) {
2707             DbgBreak();
2708             Status = STATUS_CANT_WAIT;
2709             _SEH2_LEAVE;
2710         }
2711 
2712         /* initializeroot node */
2713         Vcb->McbTree->CreationTime = Ext2NtTime(Vcb->McbTree->Inode.i_ctime);
2714         Vcb->McbTree->LastAccessTime = Ext2NtTime(Vcb->McbTree->Inode.i_atime);
2715         Vcb->McbTree->LastWriteTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime);
2716         Vcb->McbTree->ChangeTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime);
2717 
2718         /* check bitmap if user specifies it */
2719         if (IsFlagOn(Ext2Global->Flags, EXT2_CHECKING_BITMAP)) {
2720             Ext2CheckBitmapConsistency(IrpContext, Vcb);
2721         }
2722 
2723         /* get anything doen, then refer target device */
2724         ObReferenceObject(Vcb->TargetDeviceObject);
2725 
2726         /* query parameters from registry */
2727         Ext2PerformRegistryVolumeParams(Vcb);
2728 
2729         SetLongFlag(Vcb->Flags, VCB_INITIALIZED);
2730 
2731     } _SEH2_FINALLY {
2732 
2733         if (!NT_SUCCESS(Status)) {
2734 
2735             if (Vcb->McbTree) {
2736                 Ext2FreeMcb(Vcb, Vcb->McbTree);
2737             }
2738 
2739             if (InodeLookasideInitialized) {
2740                 ExDeleteNPagedLookasideList(&(Vcb->InodeLookasideList));
2741             }
2742 
2743             if (ExtentsInitialized) {
2744                 if (Vcb->bd.bd_bh_cache) {
2745                     if (GroupLoaded)
2746                         Ext2PutGroup(Vcb);
2747                     kmem_cache_destroy(Vcb->bd.bd_bh_cache);
2748                 }
2749                 FsRtlUninitializeLargeMcb(&(Vcb->Extents));
2750             }
2751 
2752             if (Vcb->Volume) {
2753                 if (Vcb->Volume->PrivateCacheMap) {
2754                     Ext2SyncUninitializeCacheMap(Vcb->Volume);
2755                 }
2756                 ObDereferenceObject(Vcb->Volume);
2757             }
2758 
2759             if (NotifySyncInitialized) {
2760                 FsRtlNotifyUninitializeSync(&Vcb->NotifySync);
2761             }
2762 
2763             if (VcbResourceInitialized) {
2764                 ExDeleteResourceLite(&Vcb->FcbLock);
2765                 ExDeleteResourceLite(&Vcb->McbLock);
2766                 ExDeleteResourceLite(&Vcb->MetaInode);
2767                 ExDeleteResourceLite(&Vcb->MetaBlock);
2768                 ExDeleteResourceLite(&Vcb->sbi.s_gd_lock);
2769                 ExDeleteResourceLite(&Vcb->MainResource);
2770                 ExDeleteResourceLite(&Vcb->PagingIoResource);
2771             }
2772         }
2773     } _SEH2_END;
2774 
2775     return Status;
2776 }
2777 
2778 
2779 VOID
2780 Ext2TearDownStream(IN PEXT2_VCB Vcb)
2781 {
2782     PFILE_OBJECT    Stream = Vcb->Volume;
2783     IO_STATUS_BLOCK IoStatus;
2784 
2785     ASSERT(Vcb != NULL);
2786     ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
2787            (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
2788 
2789     if (Stream) {
2790 
2791         Vcb->Volume = NULL;
2792 
2793         if (IsFlagOn(Stream->Flags, FO_FILE_MODIFIED)) {
2794             CcFlushCache(&(Vcb->SectionObject), NULL, 0, &IoStatus);
2795             ClearFlag(Stream->Flags, FO_FILE_MODIFIED);
2796         }
2797 
2798         if (Stream->PrivateCacheMap) {
2799             Ext2SyncUninitializeCacheMap(Stream);
2800         }
2801 
2802         ObDereferenceObject(Stream);
2803     }
2804 }
2805 
2806 VOID
2807 Ext2DestroyVcb (IN PEXT2_VCB Vcb)
2808 {
2809     ASSERT(Vcb != NULL);
2810     ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
2811            (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
2812 
2813     DEBUG(DL_FUN, ("Ext2DestroyVcb ...\n"));
2814 
2815     if (Vcb->Volume) {
2816         Ext2TearDownStream(Vcb);
2817     }
2818     ASSERT(NULL == Vcb->Volume);
2819 
2820     FsRtlNotifyUninitializeSync(&Vcb->NotifySync);
2821     Ext2ListExtents(&Vcb->Extents);
2822     FsRtlUninitializeLargeMcb(&(Vcb->Extents));
2823 
2824     Ext2CleanupAllMcbs(Vcb);
2825 
2826     Ext2DropBH(Vcb);
2827 
2828     if (Vcb->bd.bd_bh_cache)
2829         kmem_cache_destroy(Vcb->bd.bd_bh_cache);
2830     ExDeleteResourceLite(&Vcb->bd.bd_bh_lock);
2831 
2832     if (Vcb->SuperBlock) {
2833         Ext2FreePool(Vcb->SuperBlock, EXT2_SB_MAGIC);
2834         Vcb->SuperBlock = NULL;
2835     }
2836 
2837     if (IsFlagOn(Vcb->Flags, VCB_NEW_VPB)) {
2838         ASSERT(Vcb->Vpb2 != NULL);
2839         DEBUG(DL_DBG, ("Ext2DestroyVcb: Vpb2 to be freed: %p\n", Vcb->Vpb2));
2840         ExFreePoolWithTag(Vcb->Vpb2, TAG_VPB);
2841         DEC_MEM_COUNT(PS_VPB, Vcb->Vpb2, sizeof(VPB));
2842         Vcb->Vpb2 = NULL;
2843     }
2844 
2845     ObDereferenceObject(Vcb->TargetDeviceObject);
2846 
2847     ExDeleteNPagedLookasideList(&(Vcb->InodeLookasideList));
2848     ExDeleteResourceLite(&Vcb->FcbLock);
2849     ExDeleteResourceLite(&Vcb->McbLock);
2850     ExDeleteResourceLite(&Vcb->MetaInode);
2851     ExDeleteResourceLite(&Vcb->MetaBlock);
2852     ExDeleteResourceLite(&Vcb->sbi.s_gd_lock);
2853     ExDeleteResourceLite(&Vcb->PagingIoResource);
2854     ExDeleteResourceLite(&Vcb->MainResource);
2855 
2856     DEBUG(DL_DBG, ("Ext2DestroyVcb: DevObject=%p Vcb=%p\n", Vcb->DeviceObject, Vcb));
2857     IoDeleteDevice(Vcb->DeviceObject);
2858     DEC_MEM_COUNT(PS_VCB, Vcb->DeviceObject, sizeof(EXT2_VCB));
2859 }
2860 
2861 
2862 /* uninitialize cache map */
2863 
2864 VOID
2865 Ext2SyncUninitializeCacheMap (
2866     IN PFILE_OBJECT FileObject
2867 )
2868 {
2869     CACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent;
2870     NTSTATUS WaitStatus;
2871     LARGE_INTEGER Ext2LargeZero = {0,0};
2872 
2873 
2874     KeInitializeEvent( &UninitializeCompleteEvent.Event,
2875                        SynchronizationEvent,
2876                        FALSE);
2877 
2878     CcUninitializeCacheMap( FileObject,
2879                             &Ext2LargeZero,
2880                             &UninitializeCompleteEvent );
2881 
2882     WaitStatus = KeWaitForSingleObject( &UninitializeCompleteEvent.Event,
2883                                         Executive,
2884                                         KernelMode,
2885                                         FALSE,
2886                                         NULL);
2887 
2888     ASSERT (NT_SUCCESS(WaitStatus));
2889 }
2890 
2891 /* Link Mcb to tail of Vcb->McbList queue */
2892 
2893 VOID
2894 Ext2LinkTailMcb(PEXT2_VCB Vcb, PEXT2_MCB Mcb)
2895 {
2896     if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
2897         return;
2898     }
2899 
2900     ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
2901 
2902     if (IsFlagOn(Mcb->Flags, MCB_VCB_LINK)) {
2903         DEBUG(DL_RES, ( "Ext2LinkTailMcb: %wZ already linked.\n",
2904                         &Mcb->FullName));
2905     } else {
2906         InsertTailList(&Vcb->McbList, &Mcb->Link);
2907         SetLongFlag(Mcb->Flags, MCB_VCB_LINK);
2908         Ext2ReferXcb(&Vcb->NumOfMcb);
2909     }
2910 
2911     ExReleaseResourceLite(&Vcb->McbLock);
2912 }
2913 
2914 /* Link Mcb to head of Vcb->McbList queue */
2915 
2916 VOID
2917 Ext2LinkHeadMcb(PEXT2_VCB Vcb, PEXT2_MCB Mcb)
2918 {
2919     if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
2920         return;
2921     }
2922 
2923     ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
2924 
2925     if (!IsFlagOn(Mcb->Flags, MCB_VCB_LINK)) {
2926         InsertHeadList(&Vcb->McbList, &Mcb->Link);
2927         SetLongFlag(Mcb->Flags, MCB_VCB_LINK);
2928         Ext2ReferXcb(&Vcb->NumOfMcb);
2929     } else {
2930         DEBUG(DL_RES, ( "Ext2LinkHeadMcb: %wZ already linked.\n",
2931                         &Mcb->FullName));
2932     }
2933     ExReleaseResourceLite(&Vcb->McbLock);
2934 }
2935 
2936 /* Unlink Mcb from Vcb->McbList queue */
2937 
2938 VOID
2939 Ext2UnlinkMcb(PEXT2_VCB Vcb, PEXT2_MCB Mcb)
2940 {
2941     if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
2942         return;
2943     }
2944 
2945     ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
2946 
2947     if (IsFlagOn(Mcb->Flags, MCB_VCB_LINK)) {
2948         RemoveEntryList(&(Mcb->Link));
2949         ClearLongFlag(Mcb->Flags, MCB_VCB_LINK);
2950         Ext2DerefXcb(&Vcb->NumOfMcb);
2951     } else {
2952         DEBUG(DL_RES, ( "Ext2UnlinkMcb: %wZ already unlinked.\n",
2953                         &Mcb->FullName));
2954     }
2955     ExReleaseResourceLite(&Vcb->McbLock);
2956 }
2957 
2958 /* get the first Mcb record in Vcb->McbList */
2959 
2960 PEXT2_MCB
2961 Ext2FirstUnusedMcb(PEXT2_VCB Vcb, BOOLEAN Wait, ULONG Number)
2962 {
2963     PEXT2_MCB   Head = NULL;
2964     PEXT2_MCB   Tail = NULL;
2965     PEXT2_MCB   Mcb = NULL;
2966     PLIST_ENTRY List = NULL;
2967     ULONG       i = 0;
2968     LARGE_INTEGER   start, now;
2969 
2970     if (!ExAcquireResourceExclusiveLite(&Vcb->McbLock, Wait)) {
2971         return NULL;
2972     }
2973 
2974     KeQuerySystemTime(&start);
2975 
2976     while (Number--) {
2977 
2978         BOOLEAN     Skip = TRUE;
2979 
2980         if (IsListEmpty(&Vcb->McbList)) {
2981             break;
2982         }
2983 
2984         while (i++ < Vcb->NumOfMcb) {
2985 
2986             KeQuerySystemTime(&now);
2987             if (now.QuadPart > start.QuadPart + (LONGLONG)10*1000*1000) {
2988                 break;
2989             }
2990 
2991             List = RemoveHeadList(&Vcb->McbList);
2992             Mcb = CONTAINING_RECORD(List, EXT2_MCB, Link);
2993             ASSERT(IsFlagOn(Mcb->Flags, MCB_VCB_LINK));
2994 
2995             if (Mcb->Fcb == NULL && !IsMcbRoot(Mcb) &&
2996                     Mcb->Refercount == 0 &&
2997                     (Mcb->Child == NULL || IsMcbSymLink(Mcb))) {
2998 
2999                 Ext2RemoveMcb(Vcb, Mcb);
3000                 ClearLongFlag(Mcb->Flags, MCB_VCB_LINK);
3001                 Ext2DerefXcb(&Vcb->NumOfMcb);
3002 
3003                 /* attach all Mcb into a chain*/
3004                 if (Head) {
3005                     ASSERT(Tail != NULL);
3006                     Tail->Next = Mcb;
3007                     Tail = Mcb;
3008                 } else {
3009                     Head = Tail = Mcb;
3010                 }
3011                 Tail->Next = NULL;
3012                 Skip = FALSE;
3013 
3014             } else {
3015 
3016                 InsertTailList(&Vcb->McbList, &Mcb->Link);
3017                 Mcb = NULL;
3018             }
3019         }
3020 
3021         if (Skip)
3022             break;
3023     }
3024 
3025     ExReleaseResourceLite(&Vcb->McbLock);
3026 
3027     return Head;
3028 }
3029 
3030 
3031 /* Reaper thread to release unused Mcb blocks */
3032 VOID NTAPI
3033 Ext2McbReaperThread(
3034     PVOID   Context
3035 )
3036 {
3037     PEXT2_REAPER    Reaper = Context;
3038     PLIST_ENTRY     List = NULL;
3039     LARGE_INTEGER   Timeout;
3040 
3041     PEXT2_VCB       Vcb = NULL;
3042     PEXT2_MCB       Mcb  = NULL;
3043 
3044     ULONG           i, NumOfMcbs;
3045 
3046     BOOLEAN         GlobalAcquired = FALSE;
3047 
3048     BOOLEAN         DidNothing = TRUE;
3049     BOOLEAN         LastState  = TRUE;
3050     BOOLEAN         WaitLock;
3051 
3052     _SEH2_TRY {
3053 
3054         Reaper->Thread = PsGetCurrentThread();
3055 
3056         /* wake up DirverEntry */
3057         KeSetEvent(&Reaper->Engine, 0, FALSE);
3058 
3059         /* now process looping */
3060         while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) {
3061 
3062             WaitLock = FALSE;
3063 
3064             /* calculate how long we need wait */
3065             if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 128)) {
3066                 Timeout.QuadPart = (LONGLONG)-1000*1000; /* 0.1 second */
3067                 NumOfMcbs = Ext2Global->MaxDepth * 4;
3068                 WaitLock = TRUE;
3069             } else if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 32)) {
3070                 Timeout.QuadPart = (LONGLONG)-1000*1000*5; /* 0.5 second */
3071                 NumOfMcbs = Ext2Global->MaxDepth * 2;
3072                 WaitLock = TRUE;
3073             } else if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 8)) {
3074                 Timeout.QuadPart = (LONGLONG)-1000*1000*10; /* 1 second */
3075                 NumOfMcbs = Ext2Global->MaxDepth;
3076             } else if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 2)) {
3077                 Timeout.QuadPart = (LONGLONG)-2*1000*1000*10; /* 2 second */
3078                 NumOfMcbs = Ext2Global->MaxDepth / 4;
3079             } else if (Ext2Global->PerfStat.Current.Mcb > (ULONG)Ext2Global->MaxDepth) {
3080                 Timeout.QuadPart = (LONGLONG)-4*1000*1000*10; /* 4 seconds */
3081                 NumOfMcbs = Ext2Global->MaxDepth / 8;
3082             } else if (DidNothing) {
3083                 Timeout.QuadPart = (LONGLONG)-8*1000*1000*10; /* 8 seconds */
3084                 if (LastState) {
3085                     Timeout.QuadPart *= 2;
3086                 }
3087                 NumOfMcbs = Ext2Global->MaxDepth / 16;
3088             } else {
3089                 Timeout.QuadPart = (LONGLONG)-5*1000*1000*10; /* 5 seconds */
3090                 if (LastState) {
3091                     Timeout.QuadPart *= 2;
3092                 }
3093                 NumOfMcbs = Ext2Global->MaxDepth / 32;
3094             }
3095 
3096             if (NumOfMcbs == 0)
3097                 NumOfMcbs = 1;
3098 
3099             LastState = DidNothing;
3100 
3101             /* wait until it is waken or it times out */
3102             KeWaitForSingleObject(
3103                 &Reaper->Wait,
3104                 Executive,
3105                 KernelMode,
3106                 FALSE,
3107                 &Timeout
3108             );
3109 
3110             if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP))
3111                 break;
3112 
3113             DidNothing = TRUE;
3114 
3115             /* acquire global exclusive lock */
3116             if (!ExAcquireResourceSharedLite(&Ext2Global->Resource, WaitLock)) {
3117                 continue;
3118             }
3119             GlobalAcquired = TRUE;
3120 
3121             /* search all Vcb to get unused resources freed to system */
3122             for (List = Ext2Global->VcbList.Flink;
3123                     List != &(Ext2Global->VcbList);
3124                     List = List->Flink ) {
3125 
3126                 Vcb = CONTAINING_RECORD(List, EXT2_VCB, Next);
3127 
3128                 Mcb = Ext2FirstUnusedMcb(Vcb, WaitLock, NumOfMcbs);
3129                 while (Mcb) {
3130                     PEXT2_MCB   Next = Mcb->Next;
3131                     DEBUG(DL_RES, ( "Ext2ReaperThread: releasing Mcb (%p): %wZ"
3132                                     " Total: %xh\n", Mcb, &Mcb->FullName,
3133                                     Ext2Global->PerfStat.Current.Mcb));
3134                     Ext2FreeMcb(Vcb, Mcb);
3135                     Mcb = Next;
3136                     LastState = DidNothing = FALSE;
3137                 }
3138             }
3139             if (DidNothing) {
3140                 KeClearEvent(&Reaper->Wait);
3141             }
3142             if (GlobalAcquired) {
3143                 ExReleaseResourceLite(&Ext2Global->Resource);
3144                 GlobalAcquired = FALSE;
3145             }
3146         }
3147 
3148     } _SEH2_FINALLY {
3149 
3150         if (GlobalAcquired) {
3151             ExReleaseResourceLite(&Ext2Global->Resource);
3152         }
3153 
3154         KeSetEvent(&Reaper->Engine, 0, FALSE);
3155     } _SEH2_END;
3156 
3157     PsTerminateSystemThread(STATUS_SUCCESS);
3158 }
3159 
3160 
3161 /* get buffer heads from global Vcb BH list */
3162 
3163 BOOLEAN
3164 Ext2QueryUnusedBH(PEXT2_VCB Vcb, PLIST_ENTRY head)
3165 {
3166     struct buffer_head *bh = NULL;
3167     PLIST_ENTRY         next = NULL;
3168     LARGE_INTEGER       start, now;
3169     BOOLEAN             wake = FALSE;
3170 
3171     KeQuerySystemTime(&start);
3172 
3173     ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
3174 
3175     while (!IsListEmpty(&Vcb->bd.bd_bh_free)) {
3176 
3177         KeQuerySystemTime(&now);
3178         if (now.QuadPart > start.QuadPart + (LONGLONG)10*1000*1000) {
3179             break;
3180         }
3181 
3182         next = RemoveHeadList(&Vcb->bd.bd_bh_free);
3183         bh = CONTAINING_RECORD(next, struct buffer_head, b_link);
3184         if (atomic_read(&bh->b_count)) {
3185             InitializeListHead(&bh->b_link);
3186             /* to be inserted by brelse */
3187             continue;
3188         }
3189 
3190         if ( IsFlagOn(Vcb->Flags, VCB_BEING_DROPPED) ||
3191             (bh->b_ts_drop.QuadPart + (LONGLONG)10*1000*1000*15) > now.QuadPart ||
3192             (bh->b_ts_creat.QuadPart + (LONGLONG)10*1000*1000*180) > now.QuadPart) {
3193             InsertTailList(head, &bh->b_link);
3194             buffer_head_remove(&Vcb->bd, bh);
3195         } else {
3196             InsertHeadList(&Vcb->bd.bd_bh_free, &bh->b_link);
3197             break;
3198         }
3199     }
3200 
3201     wake = IsListEmpty(&Vcb->bd.bd_bh_free);
3202     ExReleaseResourceLite(&Vcb->bd.bd_bh_lock);
3203 
3204     if (wake)
3205         KeSetEvent(&Vcb->bd.bd_bh_notify, 0, FALSE);
3206 
3207     return IsFlagOn(Vcb->Flags, VCB_BEING_DROPPED);
3208 }
3209 
3210 
3211 /* Reaper thread to release unused buffer heads */
3212 VOID NTAPI
3213 Ext2bhReaperThread(
3214     PVOID   Context
3215 )
3216 {
3217     PEXT2_REAPER    Reaper = Context;
3218     PEXT2_VCB       Vcb = NULL;
3219     LIST_ENTRY      List, *Link;
3220     LARGE_INTEGER   Timeout;
3221 
3222     BOOLEAN         GlobalAcquired = FALSE;
3223     BOOLEAN         DidNothing = FALSE;
3224     BOOLEAN         NonWait = FALSE;
3225 
3226     _SEH2_TRY {
3227 
3228         Reaper->Thread = PsGetCurrentThread();
3229 
3230         /* wake up DirverEntry */
3231         KeSetEvent(&Reaper->Engine, 0, FALSE);
3232 
3233         /* now process looping */
3234         while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) {
3235 
3236             /* wait until it is waken or it times out */
3237             if (NonWait) {
3238                 Timeout.QuadPart = (LONGLONG)-10*1000*10;
3239                 NonWait = FALSE;
3240             } else if (DidNothing) {
3241                 Timeout.QuadPart = Timeout.QuadPart * 2;
3242             } else {
3243                 Timeout.QuadPart = (LONGLONG)-10*1000*1000*10; /* 10 seconds */
3244             }
3245             KeWaitForSingleObject(
3246                 &Reaper->Wait,
3247                 Executive,
3248                 KernelMode,
3249                 FALSE,
3250                 &Timeout
3251             );
3252 
3253             if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP))
3254                 break;
3255 
3256             InitializeListHead(&List);
3257 
3258             /* acquire global exclusive lock */
3259             ExAcquireResourceSharedLite(&Ext2Global->Resource, TRUE);
3260             GlobalAcquired = TRUE;
3261             /* search all Vcb to get unused resources freed to system */
3262             for (Link = Ext2Global->VcbList.Flink;
3263                  Link != &(Ext2Global->VcbList);
3264                  Link = Link->Flink ) {
3265 
3266                 Vcb = CONTAINING_RECORD(Link, EXT2_VCB, Next);
3267                 NonWait = Ext2QueryUnusedBH(Vcb, &List);
3268             }
3269             DidNothing = IsListEmpty(&List);
3270             if (DidNothing) {
3271                 KeClearEvent(&Reaper->Wait);
3272             }
3273             if (GlobalAcquired) {
3274                 ExReleaseResourceLite(&Ext2Global->Resource);
3275                 GlobalAcquired = FALSE;
3276             }
3277 
3278             while (!IsListEmpty(&List)) {
3279                 struct buffer_head *bh;
3280                 Link = RemoveHeadList(&List);
3281                 bh = CONTAINING_RECORD(Link, struct buffer_head, b_link);
3282                 ASSERT(0 == atomic_read(&bh->b_count));
3283                 free_buffer_head(bh);
3284             }
3285         }
3286 
3287     } _SEH2_FINALLY {
3288 
3289         if (GlobalAcquired) {
3290             ExReleaseResourceLite(&Ext2Global->Resource);
3291         }
3292 
3293         KeSetEvent(&Reaper->Engine, 0, FALSE);
3294     } _SEH2_END;
3295 
3296     PsTerminateSystemThread(STATUS_SUCCESS);
3297 }
3298 
3299 /* get unused Fcbs to free */
3300 
3301 BOOLEAN
3302 Ext2QueryUnusedFcb(PEXT2_VCB Vcb, PLIST_ENTRY list)
3303 {
3304     PEXT2_FCB       Fcb;
3305     PLIST_ENTRY     next = NULL;
3306     LARGE_INTEGER   start, now;
3307 
3308     ULONG           count = 0;
3309     ULONG           tries = 0;
3310     BOOLEAN         wake = FALSE;
3311     BOOLEAN         retry = TRUE;
3312 
3313     KeQuerySystemTime(&start);
3314 
3315     ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
3316 
3317 again:
3318 
3319     KeQuerySystemTime(&now);
3320     while (!IsListEmpty(&Vcb->FcbList)) {
3321 
3322         next = RemoveHeadList(&Vcb->FcbList);
3323         Fcb = CONTAINING_RECORD(next, EXT2_FCB, Next);
3324 
3325         if (Fcb->ReferenceCount > 0) {
3326             InsertTailList(&Vcb->FcbList, &Fcb->Next);
3327             break;
3328         }
3329 
3330         retry = FALSE;
3331 
3332         if (now.QuadPart < Fcb->TsDrop.QuadPart + 10*1000*1000*120) {
3333             InsertHeadList(&Vcb->FcbList, &Fcb->Next);
3334             break;
3335         }
3336 
3337         Ext2UnlinkFcb(Fcb);
3338         Ext2DerefXcb(&Vcb->FcbCount);
3339         InsertTailList(list, &Fcb->Next);
3340         if (++count >= Ext2Global->MaxDepth) {
3341             break;
3342         }
3343     }
3344 
3345     if (start.QuadPart + 10*1000*1000 > now.QuadPart) {
3346         retry = FALSE;
3347     }
3348 
3349     if (retry) {
3350         if (++tries < (Vcb->FcbCount >> 4) )
3351             goto again;
3352     }
3353 
3354     ExReleaseResourceLite(&Vcb->FcbLock);
3355 
3356     return 0;
3357 }
3358 
3359 /* Reaper thread to release Fcb */
3360 VOID NTAPI
3361 Ext2FcbReaperThread(
3362     PVOID   Context
3363 )
3364 {
3365     PEXT2_REAPER    Reaper = Context;
3366     PEXT2_VCB       Vcb = NULL;
3367     LIST_ENTRY      List, *Link;
3368     LARGE_INTEGER   Timeout;
3369 
3370     BOOLEAN         GlobalAcquired = FALSE;
3371     BOOLEAN         DidNothing = FALSE;
3372     BOOLEAN         NonWait = FALSE;
3373 
3374     _SEH2_TRY {
3375 
3376         Reaper->Thread = PsGetCurrentThread();
3377 
3378         /* wake up DirverEntry */
3379         KeSetEvent(&Reaper->Engine, 0, FALSE);
3380 
3381         /* now process looping */
3382         while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) {
3383 
3384             /* wait until it is waken or it times out */
3385             if (NonWait) {
3386                 Timeout.QuadPart = (LONGLONG)-10*1000*100;
3387                 NonWait = FALSE;
3388             } else if (DidNothing) {
3389                 Timeout.QuadPart = Timeout.QuadPart * 2;
3390             } else {
3391                 Timeout.QuadPart = (LONGLONG)-10*1000*1000*20; /* 20 seconds */
3392             }
3393             KeWaitForSingleObject(
3394                 &Reaper->Wait,
3395                 Executive,
3396                 KernelMode,
3397                 FALSE,
3398                 &Timeout
3399             );
3400 
3401             if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP))
3402                 break;
3403 
3404             InitializeListHead(&List);
3405 
3406             /* acquire global exclusive lock */
3407             ExAcquireResourceSharedLite(&Ext2Global->Resource, TRUE);
3408             GlobalAcquired = TRUE;
3409             /* search all Vcb to get unused resources freed to system */
3410             for (Link  = Ext2Global->VcbList.Flink;
3411                  Link != &(Ext2Global->VcbList);
3412                  Link  = Link->Flink ) {
3413 
3414                 Vcb = CONTAINING_RECORD(Link, EXT2_VCB, Next);
3415                 NonWait = Ext2QueryUnusedFcb(Vcb, &List);
3416             }
3417             DidNothing = IsListEmpty(&List);
3418             if (DidNothing) {
3419                 KeClearEvent(&Reaper->Wait);
3420             }
3421             if (GlobalAcquired) {
3422                 ExReleaseResourceLite(&Ext2Global->Resource);
3423                 GlobalAcquired = FALSE;
3424             }
3425 
3426             while (!IsListEmpty(&List)) {
3427                 PEXT2_FCB  Fcb;
3428                 Link = RemoveHeadList(&List);
3429                 Fcb = CONTAINING_RECORD(Link, EXT2_FCB, Next);
3430                 ASSERT(0 == Fcb->ReferenceCount);
3431                 Ext2FreeFcb(Fcb);
3432             }
3433         }
3434 
3435     } _SEH2_FINALLY {
3436 
3437         if (GlobalAcquired) {
3438             ExReleaseResourceLite(&Ext2Global->Resource);
3439         }
3440 
3441         KeSetEvent(&Reaper->Engine, 0, FALSE);
3442     } _SEH2_END;
3443 
3444     PsTerminateSystemThread(STATUS_SUCCESS);
3445 }
3446 
3447 NTSTATUS
3448 Ext2StartReaper(PEXT2_REAPER Reaper, EXT2_REAPER_RELEASE Free)
3449 {
3450     NTSTATUS status = STATUS_SUCCESS;
3451     OBJECT_ATTRIBUTES  oa;
3452     HANDLE   handle = 0;
3453     LARGE_INTEGER timeout;
3454 
3455     Reaper->Free = Free;
3456 
3457     /* initialize wait event */
3458     KeInitializeEvent(
3459         &Reaper->Wait,
3460         SynchronizationEvent, FALSE
3461     );
3462 
3463     /* Reaper thread engine event */
3464     KeInitializeEvent(
3465         &Reaper->Engine,
3466         SynchronizationEvent, FALSE
3467     );
3468 
3469     /* initialize oa */
3470     InitializeObjectAttributes(
3471         &oa,
3472         NULL,
3473         OBJ_CASE_INSENSITIVE |
3474         OBJ_KERNEL_HANDLE,
3475         NULL,
3476         NULL
3477     );
3478 
3479     /* start a new system thread */
3480     status = PsCreateSystemThread(
3481                  &handle,
3482                  0,
3483                  &oa,
3484                  NULL,
3485                  NULL,
3486                  Free,
3487                  (PVOID)Reaper
3488              );
3489 
3490     if (NT_SUCCESS(status)) {
3491         ZwClose(handle);
3492 
3493         /* make sure Reaperthread is started */
3494         timeout.QuadPart = (LONGLONG)-10*1000*1000*2; /* 2 seconds */
3495         status = KeWaitForSingleObject(
3496                      &Reaper->Engine,
3497                      Executive,
3498                      KernelMode,
3499                      FALSE,
3500                      &timeout
3501                  );
3502         if (status != STATUS_SUCCESS) {
3503             status = STATUS_INSUFFICIENT_RESOURCES;
3504         }
3505     }
3506 
3507     return status;
3508 }
3509 
3510 
3511 VOID NTAPI
3512 Ext2StopReaper(PEXT2_REAPER Reaper)
3513 {
3514     LARGE_INTEGER timeout;
3515 
3516     Reaper->Flags |= EXT2_REAPER_FLAG_STOP;
3517     KeSetEvent(&Reaper->Wait, 0, FALSE);
3518 
3519     /* make sure Reaperthread is started */
3520     timeout.QuadPart = (LONGLONG)-10*1000*1000*2; /* 2 seconds */
3521     KeWaitForSingleObject(
3522                      &Reaper->Engine,
3523                      Executive,
3524                      KernelMode,
3525                      FALSE,
3526                      &timeout);
3527 }
3528