update for HEAD-2003091401
[reactos.git] / ntoskrnl / mm / rmap.c
index 81df3e4..272f42b 100644 (file)
@@ -45,9 +45,12 @@ typedef struct _MM_RMAP_ENTRY
   PVOID Address;
 } MM_RMAP_ENTRY, *PMM_RMAP_ENTRY;
 
+#define TAG_RMAP    TAG('R', 'M', 'A', 'P')
+
 /* GLOBALS ******************************************************************/
 
 static FAST_MUTEX RmapListLock;
+static NPAGED_LOOKASIDE_LIST RmapLookasideList;
 
 /* FUNCTIONS ****************************************************************/
 
@@ -55,6 +58,13 @@ VOID
 MmInitializeRmapList(VOID)
 {
   ExInitializeFastMutex(&RmapListLock);
+  ExInitializeNPagedLookasideList (&RmapLookasideList,
+                                  NULL,
+                                  NULL,
+                                  0,
+                                  sizeof(MM_RMAP_ENTRY),
+                                  TAG_RMAP,
+                                  50);
 }
 
 NTSTATUS
@@ -62,12 +72,13 @@ MmWritePagePhysicalAddress(PHYSICAL_ADDRESS PhysicalAddress)
 {
   PMM_RMAP_ENTRY entry;
   PMEMORY_AREA MemoryArea;
+  PMADDRESS_SPACE AddressSpace;
   ULONG Type;
   PVOID Address;
   PEPROCESS Process;
   PMM_PAGEOP PageOp;
-  LARGE_INTEGER Offset;
-  NTSTATUS Status;
+  ULONG Offset;
+  NTSTATUS Status = STATUS_SUCCESS;
 
   /*
    * Check that the address still has a valid rmap; then reference the
@@ -84,96 +95,122 @@ MmWritePagePhysicalAddress(PHYSICAL_ADDRESS PhysicalAddress)
   Address = entry->Address;
   if ((((ULONG)Address) & 0xFFF) != 0)
     {
-      KeBugCheck(0);
+      KEBUGCHECK(0);
+    }
+  if (Address < (PVOID)KERNEL_BASE)
+    {
+      Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
+      ExReleaseFastMutex(&RmapListLock);
+      if (!NT_SUCCESS(Status))
+        {
+          return Status;
+        }
+      AddressSpace = &Process->AddressSpace;
+    }
+  else
+    {
+      ExReleaseFastMutex(&RmapListLock);
+      AddressSpace = MmGetKernelAddressSpace();
     }
-  Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
-  ExReleaseFastMutex(&RmapListLock);
-  if (!NT_SUCCESS(Status))
-  {
-     return Status;
-  }
 
   /*
    * Lock the address space; then check that the address we are using
    * still corresponds to a valid memory area (the page might have been
    * freed or paged out after we read the rmap entry.) 
    */
-  MmLockAddressSpace(&Process->AddressSpace);
-  MemoryArea = MmOpenMemoryAreaByAddress(&Process->AddressSpace, Address);
-  if (MemoryArea == NULL)
+  MmLockAddressSpace(AddressSpace);
+  MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, Address);
+  if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
     {
-      ObDereferenceObject(Process);
+      MmUnlockAddressSpace(AddressSpace);
+      if (Address < (PVOID)KERNEL_BASE)
+        {
+          ObDereferenceObject(Process);
+       }
       return(STATUS_UNSUCCESSFUL);
     }
 
   Type = MemoryArea->Type;
   if (Type == MEMORY_AREA_SECTION_VIEW)
     {
-      Offset.QuadPart = (ULONG)((Address - (ULONG)MemoryArea->BaseAddress) +
-       MemoryArea->Data.SectionData.ViewOffset);
+      Offset = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress);
 
       /*
        * Get or create a pageop
        */
       PageOp = MmGetPageOp(MemoryArea, 0, 0, 
                           MemoryArea->Data.SectionData.Segment, 
-                          Offset.u.LowPart, MM_PAGEOP_PAGEOUT);
+                          Offset, MM_PAGEOP_PAGEOUT);
       if (PageOp == NULL)
        {
          DPRINT1("MmGetPageOp failed\n");
-         KeBugCheck(0);
+         KEBUGCHECK(0);
        }
 
 
       if (PageOp->Thread != PsGetCurrentThread())
        {
+         MmUnlockAddressSpace(AddressSpace);
+          Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
+                                        0,
+                                        KernelMode,
+                                        FALSE,
+                                        NULL);
+          KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
          MmReleasePageOp(PageOp);
-         MmUnlockAddressSpace(&Process->AddressSpace);
-          ObDereferenceObject(Process);
+         if (Address < (PVOID)KERNEL_BASE)
+           {
+              ObDereferenceObject(Process);
+           }
          return(STATUS_UNSUCCESSFUL);
        }
       
       /*
        * Release locks now we have a page op.
        */
-      MmUnlockAddressSpace(&Process->AddressSpace);      
+      MmUnlockAddressSpace(AddressSpace);      
 
       /*
        * Do the actual page out work.
        */
-      Status = MmWritePageSectionView(&Process->AddressSpace, MemoryArea, 
+      Status = MmWritePageSectionView(AddressSpace, MemoryArea, 
                                      Address, PageOp);
     }
   else if (Type == MEMORY_AREA_VIRTUAL_MEMORY)
     {
-      PageOp = MmGetPageOp(MemoryArea, Process->UniqueProcessId,
+      PageOp = MmGetPageOp(MemoryArea, Address < (PVOID)KERNEL_BASE ? Process->UniqueProcessId : 0,
                           Address, NULL, 0, MM_PAGEOP_PAGEOUT);
       
-
       if (PageOp->Thread != PsGetCurrentThread())
        {
          MmReleasePageOp(PageOp);
-         MmUnlockAddressSpace(&Process->AddressSpace);
-          ObDereferenceObject(Process);
+         MmUnlockAddressSpace(AddressSpace);
+         if (Address < (PVOID)KERNEL_BASE)
+           {
+              ObDereferenceObject(Process);
+           }
          return(STATUS_UNSUCCESSFUL);
        }
 
       /*
        * Release locks now we have a page op.
        */
-      MmUnlockAddressSpace(&Process->AddressSpace);
+      MmUnlockAddressSpace(AddressSpace);
 
       /*
        * Do the actual page out work.
        */
-      Status = MmWritePageVirtualMemory(&Process->AddressSpace, MemoryArea, 
+      Status = MmWritePageVirtualMemory(AddressSpace, MemoryArea, 
                                        Address, PageOp);
     }
   else
     {
-      KeBugCheck(0);
+      KEBUGCHECK(0);
     }  
-  ObDereferenceObject(Process);
+  if (Address < (PVOID)KERNEL_BASE)
+    {
+      ObDereferenceObject(Process);
+    }
   return(Status);
 }
 
@@ -182,12 +219,13 @@ MmPageOutPhysicalAddress(PHYSICAL_ADDRESS PhysicalAddress)
 {
   PMM_RMAP_ENTRY entry;
   PMEMORY_AREA MemoryArea;
+  PMADDRESS_SPACE AddressSpace;
   ULONG Type;
   PVOID Address;
   PEPROCESS Process;
   PMM_PAGEOP PageOp;
-  LARGE_INTEGER Offset;
-  NTSTATUS Status;
+  ULONG Offset;
+  NTSTATUS Status = STATUS_SUCCESS;
 
   ExAcquireFastMutex(&RmapListLock);
   entry = MmGetRmapListHeadPage(PhysicalAddress);
@@ -200,82 +238,115 @@ MmPageOutPhysicalAddress(PHYSICAL_ADDRESS PhysicalAddress)
   Address = entry->Address;
   if ((((ULONG)Address) & 0xFFF) != 0)
     {
-      KeBugCheck(0);
+      KEBUGCHECK(0);
     }
 
-  Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
-  ExReleaseFastMutex(&RmapListLock);
-  if (!NT_SUCCESS(Status))
-  {
-      return Status;
-  }
-  MmLockAddressSpace(&Process->AddressSpace);
-  MemoryArea = MmOpenMemoryAreaByAddress(&Process->AddressSpace, Address);
+  if (Address < (PVOID)KERNEL_BASE)
+    {
+      Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
+      ExReleaseFastMutex(&RmapListLock);
+      if (!NT_SUCCESS(Status))
+        {
+          return Status;
+        }
+      AddressSpace = &Process->AddressSpace;
+    }
+  else
+    {
+      ExReleaseFastMutex(&RmapListLock);
+      AddressSpace = MmGetKernelAddressSpace();
+    }
+
+  MmLockAddressSpace(AddressSpace);
+  MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, Address);
+  if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
+    {
+      MmUnlockAddressSpace(AddressSpace);
+      if (Address < (PVOID)KERNEL_BASE)
+        {
+          ObDereferenceObject(Process);
+       }
+      return(STATUS_UNSUCCESSFUL);
+    }
   Type = MemoryArea->Type;
   if (Type == MEMORY_AREA_SECTION_VIEW)
     {
-      Offset.QuadPart = (ULONG)((Address - (ULONG)MemoryArea->BaseAddress) +
-       MemoryArea->Data.SectionData.ViewOffset);
+      Offset = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress);
 
       /*
        * Get or create a pageop
        */
       PageOp = MmGetPageOp(MemoryArea, 0, 0, 
                           MemoryArea->Data.SectionData.Segment, 
-                          Offset.u.LowPart, MM_PAGEOP_PAGEOUT);
+                          Offset, MM_PAGEOP_PAGEOUT);
       if (PageOp == NULL)
        {
          DPRINT1("MmGetPageOp failed\n");
-         KeBugCheck(0);
+         KEBUGCHECK(0);
        }
 
       if (PageOp->Thread != PsGetCurrentThread())
        {
          MmReleasePageOp(PageOp);
-         MmUnlockAddressSpace(&Process->AddressSpace);
-          ObDereferenceObject(Process);
+         MmUnlockAddressSpace(AddressSpace);
+         if (Address < (PVOID)KERNEL_BASE)
+           {
+              ObDereferenceObject(Process);
+           }
          return(STATUS_UNSUCCESSFUL);
        }
       
       /*
        * Release locks now we have a page op.
        */
-      MmUnlockAddressSpace(&Process->AddressSpace);
+      MmUnlockAddressSpace(AddressSpace);
 
       /*
        * Do the actual page out work.
        */
-      Status = MmPageOutSectionView(&Process->AddressSpace, MemoryArea, 
+      Status = MmPageOutSectionView(AddressSpace, MemoryArea, 
                                    Address, PageOp);
     }
   else if (Type == MEMORY_AREA_VIRTUAL_MEMORY)
     {
-      PageOp = MmGetPageOp(MemoryArea, Process->UniqueProcessId,
+      PageOp = MmGetPageOp(MemoryArea, Address < (PVOID)KERNEL_BASE ? Process->UniqueProcessId : 0,
                           Address, NULL, 0, MM_PAGEOP_PAGEOUT);
       if (PageOp->Thread != PsGetCurrentThread())
        {
+         MmUnlockAddressSpace(AddressSpace);
+          Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
+                                        0,
+                                        KernelMode,
+                                        FALSE,
+                                        NULL);
+          KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
          MmReleasePageOp(PageOp);
-         MmUnlockAddressSpace(&Process->AddressSpace);
-          ObDereferenceObject(Process);
+         if (Address < (PVOID)KERNEL_BASE)
+           {
+              ObDereferenceObject(Process);
+           }
          return(STATUS_UNSUCCESSFUL);
        }
 
       /*
        * Release locks now we have a page op.
        */
-      MmUnlockAddressSpace(&Process->AddressSpace);
+      MmUnlockAddressSpace(AddressSpace);
 
       /*
        * Do the actual page out work.
        */
-      Status = MmPageOutVirtualMemory(&Process->AddressSpace, MemoryArea, 
+      Status = MmPageOutVirtualMemory(AddressSpace, MemoryArea, 
                                      Address, PageOp);
     }
   else
     {
-      KeBugCheck(0);
+      KEBUGCHECK(0);
+    }
+  if (Address < (PVOID)KERNEL_BASE)
+    {
+      ObDereferenceObject(Process);
     }
-  ObDereferenceObject(Process);
   return(Status);
 }
 
@@ -289,7 +360,7 @@ MmSetCleanAllRmaps(PHYSICAL_ADDRESS PhysicalAddress)
   if (current_entry == NULL)
     {
       DPRINT1("MmIsDirtyRmap: No rmaps.\n");
-      KeBugCheck(0);
+      KEBUGCHECK(0);
     }
   while (current_entry != NULL)
     {      
@@ -309,7 +380,7 @@ MmSetDirtyAllRmaps(PHYSICAL_ADDRESS PhysicalAddress)
   if (current_entry == NULL)
     {
       DPRINT1("MmIsDirtyRmap: No rmaps.\n");
-      KeBugCheck(0);
+      KEBUGCHECK(0);
     }
   while (current_entry != NULL)
     {      
@@ -353,10 +424,10 @@ MmInsertRmap(PHYSICAL_ADDRESS PhysicalAddress, PEPROCESS Process,
 
   Address = (PVOID)PAGE_ROUND_DOWN(Address);
 
-  new_entry = ExAllocatePool(NonPagedPool, sizeof(MM_RMAP_ENTRY));
+  new_entry = ExAllocateFromNPagedLookasideList(&RmapLookasideList);
   if (new_entry == NULL)
     {
-      KeBugCheck(0);
+      KEBUGCHECK(0);
     }
   new_entry->Address = Address;
   new_entry->Process = Process;
@@ -368,7 +439,7 @@ MmInsertRmap(PHYSICAL_ADDRESS PhysicalAddress, PEPROCESS Process,
              "address 0x%.8X\n", Process->UniqueProcessId, Address, 
              MmGetPhysicalAddressForProcess(Process, Address), 
              PhysicalAddress)
-      KeBugCheck(0);
+      KEBUGCHECK(0);
     }
 
   ExAcquireFastMutex(&RmapListLock);
@@ -391,8 +462,9 @@ MmDeleteAllRmaps(PHYSICAL_ADDRESS PhysicalAddress, PVOID Context,
   if (current_entry == NULL)
     {
       DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
-      KeBugCheck(0);
+      KEBUGCHECK(0);
     }
+  MmSetRmapListHeadPage(PhysicalAddress, NULL);
   while (current_entry != NULL)
     {
       previous_entry = current_entry;
@@ -402,9 +474,8 @@ MmDeleteAllRmaps(PHYSICAL_ADDRESS PhysicalAddress, PVOID Context,
          DeleteMapping(Context, previous_entry->Process, 
                        previous_entry->Address);
        }
-      ExFreePool(previous_entry);
+      ExFreeToNPagedLookasideList(&RmapLookasideList, previous_entry);
     }
-  MmSetRmapListHeadPage(PhysicalAddress, NULL);
   ExReleaseFastMutex(&RmapListLock);
 }
 
@@ -425,19 +496,17 @@ MmDeleteRmap(PHYSICAL_ADDRESS PhysicalAddress, PEPROCESS Process,
          if (previous_entry == NULL)
            {
              MmSetRmapListHeadPage(PhysicalAddress, current_entry->Next);
-             ExReleaseFastMutex(&RmapListLock);
-             ExFreePool(current_entry);
            }
          else
            {
              previous_entry->Next = current_entry->Next;
-             ExReleaseFastMutex(&RmapListLock);
-             ExFreePool(current_entry);
            }
+         ExReleaseFastMutex(&RmapListLock);
+         ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
          return;
        }
       previous_entry = current_entry;
       current_entry = current_entry->Next;
     }
-  KeBugCheck(0);
+  KEBUGCHECK(0);
 }