[ros-diffs] [arty] 44180: Make AVL generic table correctly report that it's inserted a new node, and fix non-new insert slightly. If we unstub filelock and oplock, we can cmd line browse an ext3 fs with matt wu's ext2fsd (win2k build, from the website). It throws STATUS_IN_PAGE_ERROR back up to explorer while browsing, probably because of stubbed functions, but doesn't bugcheck. Implementing just a bit more fsrtl will complete it.

arty at svn.reactos.org arty at svn.reactos.org
Sun Nov 15 22:59:06 CET 2009


Author: arty
Date: Sun Nov 15 22:59:06 2009
New Revision: 44180

URL: http://svn.reactos.org/svn/reactos?rev=44180&view=rev
Log:
Make AVL generic table correctly report that it's inserted a new node, and fix non-new
insert slightly.  If we unstub filelock and oplock, we can cmd line browse an ext3 fs
with matt wu's ext2fsd (win2k build, from the website).  It throws STATUS_IN_PAGE_ERROR
back up to explorer while browsing, probably because of stubbed functions, but doesn't
bugcheck.  Implementing just a bit more fsrtl will complete it.

Modified:
    branches/arty-newcc/lib/rtl/generictable.c
    branches/arty-newcc/ntoskrnl/fsrtl/largemcb.c

Modified: branches/arty-newcc/lib/rtl/generictable.c
URL: http://svn.reactos.org/svn/reactos/branches/arty-newcc/lib/rtl/generictable.c?rev=44180&r1=44179&r2=44180&view=diff
==============================================================================
--- branches/arty-newcc/lib/rtl/generictable.c [iso-8859-1] (original)
+++ branches/arty-newcc/lib/rtl/generictable.c [iso-8859-1] Sun Nov 15 22:59:06 2009
@@ -134,6 +134,8 @@
     /* Get the splay links and table search result immediately */
     Result = RtlpFindGenericTableNodeOrParent(Table, Buffer, &NodeOrParent);
 
+	DPRINT1("Result %d\n", Result);
+
     /* Now call the routine to do the full insert */
     return RtlInsertElementGenericTableFull(Table,
                                             Buffer,
@@ -689,14 +691,7 @@
 	if(NodeOrParent) *NodeOrParent = OurNodeOrParent;
 	if(SearchResult) *SearchResult = OurSearchResult;
 
-	if(OurSearchResult == TableFoundNode)
-	{
-		RtlDeleteElementGenericTableAvl(Table, Buffer);
-		return RtlInsertElementGenericTableFullAvl
-			(Table, Buffer, BufferSize,
-			 NewElement, NodeOrParent, SearchResult);
-	}
-	else
+	if(OurSearchResult != TableFoundNode)
 	{
 		PRTL_BALANCED_LINKS NewNode =
 			Table->AllocateRoutine
@@ -711,8 +706,12 @@
 		OurNodeOrParent = NewNode;
 
 		avl_insert_node(Table, NewNode);
+		if (NewElement) *NewElement = TRUE;
 		return avl_data(NewNode);
 	}
+	
+	if (NewElement) *NewElement = FALSE;
+	return avl_data(OurNodeOrParent);
 }
 
 /*

Modified: branches/arty-newcc/ntoskrnl/fsrtl/largemcb.c
URL: http://svn.reactos.org/svn/reactos/branches/arty-newcc/ntoskrnl/fsrtl/largemcb.c?rev=44180&r1=44179&r2=44180&view=diff
==============================================================================
--- branches/arty-newcc/ntoskrnl/fsrtl/largemcb.c [iso-8859-1] (original)
+++ branches/arty-newcc/ntoskrnl/fsrtl/largemcb.c [iso-8859-1] Sun Nov 15 22:59:06 2009
@@ -1,358 +1,900 @@
-/*
- * PROJECT:         ReactOS Kernel
- * LICENSE:         GPL - See COPYING in the top level directory
- * FILE:            ntoskrnl/fsrtl/largemcb.c
- * PURPOSE:         Mapping Control Block (MCB) support for File System Drivers
- * PROGRAMMERS:     Alex Ionescu (alex.ionescu at reactos.org)
- */
-
-/* INCLUDES ******************************************************************/
-
-#include <ntoskrnl.h>
-#define NDEBUG
-#include <debug.h>
-
-/* PUBLIC FUNCTIONS **********************************************************/
-
-/*
- * @unimplemented
- */
-BOOLEAN
-NTAPI
-FsRtlAddLargeMcbEntry(IN PLARGE_MCB Mcb,
-                      IN LONGLONG Vbn,
-                      IN LONGLONG Lbn,
-                      IN LONGLONG SectorCount)
-{
-    KeBugCheck(FILE_SYSTEM);
-    return FALSE;
-}
-
-/*
- * @implemented
- */
-BOOLEAN
-NTAPI
-FsRtlAddMcbEntry(IN PMCB Mcb,
-                 IN VBN Vbn,
-                 IN LBN Lbn,
-                 IN ULONG SectorCount)
-{
-    /* Call the newer function */
-    return FsRtlAddLargeMcbEntry(&Mcb->
-                                 DummyFieldThatSizesThisStructureCorrectly,
-                                 (LONGLONG)Vbn,
-                                 (LONGLONG)Lbn,
-                                 (LONGLONG)SectorCount);
-}
-
-/*
- * @unimplemented
- */
-BOOLEAN
-NTAPI
-FsRtlGetNextLargeMcbEntry(IN PLARGE_MCB Mcb,
-                          IN ULONG RunIndex,
-                          OUT PLONGLONG Vbn,
-                          OUT PLONGLONG Lbn,
-                          OUT PLONGLONG SectorCount)
-{
-    KeBugCheck(FILE_SYSTEM);
-    *Vbn = 0;
-    *Lbn = 0;
-    *SectorCount= 0;
-    return FALSE;
-}
-
-/*
- * @implemented
- */
-BOOLEAN
-NTAPI
-FsRtlGetNextMcbEntry(IN PMCB Mcb,
-                     IN ULONG RunIndex,
-                     OUT PVBN Vbn,
-                     OUT PLBN Lbn,
-                     OUT PULONG SectorCount)
-{
-    BOOLEAN Return = FALSE;
-    LONGLONG llVbn;
-    LONGLONG llLbn;
-    LONGLONG llSectorCount;
-
-    /* Call the Large version */
-    Return = FsRtlGetNextLargeMcbEntry(
-        &Mcb->DummyFieldThatSizesThisStructureCorrectly,
-        RunIndex,
-        &llVbn,
-        &llLbn,
-        &llSectorCount);
-
-    /* Return the lower 32 bits */
-    *Vbn = (ULONG)llVbn;
-    *Lbn = (ULONG)llLbn;
-    *SectorCount = (ULONG)llSectorCount;
-
-    /* And return the original value */
-    return Return;
-}
-
-/*
- * @unimplemented
- */
-VOID
-NTAPI
-FsRtlInitializeLargeMcb(IN PLARGE_MCB Mcb,
-                        IN POOL_TYPE PoolType)
-{
-    KeBugCheck(FILE_SYSTEM);
-}
-
-/*
- * @implemented
- */
-VOID
-NTAPI
-FsRtlInitializeMcb(IN PMCB Mcb,
-                   IN POOL_TYPE PoolType)
-{
-    /* Call the newer function */
-    FsRtlInitializeLargeMcb(&Mcb->DummyFieldThatSizesThisStructureCorrectly,
-                            PoolType);
-}
-
-/*
- * @unimplemented
- */
-BOOLEAN
-NTAPI
-FsRtlLookupLargeMcbEntry(IN PLARGE_MCB Mcb,
-                         IN LONGLONG Vbn,
-                         OUT PLONGLONG Lbn OPTIONAL,
-                         OUT PLONGLONG SectorCountFromLbn OPTIONAL,
-                         OUT PLONGLONG StartingLbn OPTIONAL,
-                         OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL,
-                         OUT PULONG Index OPTIONAL)
-{
-    KeBugCheck(FILE_SYSTEM);
-    *Lbn = 0;
-    *SectorCountFromLbn = 0;
-    return FALSE;
-}
-
-/*
- * @unimplemented
- */
-BOOLEAN
-NTAPI
-FsRtlLookupLastLargeMcbEntryAndIndex(IN PLARGE_MCB OpaqueMcb,
-                                     OUT PLONGLONG LargeVbn,
-                                     OUT PLONGLONG LargeLbn,
-                                     OUT PULONG Index)
-{
-    KeBugCheck(FILE_SYSTEM);
-    *LargeVbn = 0;
-    *LargeLbn = 0;
-    *Index = 0;
-    return FALSE;
-}
-
-/*
- * @unimplemented
- */
-BOOLEAN
-NTAPI
-FsRtlLookupLastLargeMcbEntry(IN PLARGE_MCB Mcb,
-                             OUT PLONGLONG Vbn,
-                             OUT PLONGLONG Lbn)
-{
-    KeBugCheck(FILE_SYSTEM);
-    return(FALSE);
-}
-
-/*
- * @implemented
- */
-BOOLEAN
-NTAPI
-FsRtlLookupLastMcbEntry(IN PMCB Mcb,
-                        OUT PVBN Vbn,
-                        OUT PLBN Lbn)
-{
-    BOOLEAN Return = FALSE;
-    LONGLONG llVbn = 0;
-    LONGLONG llLbn = 0;
-
-    /* Call the Large version */
-    Return = FsRtlLookupLastLargeMcbEntry(
-        &Mcb->DummyFieldThatSizesThisStructureCorrectly,
-        &llVbn,
-        &llLbn);
-
-    /* Return the lower 32-bits */
-    *Vbn = (ULONG)llVbn;
-    *Lbn = (ULONG)llLbn;
-
-    /* And return the original value */
-    return Return;
-}
-
-/*
- * @implemented
- */
-BOOLEAN
-NTAPI
-FsRtlLookupMcbEntry(IN PMCB Mcb,
-                    IN VBN Vbn,
-                    OUT PLBN Lbn,
-                    OUT PULONG SectorCount OPTIONAL,
-                    OUT PULONG Index)
-{
-    BOOLEAN Return = FALSE;
-    LONGLONG llLbn;
-    LONGLONG llSectorCount;
-
-    /* Call the Large version */
-    Return = FsRtlLookupLargeMcbEntry(&Mcb->
-                                      DummyFieldThatSizesThisStructureCorrectly,
-                                      (LONGLONG)Vbn,
-                                      &llLbn,
-                                      &llSectorCount,
-                                      NULL,
-                                      NULL,
-                                      Index);
-
-    /* Return the lower 32-bits */
-    *Lbn = (ULONG)llLbn;
-    if (SectorCount) *SectorCount = (ULONG)llSectorCount;
-
-    /* And return the original value */
-    return Return;
-}
-
-/*
- * @implemented
- */
-ULONG
-NTAPI
-FsRtlNumberOfRunsInLargeMcb(IN PLARGE_MCB Mcb)
-{
-    ULONG NumberOfRuns;
-
-    /* Read the number of runs while holding the MCB lock */
-    KeAcquireGuardedMutex(Mcb->GuardedMutex);
-    NumberOfRuns = Mcb->BaseMcb.PairCount;
-    KeReleaseGuardedMutex(Mcb->GuardedMutex);
-
-    /* Return the count */
-    return NumberOfRuns;
-}
-
-/*
- * @implemented
- */
-ULONG
-NTAPI
-FsRtlNumberOfRunsInMcb (IN PMCB Mcb)
-{
-    /* Call the newer function */
-    return FsRtlNumberOfRunsInLargeMcb(
-        &Mcb->DummyFieldThatSizesThisStructureCorrectly);
-}
-
-/*
- * @unimplemented
- */
-VOID
-NTAPI
-FsRtlRemoveLargeMcbEntry(IN PLARGE_MCB Mcb,
-                         IN LONGLONG Vbn,
-                         IN LONGLONG SectorCount)
-{
-    KeBugCheck(FILE_SYSTEM);
-}
-
-/*
- * @implemented
- */
-VOID
-NTAPI
-FsRtlRemoveMcbEntry(IN PMCB Mcb,
-                    IN VBN Vbn,
-                    IN ULONG SectorCount)
-{
-    /* Call the large function */
-    FsRtlRemoveLargeMcbEntry(&Mcb->DummyFieldThatSizesThisStructureCorrectly,
-                             (LONGLONG)Vbn,
-                             (LONGLONG)SectorCount);
-}
-
-/*
- * @unimplemented
- */
-VOID
-NTAPI
-FsRtlResetLargeMcb(IN PLARGE_MCB Mcb,
-                   IN BOOLEAN SelfSynchronized)
-{
-    KeBugCheck(FILE_SYSTEM);
-}
-
-/*
- * @unimplemented
- */
-BOOLEAN
-NTAPI
-FsRtlSplitLargeMcb(IN PLARGE_MCB Mcb,
-                   IN LONGLONG Vbn,
-                   IN LONGLONG Amount)
-{
-    KeBugCheck(FILE_SYSTEM);
-    return FALSE;
-}
-
-/*
- * @unimplemented
- */
-VOID
-NTAPI
-FsRtlTruncateLargeMcb(IN PLARGE_MCB Mcb,
-                      IN LONGLONG Vbn)
-{
-    KeBugCheck(FILE_SYSTEM);
-}
-
-/*
- * @implemented
- */
-VOID
-NTAPI
-FsRtlTruncateMcb (IN PMCB Mcb,
-                  IN VBN  Vbn)
-{
-    /* Call the newer function */
-    FsRtlTruncateLargeMcb(&Mcb->DummyFieldThatSizesThisStructureCorrectly,
-                          (LONGLONG)Vbn);
-}
-
-/*
- * @unimplemented
- */
-VOID
-NTAPI
-FsRtlUninitializeLargeMcb(IN PLARGE_MCB Mcb)
-{
-    KeBugCheck(FILE_SYSTEM);
-}
-
-/*
- * @implemented
- */
-VOID
-NTAPI
-FsRtlUninitializeMcb(IN PMCB Mcb)
-{
-    /* Call the newer function */
-    FsRtlUninitializeLargeMcb(&Mcb->DummyFieldThatSizesThisStructureCorrectly);
-}
-
+/*
+ * PROJECT:         ReactOS Kernel
+ * LICENSE:         GPL - See COPYING in the top level directory
+ * FILE:            ntoskrnl/fsrtl/largemcb.c
+ * PURPOSE:         Large Mapped Control Block (MCB) support for File System Drivers
+ * PROGRAMMERS:     Alex Ionescu (alex.ionescu at reactos.org)
+ *                  Pierre Schweitzer (heis_spiter at hotmail.com) 
+ *                  Art Yerkes (art.yerkes at gmail.com)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <ntoskrnl.h>
+//#define NDEBUG
+#include <debug.h>
+
+/* GLOBALS *******************************************************************/
+
+#define GET_LIST_HEAD(x) ((PLIST_ENTRY)(&((PRTL_GENERIC_TABLE)x)[1]))
+
+PAGED_LOOKASIDE_LIST FsRtlFirstMappingLookasideList;
+NPAGED_LOOKASIDE_LIST FsRtlFastMutexLookasideList;
+
+typedef struct _LARGE_MCB_MAPPING_ENTRY
+{
+	LARGE_INTEGER RunStartVbn;
+	LARGE_INTEGER SectorCount;
+	LARGE_INTEGER StartingLbn;
+	LIST_ENTRY Sequence;
+} LARGE_MCB_MAPPING_ENTRY, *PLARGE_MCB_MAPPING_ENTRY;
+
+static PVOID NTAPI McbMappingAllocate(PRTL_GENERIC_TABLE Table, CLONG Bytes)
+{
+	PVOID Result;
+	PBASE_MCB Mcb = (PBASE_MCB)Table->TableContext;
+	Result = ExAllocatePoolWithTag(Mcb->PoolType, Bytes, 'LMCB');
+	DPRINT("McbMappingAllocate(%d) => %p\n", Bytes, Result);
+	return Result;
+}
+
+static VOID NTAPI McbMappingFree(PRTL_GENERIC_TABLE Table, PVOID Buffer)
+{
+	DPRINT("McbMappingFree(%p)\n", Buffer);
+	ExFreePoolWithTag(Buffer, 'LMCB');
+}
+
+static RTL_GENERIC_COMPARE_RESULTS NTAPI McbMappingCompare
+(RTL_GENERIC_TABLE Table, PVOID PtrA, PVOID PtrB)
+{
+	PLARGE_MCB_MAPPING_ENTRY A = PtrA, B = PtrB;
+	return 
+		(A->RunStartVbn.QuadPart + A->SectorCount.QuadPart <
+		 B->RunStartVbn.QuadPart) ? GenericLessThan :
+		(A->RunStartVbn.QuadPart > 
+		 B->RunStartVbn.QuadPart + B->SectorCount.QuadPart) ? 
+		GenericGreaterThan : GenericEqual;
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+FsRtlAddBaseMcbEntry(IN PBASE_MCB Mcb,
+                     IN LONGLONG Vbn,
+                     IN LONGLONG Lbn,
+                     IN LONGLONG SectorCount)
+{
+	LARGE_MCB_MAPPING_ENTRY Node;
+	PLARGE_MCB_MAPPING_ENTRY Existing = NULL;
+	BOOLEAN NewElement = FALSE;
+
+	Node.RunStartVbn.QuadPart = Vbn;
+	Node.StartingLbn.QuadPart = Lbn;
+	Node.SectorCount.QuadPart = SectorCount;
+
+	while (!NewElement)
+	{
+		DPRINT("Inserting %x:%x\n", Node.RunStartVbn.LowPart, Node.SectorCount.LowPart);
+		Existing = RtlInsertElementGenericTable
+			(Mcb->Mapping, &Node, sizeof(Node), &NewElement);
+		DPRINT("Existing %x\n", Existing);
+		if (!Existing) break;
+
+		DPRINT("NewElement %d\n", NewElement);
+		if (!NewElement)
+		{
+			// We merge the existing runs
+			LARGE_INTEGER StartVbn, FinalVbn;
+			DPRINT("Existing: %x:%x\n", 
+				   Existing->RunStartVbn.LowPart, Node.SectorCount.LowPart);
+			if (Existing->RunStartVbn.QuadPart < Node.RunStartVbn.QuadPart)
+			{
+				StartVbn = Existing->RunStartVbn;
+				Node.StartingLbn = Existing->StartingLbn;
+			}
+			else
+			{
+				StartVbn = Node.RunStartVbn;
+			}
+			DPRINT("StartVbn %x\n", StartVbn.LowPart);
+			if (Existing->RunStartVbn.QuadPart + Existing->SectorCount.QuadPart >
+				Node.RunStartVbn.QuadPart + Node.SectorCount.QuadPart)
+			{
+				FinalVbn.QuadPart = 
+					Existing->RunStartVbn.QuadPart + Existing->SectorCount.QuadPart;
+			}
+			else
+			{
+				FinalVbn.QuadPart =
+					Node.RunStartVbn.QuadPart + Node.SectorCount.QuadPart;
+			}
+			DPRINT("FinalVbn %x\n", FinalVbn.LowPart);
+			Node.RunStartVbn.QuadPart = StartVbn.QuadPart;
+			Node.SectorCount.QuadPart = FinalVbn.QuadPart - StartVbn.QuadPart;
+			RemoveHeadList(&Existing->Sequence);
+			RtlDeleteElementGenericTable(Mcb->Mapping, Existing);
+			Mcb->PairCount--;
+		}
+		else
+		{
+			DPRINT("Mapping added %x\n", Existing);
+			Mcb->MaximumPairCount++;
+			Mcb->PairCount++;
+			InsertHeadList(GET_LIST_HEAD(Mcb->Mapping), &Existing->Sequence);
+		}
+	}
+
+	DPRINT("!!Existing %d\n", !!Existing);
+	return !!Existing;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+FsRtlAddLargeMcbEntry(IN PLARGE_MCB Mcb,
+                      IN LONGLONG Vbn,
+                      IN LONGLONG Lbn,
+                      IN LONGLONG SectorCount)
+{
+    BOOLEAN Result;
+
+	DPRINT("Mcb %x Vbn %x Lbn %x SectorCount %x\n", Mcb, Vbn, Lbn, SectorCount);
+
+    KeAcquireGuardedMutex(Mcb->GuardedMutex);
+    Result = FsRtlAddBaseMcbEntry(&(Mcb->BaseMcb),
+                                  Vbn,
+                                  Lbn,
+                                  SectorCount);
+    KeReleaseGuardedMutex(Mcb->GuardedMutex);
+
+	DPRINT("Done %d\n", Result);
+
+    return Result;
+}
+
+/*
+ * @unimplemented
+ */
+BOOLEAN
+NTAPI
+FsRtlGetNextBaseMcbEntry(IN PBASE_MCB Mcb,
+                         IN ULONG RunIndex,
+                         OUT PLONGLONG Vbn,
+                         OUT PLONGLONG Lbn,
+                         OUT PLONGLONG SectorCount)
+{
+	ULONG i = 0;
+	BOOLEAN Result = FALSE;
+	PLARGE_MCB_MAPPING_ENTRY Entry;
+	for (Entry = (PLARGE_MCB_MAPPING_ENTRY)
+			 RtlEnumerateGenericTable(Mcb->Mapping, TRUE);
+		 Entry && i < RunIndex;
+		 Entry = (PLARGE_MCB_MAPPING_ENTRY)
+			 RtlEnumerateGenericTable(Mcb->Mapping, FALSE), i++);
+	if (Entry)
+	{
+		Result = TRUE;
+		if (Vbn)
+			*Vbn = Entry->RunStartVbn.QuadPart;
+		if (Lbn)
+			*Lbn = Entry->StartingLbn.QuadPart;
+		if (SectorCount)
+			*SectorCount = Entry->SectorCount.QuadPart;
+	}
+
+	return Result;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+FsRtlGetNextLargeMcbEntry(IN PLARGE_MCB Mcb,
+                          IN ULONG RunIndex,
+                          OUT PLONGLONG Vbn,
+                          OUT PLONGLONG Lbn,
+                          OUT PLONGLONG SectorCount)
+{
+    BOOLEAN Result;
+
+	DPRINT("FsRtlGetNextLargeMcbEntry Mcb %x RunIndex %x\n", Mcb, RunIndex);
+
+    KeAcquireGuardedMutex(Mcb->GuardedMutex);
+    Result = FsRtlGetNextBaseMcbEntry(&(Mcb->BaseMcb),
+                                      RunIndex,
+                                      Vbn,
+                                      Lbn,
+                                      SectorCount);
+    KeReleaseGuardedMutex(Mcb->GuardedMutex);
+
+	DPRINT("Done %d\n", Result);
+
+    return Result;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+FsRtlInitializeBaseMcb(IN PBASE_MCB Mcb,
+                       IN POOL_TYPE PoolType)
+{
+    Mcb->PairCount = 0;
+
+    if (PoolType == PagedPool)
+    {
+        Mcb->Mapping = ExAllocateFromPagedLookasideList(&FsRtlFirstMappingLookasideList);
+    }
+    else
+    {
+        Mcb->Mapping = ExAllocatePoolWithTag(PoolType | POOL_RAISE_IF_ALLOCATION_FAILURE,
+											 sizeof(RTL_GENERIC_TABLE) + sizeof(LIST_ENTRY),
+                                             'FSBC');
+    }
+
+    Mcb->PoolType = PoolType;
+    Mcb->MaximumPairCount = MAXIMUM_PAIR_COUNT;
+	RtlInitializeGenericTable
+		(Mcb->Mapping,
+		 (PRTL_GENERIC_COMPARE_ROUTINE)McbMappingCompare,
+		 McbMappingAllocate,
+		 McbMappingFree,
+		 Mcb);
+	InitializeListHead(GET_LIST_HEAD(Mcb->Mapping));
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+FsRtlInitializeLargeMcb(IN PLARGE_MCB Mcb,
+                        IN POOL_TYPE PoolType)
+{
+    Mcb->GuardedMutex = ExAllocateFromNPagedLookasideList(&FsRtlFastMutexLookasideList);
+
+    KeInitializeGuardedMutex(Mcb->GuardedMutex);
+
+    _SEH2_TRY
+    {
+        FsRtlInitializeBaseMcb(&(Mcb->BaseMcb), PoolType);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        ExFreeToNPagedLookasideList(&FsRtlFastMutexLookasideList,
+                                    Mcb->GuardedMutex);
+        Mcb->GuardedMutex = NULL;
+    }
+    _SEH2_END;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+FsRtlInitializeLargeMcbs(VOID)
+{
+    /* Initialize the list for the MCB */
+    ExInitializePagedLookasideList(&FsRtlFirstMappingLookasideList,
+                                   NULL,
+                                   NULL,
+                                   POOL_RAISE_IF_ALLOCATION_FAILURE,
+								   sizeof(RTL_GENERIC_TABLE) + sizeof(LIST_ENTRY),
+                                   IFS_POOL_TAG,
+                                   0); /* FIXME: Should be 4 */
+
+    /* Initialize the list for the guarded mutex */
+    ExInitializeNPagedLookasideList(&FsRtlFastMutexLookasideList,
+                                    NULL,
+                                    NULL,
+                                    POOL_RAISE_IF_ALLOCATION_FAILURE,
+                                    sizeof(KGUARDED_MUTEX),
+                                    IFS_POOL_TAG,
+                                    0); /* FIXME: Should be 32 */
+}
+
+/*
+ * @unimplemented
+ */
+BOOLEAN
+NTAPI
+FsRtlLookupBaseMcbEntry(IN PBASE_MCB Mcb,
+                        IN LONGLONG Vbn,
+                        OUT PLONGLONG Lbn OPTIONAL,
+                        OUT PLONGLONG SectorCountFromLbn OPTIONAL,
+                        OUT PLONGLONG StartingLbn OPTIONAL,
+                        OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL,
+                        OUT PULONG Index OPTIONAL)
+{
+	BOOLEAN Result = FALSE;
+	LARGE_MCB_MAPPING_ENTRY ToLookup;
+	PLARGE_MCB_MAPPING_ENTRY Entry;
+
+	ToLookup.RunStartVbn.QuadPart = Vbn;
+	ToLookup.SectorCount.QuadPart = 1;
+
+	Entry = RtlLookupElementGenericTable(Mcb->Mapping, &ToLookup);
+	if (!Entry)
+	{
+		// Find out if we have a following entry.  The spec says we should return
+		// found with Lbn == -1 when we're beneath the largest map.
+		ToLookup.SectorCount.QuadPart = (1ull<<62) - ToLookup.RunStartVbn.QuadPart;
+		Entry = RtlLookupElementGenericTable(Mcb->Mapping, &ToLookup);
+		if (Entry)
+		{
+			Result = TRUE;
+			if (Lbn) *Lbn = ~0ull;
+		}
+		else
+		{
+			Result = FALSE;
+		}
+	}
+	else
+	{
+		LARGE_INTEGER Offset;
+		Offset.QuadPart = Vbn - Entry->RunStartVbn.QuadPart;
+		Result = TRUE;
+		if (Lbn) *Lbn = Entry->StartingLbn.QuadPart + Offset.QuadPart;
+		if (SectorCountFromLbn) *SectorCountFromLbn = Entry->SectorCount.QuadPart - Offset.QuadPart;
+		if (StartingLbn) *StartingLbn = Entry->StartingLbn.QuadPart;
+		if (SectorCountFromStartingLbn) *SectorCountFromStartingLbn = Entry->SectorCount.QuadPart;
+	}
+	
+    return Result;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+FsRtlLookupLargeMcbEntry(IN PLARGE_MCB Mcb,
+                         IN LONGLONG Vbn,
+                         OUT PLONGLONG Lbn OPTIONAL,
+                         OUT PLONGLONG SectorCountFromLbn OPTIONAL,
+                         OUT PLONGLONG StartingLbn OPTIONAL,
+                         OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL,
+                         OUT PULONG Index OPTIONAL)
+{
+    BOOLEAN Result;
+
+	DPRINT("FsRtlLookupLargeMcbEntry Mcb %x Vbn %x\n", Mcb, (ULONG)Vbn);
+
+    KeAcquireGuardedMutex(Mcb->GuardedMutex);
+    Result = FsRtlLookupBaseMcbEntry(&(Mcb->BaseMcb),
+                                     Vbn,
+                                     Lbn,
+                                     SectorCountFromLbn,
+                                     StartingLbn,
+                                     SectorCountFromStartingLbn,
+                                     Index);
+    KeReleaseGuardedMutex(Mcb->GuardedMutex);
+
+	DPRINT("Done %d\n", Result);
+
+    return Result;
+}
+
+/*
+ * @unimplemented
+ */
+BOOLEAN
+NTAPI
+FsRtlLookupLastBaseMcbEntryAndIndex(IN PBASE_MCB OpaqueMcb,
+                                    IN OUT PLONGLONG LargeVbn,
+                                    IN OUT PLONGLONG LargeLbn,
+                                    IN OUT PULONG Index)
+{
+	ULONG i = 0;
+	BOOLEAN Result = FALSE;
+	PLIST_ENTRY ListEntry;
+	PLARGE_MCB_MAPPING_ENTRY Entry;
+	PLARGE_MCB_MAPPING_ENTRY CountEntry;
+
+	ListEntry = GET_LIST_HEAD(OpaqueMcb->Mapping);
+	if (!IsListEmpty(ListEntry))
+	{
+		Entry = CONTAINING_RECORD(ListEntry->Flink, LARGE_MCB_MAPPING_ENTRY, Sequence);
+		Result = TRUE;
+		*LargeVbn = Entry->RunStartVbn.QuadPart;
+		*LargeLbn = Entry->StartingLbn.QuadPart;
+
+		for (i = 0, CountEntry = RtlEnumerateGenericTable(OpaqueMcb->Mapping, TRUE);
+			 CountEntry != Entry;
+			 CountEntry = RtlEnumerateGenericTable(OpaqueMcb->Mapping, FALSE));
+
+		*Index = i;
+	}
+
+	return Result;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+FsRtlLookupLastLargeMcbEntryAndIndex(IN PLARGE_MCB OpaqueMcb,
+                                     OUT PLONGLONG LargeVbn,
+                                     OUT PLONGLONG LargeLbn,
+                                     OUT PULONG Index)
+{
+    BOOLEAN Result;
+
+	DPRINT("FsRtlLookupLastLargeMcbEntryAndIndex %x\n", OpaqueMcb);
+
+    KeAcquireGuardedMutex(OpaqueMcb->GuardedMutex);
+    Result = FsRtlLookupLastBaseMcbEntryAndIndex(&(OpaqueMcb->BaseMcb),
+                                                 LargeVbn,
+                                                 LargeLbn,
+                                                 Index);
+    KeReleaseGuardedMutex(OpaqueMcb->GuardedMutex);
+
+	DPRINT("Done %d\n", Result);
+
+    return Result;
+}
+
+/*
+ * @unimplemented
+ */
+BOOLEAN
+NTAPI
+FsRtlLookupLastBaseMcbEntry(IN PBASE_MCB Mcb,
+                            OUT PLONGLONG Vbn,
+                            OUT PLONGLONG Lbn)
+{
+	BOOLEAN Result = FALSE;
+	PLIST_ENTRY ListEntry;
+	PLARGE_MCB_MAPPING_ENTRY Entry;
+
+	ListEntry = GET_LIST_HEAD(Mcb->Mapping);
+	if (!IsListEmpty(ListEntry))
+	{
+		Entry = CONTAINING_RECORD(ListEntry->Flink, LARGE_MCB_MAPPING_ENTRY, Sequence);
+		Result = TRUE;
+		*Vbn = Entry->RunStartVbn.QuadPart;
+		*Lbn = Entry->StartingLbn.QuadPart;
+	}
+	
+	return Result;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+FsRtlLookupLastLargeMcbEntry(IN PLARGE_MCB Mcb,
+                             OUT PLONGLONG Vbn,
+                             OUT PLONGLONG Lbn)
+{
+    BOOLEAN Result;
+
+	DPRINT("FsRtlLookupLastLargeMcbEntry Mcb %x\n", Mcb);
+
+    KeAcquireGuardedMutex(Mcb->GuardedMutex);
+    Result = FsRtlLookupLastBaseMcbEntry(&(Mcb->BaseMcb),
+                                         Vbn,
+                                         Lbn);
+    KeReleaseGuardedMutex(Mcb->GuardedMutex);
+
+	DPRINT("Done %d\n", Result);
+
+    return Result;
+}
+
+/*
+ * @implemented
+ */
+ULONG
+NTAPI
+FsRtlNumberOfRunsInBaseMcb(IN PBASE_MCB Mcb)
+{
+    /* Return the count */
+    return Mcb->PairCount;
+}
+
+/*
+ * @implemented
+ */
+ULONG
+NTAPI
+FsRtlNumberOfRunsInLargeMcb(IN PLARGE_MCB Mcb)
+{
+    ULONG NumberOfRuns;
+
+	DPRINT("FsRtlNumberOfRunsInLargeMcb Mcb %x\n", Mcb);
+
+    /* Read the number of runs while holding the MCB lock */
+    KeAcquireGuardedMutex(Mcb->GuardedMutex);
+    NumberOfRuns = Mcb->BaseMcb.PairCount;
+    KeReleaseGuardedMutex(Mcb->GuardedMutex);
+
+	DPRINT("Done %d\n", NumberOfRuns);
+
+    /* Return the count */
+    return NumberOfRuns;
+}
+
+/*
+ * @unimplemented
+ */
+BOOLEAN
+NTAPI
+FsRtlRemoveBaseMcbEntry(IN PBASE_MCB Mcb,
+                        IN LONGLONG Vbn,
+                        IN LONGLONG SectorCount)
+{
+	LARGE_MCB_MAPPING_ENTRY Node;
+	PLARGE_MCB_MAPPING_ENTRY Element;
+
+	Node.RunStartVbn.QuadPart = Vbn;
+	Node.SectorCount.QuadPart = SectorCount;
+
+	while ((Element = RtlLookupElementGenericTable(Mcb->Mapping, &Node)))
+	{
+		// Must split
+		if (Element->RunStartVbn.QuadPart < Node.RunStartVbn.QuadPart &&
+			Element->SectorCount.QuadPart > Node.SectorCount.QuadPart)
+		{
+			LARGE_MCB_MAPPING_ENTRY Upper, Reinsert;
+			PLARGE_MCB_MAPPING_ENTRY Reinserted, Inserted;
+			LARGE_INTEGER StartHole = Node.RunStartVbn;
+			LARGE_INTEGER EndHole;
+			EndHole.QuadPart = Node.RunStartVbn.QuadPart + Node.SectorCount.QuadPart;
+			Upper.RunStartVbn.QuadPart = EndHole.QuadPart;
+			Upper.StartingLbn.QuadPart = 
+				Element->StartingLbn.QuadPart + 
+				EndHole.QuadPart - 
+				Element->RunStartVbn.QuadPart;
+			Upper.SectorCount.QuadPart = 
+				Element->SectorCount.QuadPart -
+				(EndHole.QuadPart - Element->RunStartVbn.QuadPart);
+			Reinsert = *Element;
+			Reinsert.SectorCount.QuadPart = 
+				Element->RunStartVbn.QuadPart - StartHole.QuadPart;
+			RemoveEntryList(&Element->Sequence);
+			RtlDeleteElementGenericTable(Mcb->Mapping, Element);
+			Mcb->PairCount--;
+
+			Reinserted = RtlInsertElementGenericTable
+				(Mcb->Mapping, &Reinsert, sizeof(Reinsert), NULL);
+			InsertHeadList(GET_LIST_HEAD(Mcb->Mapping), &Reinserted->Sequence);
+			Mcb->PairCount++;
+			
+			Inserted = RtlInsertElementGenericTable
+				(Mcb->Mapping, &Upper, sizeof(Upper), NULL);
+			InsertHeadList(GET_LIST_HEAD(Mcb->Mapping), &Inserted->Sequence);
+			Mcb->PairCount++;
+		}
+		else if (Element->RunStartVbn.QuadPart < Node.RunStartVbn.QuadPart)
+		{
+			LARGE_MCB_MAPPING_ENTRY NewElement;
+			PLARGE_MCB_MAPPING_ENTRY Reinserted;
+			LARGE_INTEGER StartHole = Node.RunStartVbn;
+			NewElement.RunStartVbn = Element->RunStartVbn;
+			NewElement.StartingLbn = Element->StartingLbn;
+			NewElement.SectorCount.QuadPart = StartHole.QuadPart - Element->StartingLbn.QuadPart;
+
+			RemoveEntryList(&Element->Sequence);
+			RtlDeleteElementGenericTable(Mcb->Mapping, Element);
+			Mcb->PairCount--;
+			
+			Reinserted = RtlInsertElementGenericTable
+				(Mcb->Mapping, &NewElement, sizeof(NewElement), NULL);
+			InsertHeadList(GET_LIST_HEAD(Mcb->Mapping), &Reinserted->Sequence);
+			Mcb->PairCount++;			
+		}
+		else
+		{
+			LARGE_MCB_MAPPING_ENTRY NewElement;
+			PLARGE_MCB_MAPPING_ENTRY Reinserted;
+			LARGE_INTEGER EndHole = Element->RunStartVbn;
+			LARGE_INTEGER EndRun;
+			EndRun.QuadPart = Element->RunStartVbn.QuadPart + Element->SectorCount.QuadPart;
+			NewElement.RunStartVbn = EndHole;
+			NewElement.StartingLbn.QuadPart = Element->StartingLbn.QuadPart + 
+				(EndHole.QuadPart - Element->RunStartVbn.QuadPart);
+			NewElement.SectorCount.QuadPart = EndRun.QuadPart - EndHole.QuadPart;
+
+			RemoveEntryList(&Element->Sequence);
+			RtlDeleteElementGenericTable(Mcb->Mapping, Element);
+			Mcb->PairCount--;
+			
+			Reinserted = RtlInsertElementGenericTable
+				(Mcb->Mapping, &NewElement, sizeof(NewElement), NULL);
+			InsertHeadList(GET_LIST_HEAD(Mcb->Mapping), &Reinserted->Sequence);
+			Mcb->PairCount++;			
+		}
+	}
+
+	return TRUE;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+FsRtlRemoveLargeMcbEntry(IN PLARGE_MCB Mcb,
+                         IN LONGLONG Vbn,
+                         IN LONGLONG SectorCount)
+{
+	DPRINT("FsRtlRemoveLargeMcbEntry Mcb %x, Vbn %x, SectorCount %x\n", Mcb, (ULONG)Vbn, (ULONG)SectorCount);
+
+    KeAcquireGuardedMutex(Mcb->GuardedMutex);
+    FsRtlRemoveBaseMcbEntry(&(Mcb->BaseMcb),
+                            Vbn,
+                            SectorCount);
+    KeReleaseGuardedMutex(Mcb->GuardedMutex);
+
+	DPRINT("Done\n");
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+FsRtlResetBaseMcb(IN PBASE_MCB Mcb)
+{
+	PLARGE_MCB_MAPPING_ENTRY Element;
+
+	while (RtlNumberGenericTableElements(Mcb->Mapping) &&
+		   (Element = (PLARGE_MCB_MAPPING_ENTRY)RtlGetElementGenericTable(Mcb->Mapping, 0)))
+	{
+		RtlDeleteElementGenericTable(Mcb->Mapping, Element);
+	}
+
+	Mcb->PairCount = 0;
+	Mcb->MaximumPairCount = 0;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+FsRtlResetLargeMcb(IN PLARGE_MCB Mcb,
+                   IN BOOLEAN SelfSynchronized)
+{
+    if (!SelfSynchronized)
+    {
+        KeAcquireGuardedMutex(Mcb->GuardedMutex);
+	}
+
+	FsRtlResetBaseMcb(&Mcb->BaseMcb);
+
+
+    if (!SelfSynchronized)
+    {
+		KeReleaseGuardedMutex(Mcb->GuardedMutex);
+    }
+}
+
+#define MCB_BUMP_NO_MORE 0
+#define MCB_BUMP_AGAIN   1
+
+static ULONG NTAPI McbBump(PBASE_MCB Mcb, PLARGE_MCB_MAPPING_ENTRY FixedPart)
+{
+	LARGE_MCB_MAPPING_ENTRY Reimagined;
+	PLARGE_MCB_MAPPING_ENTRY Found = NULL;
+
+	DPRINT("McbBump %x (%x:%x)\n", Mcb, FixedPart->RunStartVbn.LowPart, FixedPart->SectorCount.LowPart);
+
+	Reimagined = *FixedPart;
+	while ((Found = RtlLookupElementGenericTable(Mcb->Mapping, &Reimagined)))
+	{
+		Reimagined = *Found;
+		Reimagined.RunStartVbn.QuadPart = 
+			FixedPart->RunStartVbn.QuadPart + FixedPart->SectorCount.QuadPart;
+		DPRINT("Reimagined %x\n", Reimagined.RunStartVbn.LowPart);
+	}
+
+	DPRINT("Found %x\n", Found);
+	if (!Found) return MCB_BUMP_NO_MORE;
+	DPRINT1
+		("Moving %x-%x to %x because %x-%x overlaps\n",
+		 Found->RunStartVbn.LowPart, 
+		 Found->RunStartVbn.LowPart + Found->SectorCount.QuadPart,
+		 Reimagined.RunStartVbn.LowPart + Reimagined.SectorCount.LowPart,
+		 Reimagined.RunStartVbn.LowPart,
+		 Reimagined.RunStartVbn.LowPart + Reimagined.SectorCount.LowPart);
+	Found->RunStartVbn.QuadPart = Reimagined.RunStartVbn.QuadPart + Reimagined.SectorCount.QuadPart;
+	Found->StartingLbn.QuadPart = Reimagined.StartingLbn.QuadPart + Reimagined.SectorCount.QuadPart;
+
+	DPRINT("Again\n");
+	return MCB_BUMP_AGAIN;
+}
+
+/*
+ * @unimplemented
+ */
+BOOLEAN
+NTAPI
+FsRtlSplitBaseMcb(IN PBASE_MCB Mcb,
+                  IN LONGLONG Vbn,
+                  IN LONGLONG Amount)
+{
+	ULONG Result;
+	LARGE_MCB_MAPPING_ENTRY Node;
+	PLARGE_MCB_MAPPING_ENTRY Existing = NULL;
+
+	Node.RunStartVbn.QuadPart = Vbn;
+	Node.SectorCount.QuadPart = 0;
+	
+	Existing = RtlLookupElementGenericTable(Mcb->Mapping, &Node);
+
+	if (Existing)
+	{
+		// We're in the middle of a run
+		LARGE_MCB_MAPPING_ENTRY UpperPart;
+		LARGE_MCB_MAPPING_ENTRY LowerPart;
+		PLARGE_MCB_MAPPING_ENTRY InsertedUpper;
+
+		UpperPart.RunStartVbn.QuadPart = Node.RunStartVbn.QuadPart + Amount;
+		UpperPart.SectorCount.QuadPart = Existing->RunStartVbn.QuadPart + 
+			(Existing->SectorCount.QuadPart - Node.RunStartVbn.QuadPart);
+		UpperPart.StartingLbn.QuadPart = Existing->StartingLbn.QuadPart + 
+			(Node.RunStartVbn.QuadPart - Existing->RunStartVbn.QuadPart);
+		LowerPart.RunStartVbn.QuadPart = Existing->RunStartVbn.QuadPart;
+		LowerPart.SectorCount.QuadPart = Node.RunStartVbn.QuadPart - Existing->RunStartVbn.QuadPart;
+		LowerPart.StartingLbn.QuadPart = Existing->StartingLbn.QuadPart;
+		
+		Node = UpperPart;
+
+		DPRINT("Loop: %x\n", Node.RunStartVbn.LowPart);
+		while ((Result = McbBump(Mcb, &Node)) == MCB_BUMP_AGAIN)
+		{
+			DPRINT("Node: %x\n", Node.RunStartVbn.LowPart);
+		}
+		DPRINT("Done\n");
+
+		if (Result == MCB_BUMP_NO_MORE)
+		{
+			Node = *Existing;
+			RemoveHeadList(&Existing->Sequence);
+			RtlDeleteElementGenericTable(Mcb->Mapping, Existing);
+			Mcb->PairCount--;
+			
+			// Adjust the element we found.
+			Existing->SectorCount = LowerPart.SectorCount;
+
+			InsertedUpper = RtlInsertElementGenericTable
+				(Mcb->Mapping, &UpperPart, sizeof(UpperPart), NULL);
+			if (!InsertedUpper)
+			{
+				// Just make it like it was
+				Existing->SectorCount = Node.SectorCount;
+				return FALSE;
+			}
+			InsertHeadList(GET_LIST_HEAD(Mcb->Mapping), &InsertedUpper->Sequence);
+			Mcb->PairCount++;
+		}
+		else
+		{
+			Node.RunStartVbn.QuadPart = Vbn;
+			Node.SectorCount.QuadPart = Amount;
+			while ((Result = McbBump(Mcb, &Node)) == MCB_BUMP_AGAIN);
+			return Result == MCB_BUMP_NO_MORE;
+		}
+	}
+
+	DPRINT("Done\n");
+	
+	return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+FsRtlSplitLargeMcb(IN PLARGE_MCB Mcb,
+                   IN LONGLONG Vbn,
+                   IN LONGLONG Amount)
+{
+    BOOLEAN Result;
+
+	DPRINT("FsRtlSplitLargeMcb %x, Vbn %x, Amount %x\n", Mcb, (ULONG)Vbn, (ULONG)Amount);
+
+    KeAcquireGuardedMutex(Mcb->GuardedMutex);
+    Result = FsRtlSplitBaseMcb(&(Mcb->BaseMcb),
+                               Vbn,
+                               Amount);
+    KeReleaseGuardedMutex(Mcb->GuardedMutex);
+
+	DPRINT("Done %d\n", Result);
+
+    return Result;
+}
+
+/*
+ * @unimplemented
+ */
+VOID
+NTAPI
+FsRtlTruncateBaseMcb(IN PBASE_MCB Mcb,
+                     IN LONGLONG Vbn)
+{
+	if (!Vbn)
+	{
+		FsRtlResetBaseMcb(Mcb);
+	}
+	else
+	{
+		LARGE_MCB_MAPPING_ENTRY Truncate;
+		PLARGE_MCB_MAPPING_ENTRY Found;
+		Truncate.RunStartVbn.QuadPart = Vbn;
+		Truncate.SectorCount.QuadPart = (1ull<<62) - Truncate.RunStartVbn.QuadPart;
+		while ((Found = RtlLookupElementGenericTable(Mcb->Mapping, &Truncate)))
+		{
+			RemoveEntryList(&Found->Sequence);
+			RtlDeleteElementGenericTable(Mcb->Mapping, Found);
+			Mcb->PairCount--;
+		}
+	}
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+FsRtlTruncateLargeMcb(IN PLARGE_MCB Mcb,
+                      IN LONGLONG Vbn)
+{
+	DPRINT("FsRtlTruncateLargeMcb %x Vbn %x\n", Mcb, (ULONG)Vbn);
+    KeAcquireGuardedMutex(Mcb->GuardedMutex);
+    FsRtlTruncateBaseMcb(&(Mcb->BaseMcb),
+                         Vbn);
+    KeReleaseGuardedMutex(Mcb->GuardedMutex);
+	DPRINT("Done\n");
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+FsRtlUninitializeBaseMcb(IN PBASE_MCB Mcb)
+{
+	FsRtlResetBaseMcb(Mcb);
+
+    if ((Mcb->PoolType == PagedPool) && (Mcb->MaximumPairCount == MAXIMUM_PAIR_COUNT))
+    {
+        ExFreeToPagedLookasideList(&FsRtlFirstMappingLookasideList,
+                                   Mcb->Mapping);
+    }
+    else
+    {
+        ExFreePoolWithTag(Mcb->Mapping, 'FSBC');
+    }
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+FsRtlUninitializeLargeMcb(IN PLARGE_MCB Mcb)
+{
+    if (Mcb->GuardedMutex)
+    {
+        ExFreeToNPagedLookasideList(&FsRtlFastMutexLookasideList,
+                                    Mcb->GuardedMutex);
+        FsRtlUninitializeBaseMcb(&(Mcb->BaseMcb));
+    }
+}
+




More information about the Ros-diffs mailing list