branch update for HEAD-2002110701
[reactos.git] / ntoskrnl / mm / mdl.c
index e5d1b9e..465f6ba 100644 (file)
@@ -15,6 +15,7 @@
 #include <internal/mm.h>
 #include <internal/ps.h>
 #include <internal/pool.h>
+#include <ntos/minmax.h>
 
 #define NDEBUG
 #include <internal/debug.h>
@@ -27,8 +28,8 @@
 #define MI_MDL_MAPPING_REGION_SIZE       (256*1024*1024)
 
 static PVOID MiMdlMappingRegionBase = NULL;
-static PULONG MiMdlMappingRegionAllocMap = NULL;
-static ULONG MiMdlMappingRegionHighWaterMark = 0;
+static RTL_BITMAP MiMdlMappingRegionAllocMap;
+static ULONG MiMdlMappingRegionHint;
 static KSPIN_LOCK MiMdlMappingRegionLock;
 #endif /* LIBCAPTIVE */
 
@@ -41,7 +42,9 @@ MmInitializeMdlImplementation(VOID)
 {
   MEMORY_AREA* Result;
   NTSTATUS Status;
+  PVOID Buffer;
 
+  MiMdlMappingRegionHint = 0;
   MiMdlMappingRegionBase = NULL;
 
   MmLockAddressSpace(MmGetKernelAddressSpace());
@@ -60,10 +63,11 @@ MmInitializeMdlImplementation(VOID)
     }
   MmUnlockAddressSpace(MmGetKernelAddressSpace());
 
-  MiMdlMappingRegionAllocMap = 
-    ExAllocatePool(NonPagedPool,
-                  MI_MDL_MAPPING_REGION_SIZE / (PAGE_SIZE * 32));
-  MiMdlMappingRegionHighWaterMark = 0;
+  Buffer = ExAllocatePool(NonPagedPool, MI_MDL_MAPPING_REGION_SIZE / (PAGE_SIZE * 8));
+
+  RtlInitializeBitMap(&MiMdlMappingRegionAllocMap, Buffer, MI_MDL_MAPPING_REGION_SIZE / PAGE_SIZE);
+  RtlClearAllBits(&MiMdlMappingRegionAllocMap);
+
   KeInitializeSpinLock(&MiMdlMappingRegionLock);
 }
 
@@ -134,6 +138,7 @@ MmMapLockedPages(PMDL Mdl, KPROCESSOR_MODE AccessMode)
    PULONG MdlPages;
    KIRQL oldIrql;
    ULONG RegionSize;
+   ULONG StartingOffset;
    
    DPRINT("MmMapLockedPages(Mdl %x, AccessMode %x)\n", Mdl, AccessMode);
 
@@ -153,13 +158,22 @@ MmMapLockedPages(PMDL Mdl, KPROCESSOR_MODE AccessMode)
 
    /* Allocate that number of pages from the mdl mapping region. */
    KeAcquireSpinLock(&MiMdlMappingRegionLock, &oldIrql);
-   Base = MiMdlMappingRegionBase + MiMdlMappingRegionHighWaterMark * PAGE_SIZE;
-   for (i = 0; i < RegionSize; i++)
-     {
-       ULONG Offset = MiMdlMappingRegionHighWaterMark + i;
-       MiMdlMappingRegionAllocMap[Offset / 32] |= (1 << (Offset % 32));
-     }
-   MiMdlMappingRegionHighWaterMark += RegionSize;
+
+   StartingOffset = RtlFindClearBitsAndSet(&MiMdlMappingRegionAllocMap, RegionSize, MiMdlMappingRegionHint);
+  
+   if (StartingOffset == 0xffffffff)
+   {
+      DPRINT1("Out of MDL mapping space\n");
+      KeBugCheck(0);
+   }
+
+   Base = MiMdlMappingRegionBase + StartingOffset * PAGE_SIZE;
+
+   if (MiMdlMappingRegionHint == StartingOffset)
+   {
+       MiMdlMappingRegionHint +=RegionSize; 
+   }
+
    KeReleaseSpinLock(&MiMdlMappingRegionLock, oldIrql);
 
    /* Set the virtual mappings for the MDL pages. */
@@ -199,7 +213,7 @@ MmUnmapLockedPages(PVOID BaseAddress, PMDL Mdl)
   ULONG RegionSize;
   ULONG Base;
 
-  DPRINT("MmUnmapLockedPages(BaseAddress %x, Mdl %x)\n", Mdl, BaseAddress);
+  DPRINT("MmUnmapLockedPages(BaseAddress %x, Mdl %x)\n", BaseAddress, Mdl);
 
   /*
    * In this case, the MDL has the same system address as the base address
@@ -212,6 +226,7 @@ MmUnmapLockedPages(PVOID BaseAddress, PMDL Mdl)
 
   /* Calculate the number of pages we mapped. */
   RegionSize = PAGE_ROUND_UP(Mdl->ByteCount + Mdl->ByteOffset) / PAGE_SIZE;
+  BaseAddress -= Mdl->ByteOffset;
 
   /* Unmap all the pages. */
   for (i = 0; i < RegionSize; i++)
@@ -225,18 +240,12 @@ MmUnmapLockedPages(PVOID BaseAddress, PMDL Mdl)
 
   KeAcquireSpinLock(&MiMdlMappingRegionLock, &oldIrql);
   /* Deallocate all the pages used. */
-  Base = (ULONG)(BaseAddress - MiMdlMappingRegionBase - Mdl->ByteOffset);
-  Base = Base / PAGE_SIZE;
-  for (i = 0; i < RegionSize; i++)
-    {
-      ULONG Offset = Base + i;
-      MiMdlMappingRegionAllocMap[Offset / 32] &= ~(1 << (Offset % 32));
-    }
-  /* If all the pages below the high-water mark are free then move it down. */
-  if ((Base + RegionSize) == MiMdlMappingRegionHighWaterMark)
-    {
-      MiMdlMappingRegionHighWaterMark = Base;
-    }
+  Base = (ULONG)(BaseAddress - MiMdlMappingRegionBase) / PAGE_SIZE;
+  
+  RtlClearBits(&MiMdlMappingRegionAllocMap, Base, RegionSize);
+
+  MiMdlMappingRegionHint = min (MiMdlMappingRegionHint, Base);
+
   KeReleaseSpinLock(&MiMdlMappingRegionLock, oldIrql);
   
   /* Reset the MDL state. */