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