Revert part of r20493. Created bug 1229 to keep track of the issue.
[reactos.git] / reactos / ntoskrnl / mm / pagefile.c
index 84ed6e6..5cccff8 100644 (file)
@@ -16,8 +16,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: pagefile.c,v 1.11 2001/03/25 02:34:28 dwelch Exp $
- *
+/*
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/mm/pagefile.c
  * PURPOSE:         Paging file functions
 
 /* INCLUDES *****************************************************************/
 
-#include <ddk/ntddk.h>
-#include <internal/bitops.h>
-#include <internal/io.h>
-#include <internal/mm.h>
-#include <napi/core.h>
-
+#include <ntoskrnl.h>
+#define NDEBUG
 #include <internal/debug.h>
 
+#if defined (ALLOC_PRAGMA)
+#pragma alloc_text(INIT, MmInitPagingFile)
+#endif
+
+
 /* TYPES *********************************************************************/
 
 typedef struct _PAGINGFILE
 {
    LIST_ENTRY PagingFileListEntry;
    PFILE_OBJECT FileObject;
-   ULONG MaximumSize;
-   ULONG CurrentSize;
+   LARGE_INTEGER MaximumSize;
+   LARGE_INTEGER CurrentSize;
    ULONG FreePages;
    ULONG UsedPages;
    PULONG AllocMap;
    KSPIN_LOCK AllocMapLock;
    ULONG AllocMapSize;
-} PAGINGFILE, *PPAGINGFILE;
+   PRETRIEVAL_POINTERS_BUFFER RetrievalPointers;
+}
+PAGINGFILE, *PPAGINGFILE;
+
+typedef struct _RETRIEVEL_DESCRIPTOR_LIST
+{
+   struct _RETRIEVEL_DESCRIPTOR_LIST* Next;
+   RETRIEVAL_POINTERS_BUFFER RetrievalPointers;
+}
+RETRIEVEL_DESCRIPTOR_LIST, *PRETRIEVEL_DESCRIPTOR_LIST;
 
 /* GLOBALS *******************************************************************/
 
+#define PAIRS_PER_RUN (1024)
+
 #define MAX_PAGING_FILES  (32)
 
 /* List of paging files, both used and free */
@@ -61,18 +72,21 @@ static PPAGINGFILE PagingFileList[MAX_PAGING_FILES];
 /* Lock for examining the list of paging files */
 static KSPIN_LOCK PagingFileListLock;
 
+/* Number of paging files */
+static ULONG MiPagingFileCount;
+
 /* Number of pages that are available for swapping */
-static ULONG MiFreeSwapPages;
+ULONG MiFreeSwapPages;
 
 /* Number of pages that have been allocated for swapping */
-static ULONG MiUsedSwapPages;
+ULONG MiUsedSwapPages;
 
-/* 
- * Number of pages that have been reserved for swapping but not yet allocated 
+/*
+ * Number of pages that have been reserved for swapping but not yet allocated
  */
 static ULONG MiReservedSwapPages;
 
-/* 
+/*
  * Ratio between reserved and available swap pages, e.g. setting this to five
  * forces one swap page to be available for every five swap pages that are
  * reserved. Setting this to zero turns off commit checking altogether.
@@ -81,241 +95,686 @@ static ULONG MiReservedSwapPages;
 
 /*
  * Number of pages that can be used for potentially swapable memory without
- * pagefile space being reserved. The intention is that is allows smss
+ * pagefile space being reserved. The intention is that this allows smss
  * to start up and create page files while ordinarily having a commit
  * ratio of one.
  */
 #define MM_PAGEFILE_COMMIT_GRACE      (256)
 
-#if 0
-static PVOID MmCoreDumpPageFrame;
-static BYTE MmCoreDumpHeader[PAGESIZE];
-#endif
+static PVOID MmCoreDumpPageFrame = NULL;
+static ULONG MmCoreDumpSize;
+static DUMP_POINTERS MmCoreDumpPointers;
+static PMM_CORE_DUMP_FUNCTIONS MmCoreDumpFunctions;
+static ULONG MmCoreDumpPageFile = 0xFFFFFFFF;
+static ROS_QUERY_LCN_MAPPING MmCoreDumpLcnMapping;
+
+ULONG MmCoreDumpType = MM_CORE_DUMP_TYPE_NONE;
 
 /*
  * Translate between a swap entry and a file and offset pair.
  */
 #define FILE_FROM_ENTRY(i) ((i) >> 24)
 #define OFFSET_FROM_ENTRY(i) (((i) & 0xffffff) - 1)
-#define ENTRY_FROM_FILE_OFFSET(i, j) (((i) << 24) || ((j) + 1))
+#define ENTRY_FROM_FILE_OFFSET(i, j) (((i) << 24) | ((j) + 1))
+
+static BOOLEAN MmSwapSpaceMessage = FALSE;
 
 /* FUNCTIONS *****************************************************************/
 
-NTSTATUS MmWriteToSwapPage(SWAPENTRY SwapEntry, PMDL Mdl)
+BOOLEAN
+STDCALL
+MmIsFileAPagingFile(PFILE_OBJECT FileObject)
+{
+    ULONG i;
+
+    /* Loop through all the paging files */
+    for (i = 0; i < MiPagingFileCount; i++)
+    {
+        /* Check if this is one of them */
+        if (PagingFileList[i]->FileObject == FileObject) return TRUE;
+    }
+
+    /* Nothing found */
+    return FALSE;
+}
+
+VOID
+NTAPI
+MmShowOutOfSpaceMessagePagingFile(VOID)
+{
+   if (!MmSwapSpaceMessage)
+   {
+      DPRINT1("MM: Out of swap space.\n");
+      MmSwapSpaceMessage = TRUE;
+   }
+}
+
+LARGE_INTEGER STATIC
+MmGetOffsetPageFile(PRETRIEVAL_POINTERS_BUFFER RetrievalPointers, LARGE_INTEGER Offset)
+{
+   /* Simple binary search */
+   ULONG first, last, mid;
+   first = 0;
+   last = RetrievalPointers->ExtentCount - 1;
+   while (first <= last)
+   {
+      mid = (last - first) / 2 + first;
+      if (Offset.QuadPart < RetrievalPointers->Extents[mid].NextVcn.QuadPart)
+      {
+         if (mid == 0)
+         {
+            Offset.QuadPart += RetrievalPointers->Extents[0].Lcn.QuadPart - RetrievalPointers->StartingVcn.QuadPart;
+            return Offset;
+         }
+         else
+         {
+            if (Offset.QuadPart >= RetrievalPointers->Extents[mid-1].NextVcn.QuadPart)
+            {
+               Offset.QuadPart += RetrievalPointers->Extents[mid].Lcn.QuadPart - RetrievalPointers->Extents[mid-1].NextVcn.QuadPart;
+               return Offset;
+            }
+            last = mid - 1;
+         }
+      }
+      else
+      {
+         if (mid == RetrievalPointers->ExtentCount - 1)
+         {
+            break;
+         }
+         if (Offset.QuadPart < RetrievalPointers->Extents[mid+1].NextVcn.QuadPart)
+         {
+            Offset.QuadPart += RetrievalPointers->Extents[mid+1].Lcn.QuadPart  - RetrievalPointers->Extents[mid].NextVcn.QuadPart;
+            return Offset;
+         }
+         first = mid + 1;
+      }
+   }
+   KEBUGCHECK(0);
+#if defined(__GNUC__)
+
+   return (LARGE_INTEGER)0LL;
+#else
+
+   {
+      const LARGE_INTEGER dummy =
+         {
+            0
+         };
+      return dummy;
+   }
+#endif
+}
+
+NTSTATUS
+NTAPI
+MmWriteToSwapPage(SWAPENTRY SwapEntry, PFN_TYPE Page)
 {
    ULONG i, offset;
    LARGE_INTEGER file_offset;
    IO_STATUS_BLOCK Iosb;
    NTSTATUS Status;
-   
+   KEVENT Event;
+   UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)];
+   PMDL Mdl = (PMDL)MdlBase;
+
+   DPRINT("MmWriteToSwapPage\n");
+
    if (SwapEntry == 0)
-     {
-       KeBugCheck(0);
-       return(STATUS_UNSUCCESSFUL);
-     }
-   
+   {
+      KEBUGCHECK(0);
+      return(STATUS_UNSUCCESSFUL);
+   }
+
    i = FILE_FROM_ENTRY(SwapEntry);
    offset = OFFSET_FROM_ENTRY(SwapEntry);
-   
-   file_offset.QuadPart = offset * 4096;
-     
-   Status = IoPageWrite(PagingFileList[i]->FileObject,
-                       Mdl,
-                       &file_offset,
-                       &Iosb);
+
+   if (i >= MAX_PAGING_FILES)
+   {
+      DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry);
+      KEBUGCHECK(0);
+   }
+   if (PagingFileList[i]->FileObject == NULL ||
+         PagingFileList[i]->FileObject->DeviceObject == NULL)
+   {
+      DPRINT1("Bad paging file 0x%.8X\n", SwapEntry);
+      KEBUGCHECK(0);
+   }
+
+   MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
+   MmBuildMdlFromPages(Mdl, &Page);
+
+   file_offset.QuadPart = offset * PAGE_SIZE;
+   file_offset = MmGetOffsetPageFile(PagingFileList[i]->RetrievalPointers, file_offset);
+
+   KeInitializeEvent(&Event, NotificationEvent, FALSE);
+   Status = IoSynchronousPageWrite(PagingFileList[i]->FileObject,
+                                   Mdl,
+                                   &file_offset,
+                                   &Event,
+                                   &Iosb);
+   if (Status == STATUS_PENDING)
+   {
+      KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+      Status = Iosb.Status;
+   }
+   MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
    return(Status);
 }
 
-NTSTATUS MmReadFromSwapPage(SWAPENTRY SwapEntry, PMDL Mdl)
+NTSTATUS
+NTAPI
+MmReadFromSwapPage(SWAPENTRY SwapEntry, PFN_TYPE Page)
 {
    ULONG i, offset;
    LARGE_INTEGER file_offset;
    IO_STATUS_BLOCK Iosb;
    NTSTATUS Status;
-   
+   KEVENT Event;
+   UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)];
+   PMDL Mdl = (PMDL)MdlBase;
+
+   DPRINT("MmReadFromSwapPage\n");
+
    if (SwapEntry == 0)
-     {
-       KeBugCheck(0);
-       return(STATUS_UNSUCCESSFUL);
-     }
-   
+   {
+      KEBUGCHECK(0);
+      return(STATUS_UNSUCCESSFUL);
+   }
+
    i = FILE_FROM_ENTRY(SwapEntry);
    offset = OFFSET_FROM_ENTRY(SwapEntry);
-   
-   file_offset.QuadPart = offset * 4096;
-     
+
+   if (i >= MAX_PAGING_FILES)
+   {
+      DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry);
+      KEBUGCHECK(0);
+   }
+   if (PagingFileList[i]->FileObject == NULL ||
+         PagingFileList[i]->FileObject->DeviceObject == NULL)
+   {
+      DPRINT1("Bad paging file 0x%.8X\n", SwapEntry);
+      KEBUGCHECK(0);
+   }
+
+   MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
+   MmBuildMdlFromPages(Mdl, &Page);
+
+   file_offset.QuadPart = offset * PAGE_SIZE;
+   file_offset = MmGetOffsetPageFile(PagingFileList[i]->RetrievalPointers, file_offset);
+
+   KeInitializeEvent(&Event, NotificationEvent, FALSE);
    Status = IoPageRead(PagingFileList[i]->FileObject,
-                      Mdl,
-                      &file_offset,
-                      &Iosb,
-                      TRUE);
+                       Mdl,
+                       &file_offset,
+                       &Event,
+                       &Iosb);
+   if (Status == STATUS_PENDING)
+   {
+      KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+      Status = Iosb.Status;
+   }
+   MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
    return(Status);
 }
 
-VOID 
+VOID
+INIT_FUNCTION
+NTAPI
 MmInitPagingFile(VOID)
 {
    ULONG i;
-   
+
    KeInitializeSpinLock(&PagingFileListLock);
-   
+
    MiFreeSwapPages = 0;
    MiUsedSwapPages = 0;
    MiReservedSwapPages = 0;
-   
+
    for (i = 0; i < MAX_PAGING_FILES; i++)
-     {
-       PagingFileList[i] = NULL;
-     }
+   {
+      PagingFileList[i] = NULL;
+   }
+   MiPagingFileCount = 0;
+
+   /*
+    * Initialize the crash dump support.
+    */
+   if (MmCoreDumpType != MM_CORE_DUMP_TYPE_NONE)
+   {
+      MmCoreDumpPageFrame = MmAllocateSection(PAGE_SIZE, NULL);
+      if (MmCoreDumpType == MM_CORE_DUMP_TYPE_FULL)
+      {
+         MmCoreDumpSize = MmStats.NrTotalPages * 4096 + 1024 * 1024;
+      }
+      else
+      {
+         MmCoreDumpSize = 1024 * 1024;
+      }
+   }
 }
 
 BOOLEAN
+NTAPI
 MmReserveSwapPages(ULONG Nr)
 {
    KIRQL oldIrql;
    ULONG MiAvailSwapPages;
-   
+
    KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
    MiAvailSwapPages =
-     (MiFreeSwapPages * MM_PAGEFILE_COMMIT_RATIO) + MM_PAGEFILE_COMMIT_GRACE;
-   if (MM_PAGEFILE_COMMIT_RATIO != 0 && MiAvailSwapPages < MiReservedSwapPages)
-     {
-       KeReleaseSpinLock(&PagingFileListLock, oldIrql);
-       return(FALSE);
-     }
+      (MiFreeSwapPages * MM_PAGEFILE_COMMIT_RATIO) + MM_PAGEFILE_COMMIT_GRACE;
    MiReservedSwapPages = MiReservedSwapPages + Nr;
+   if (MM_PAGEFILE_COMMIT_RATIO != 0 && MiAvailSwapPages < MiReservedSwapPages)
+   {
+      KeReleaseSpinLock(&PagingFileListLock, oldIrql);
+      return(FALSE);
+   }
    KeReleaseSpinLock(&PagingFileListLock, oldIrql);
-
    return(TRUE);
 }
 
-VOID 
+VOID
+NTAPI
 MmDereserveSwapPages(ULONG Nr)
 {
    KIRQL oldIrql;
-   
+
    KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
    MiReservedSwapPages = MiReservedSwapPages - Nr;
    KeReleaseSpinLock(&PagingFileListLock, oldIrql);
 }
 
-static ULONG 
+static ULONG
 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile)
 {
    KIRQL oldIrql;
-   ULONG i;
-   ULONG off;
-   
+   ULONG i, j;
+
    KeAcquireSpinLock(&PagingFile->AllocMapLock, &oldIrql);
-   
+
    for (i = 0; i < PagingFile->AllocMapSize; i++)
-     {
-       off = find_first_zero_bit(PagingFile->AllocMap, 
-                                 PagingFile->AllocMapSize * 32);
-       clear_bit(off % 32, &PagingFile->AllocMap[off / 32]);
-       PagingFile->UsedPages--;
-       PagingFile->FreePages++;
-       KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
-       return(off);
-     }
-   
+   {
+      for (j = 0; j < 32; j++)
+      {
+         if (!(PagingFile->AllocMap[i] & (1 << j)))
+         {
+            PagingFile->AllocMap[i] |= (1 << j);
+            PagingFile->UsedPages++;
+            PagingFile->FreePages--;
+            KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
+            return((i * 32) + j);
+         }
+      }
+   }
+
    KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
-   return(0);
+   return(0xFFFFFFFF);
 }
 
-VOID 
+VOID
+NTAPI
 MmFreeSwapPage(SWAPENTRY Entry)
 {
    ULONG i;
    ULONG off;
    KIRQL oldIrql;
-   
+
    i = FILE_FROM_ENTRY(Entry);
    off = OFFSET_FROM_ENTRY(Entry);
-   
+
+   if (i >= MAX_PAGING_FILES)
+   {
+       DPRINT1("Bad swap entry 0x%.8X\n", Entry);
+       KEBUGCHECK(0);
+   }
+
    KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
+   if (PagingFileList[i] == NULL)
+   {
+      KEBUGCHECK(0);
+   }
    KeAcquireSpinLockAtDpcLevel(&PagingFileList[i]->AllocMapLock);
-   
-   set_bit(off % 32, &PagingFileList[i]->AllocMap[off / 32]);
-   
+
+   PagingFileList[i]->AllocMap[off >> 5] &= (~(1 << (off % 32)));
+
    PagingFileList[i]->FreePages++;
    PagingFileList[i]->UsedPages--;
-   
+
    MiFreeSwapPages++;
    MiUsedSwapPages--;
-   
+
    KeReleaseSpinLockFromDpcLevel(&PagingFileList[i]->AllocMapLock);
    KeReleaseSpinLock(&PagingFileListLock, oldIrql);
 }
 
-SWAPENTRY 
+BOOLEAN
+NTAPI
+MmIsAvailableSwapPage(VOID)
+{
+   return(MiFreeSwapPages > 0);
+}
+
+SWAPENTRY
+NTAPI
 MmAllocSwapPage(VOID)
 {
    KIRQL oldIrql;
    ULONG i;
    ULONG off;
    SWAPENTRY entry;
-   
+
    KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
-   
+
    if (MiFreeSwapPages == 0)
-     {
-       KeReleaseSpinLock(&PagingFileListLock, oldIrql);
-       return(0);
-     }
-   
+   {
+      KeReleaseSpinLock(&PagingFileListLock, oldIrql);
+      return(0);
+   }
+
    for (i = 0; i < MAX_PAGING_FILES; i++)
-     {
-       if (PagingFileList[i] != NULL &&
-           PagingFileList[i]->FreePages >= 1)
-         {          
-            off = MiAllocPageFromPagingFile(PagingFileList[i]);
-            if (off != 0)
-              {
-                 KeBugCheck(0);
-                 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
-                 return(STATUS_UNSUCCESSFUL);
-              }
-            MiUsedSwapPages++;
-            MiFreeSwapPages--;
-            KeReleaseSpinLock(&PagingFileListLock, oldIrql);
-            
-            entry = ENTRY_FROM_FILE_OFFSET(i, off);
-            return(entry);
-         }
-     }
-   
+   {
+      if (PagingFileList[i] != NULL &&
+            PagingFileList[i]->FreePages >= 1)
+      {
+         off = MiAllocPageFromPagingFile(PagingFileList[i]);
+         if (off == 0xFFFFFFFF)
+         {
+            KEBUGCHECK(0);
+            KeReleaseSpinLock(&PagingFileListLock, oldIrql);
+            return(STATUS_UNSUCCESSFUL);
+         }
+         MiUsedSwapPages++;
+         MiFreeSwapPages--;
+         KeReleaseSpinLock(&PagingFileListLock, oldIrql);
+
+         entry = ENTRY_FROM_FILE_OFFSET(i, off);
+         return(entry);
+      }
+   }
+
    KeReleaseSpinLock(&PagingFileListLock, oldIrql);
+   KEBUGCHECK(0);
    return(0);
 }
 
-#if 0
-NTSTATUS STDCALL MmDumpToPagingFile(PCONTEXT Context,
-                                   ULONG BugCode,
-                                   ULONG ExceptionCode,
-                                   ULONG Cr2)
+STATIC PRETRIEVEL_DESCRIPTOR_LIST FASTCALL
+MmAllocRetrievelDescriptorList(ULONG Pairs)
 {
-   ((PMM_CORE_DUMP_HEADER)MmCoreDumpHeader)->Magic = 
-     MM_CORE_DUMP_HEADER_MAGIC;
-   ((PMM_CORE_DUMP_HEADER)MmCoreDumpHeader)->Version = 
-     MM_CORE_DUMP_HEADER_VERSION;
-   memcpy(&((PMM_CORE_DUMP_HEADER)MmCoreDumpHeader)->Context,
-         Context,
-         sizeof(CONTEXT));
-   ((PMM_CORE_DUMP_HEADER)MmCoreDumpHeader)->DumpLength = 0;
-   ((PMM_CORE_DUMP_HEADER)MmCoreDumpHeader)->BugCode = BugCode;
-   ((PMM_CORE_DUMP_HEADER)MmCoreDumpHeader)->ExceptionCode = 
-     ExceptionCode;
-   ((PMM_CORE_DUMP_HEADER)MmCoreDumpHeader)->Cr2 = Cr2;
-   ((PMM_CORE_DUMP_HEADER)MmCoreDumpHeader)->Cr3 = 0;
+   ULONG Size;
+   PRETRIEVEL_DESCRIPTOR_LIST RetDescList;
+
+   Size = sizeof(RETRIEVEL_DESCRIPTOR_LIST) + Pairs * 2 * sizeof(LARGE_INTEGER);
+   RetDescList = ExAllocatePool(NonPagedPool, Size);
+   if (RetDescList)
+   {
+      RtlZeroMemory(RetDescList, Size);
+   }
+
+   return RetDescList;
 }
+
+NTSTATUS STDCALL
+MmDumpToPagingFile(ULONG BugCode,
+                   ULONG BugCodeParameter1,
+                   ULONG BugCodeParameter2,
+                   ULONG BugCodeParameter3,
+                   ULONG BugCodeParameter4,
+                   PKTRAP_FRAME TrapFrame)
+{
+   PMM_CORE_DUMP_HEADER Headers;
+   NTSTATUS Status;
+   UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)];
+   PMDL Mdl = (PMDL)MdlBase;
+   PETHREAD Thread = PsGetCurrentThread();
+   ULONG_PTR StackSize;
+   PULONG MdlMap;
+   LONGLONG NextOffset = 0;
+   ULONG i;
+   PRETRIEVAL_POINTERS_BUFFER RetrievalPointers;
+   LARGE_INTEGER DiskOffset;
+
+   if (MmCoreDumpPageFile == 0xFFFFFFFF)
+   {
+      return(STATUS_UNSUCCESSFUL);
+   }
+
+   DbgPrint("\nMM: Dumping core: ");
+
+   /* Prepare the dump headers. */
+   Headers = (PMM_CORE_DUMP_HEADER)MmCoreDumpPageFrame;
+   Headers->Magic = MM_CORE_DUMP_HEADER_MAGIC;
+   Headers->Version = MM_CORE_DUMP_HEADER_VERSION;
+   Headers->Type = MmCoreDumpType;
+   if (TrapFrame != NULL)
+   {
+      if (!(TrapFrame->EFlags & (1 << 17)))
+      {
+         memcpy(&Headers->TrapFrame, TrapFrame,
+                sizeof(KTRAP_FRAME) - (4 * sizeof(DWORD)));
+      }
+      else
+      {
+         memcpy(&Headers->TrapFrame, TrapFrame, sizeof(KTRAP_FRAME));
+      }
+   }
+   Headers->BugCheckCode = BugCode;
+   Headers->BugCheckParameters[0] = BugCodeParameter1;
+   Headers->BugCheckParameters[1] = BugCodeParameter2;
+   Headers->BugCheckParameters[2] = BugCodeParameter3;
+   Headers->BugCheckParameters[3] = BugCodeParameter4;
+   Headers->FaultingStackBase = (PVOID)Thread->Tcb.StackLimit;
+   Headers->FaultingStackSize =
+   StackSize = (ULONG_PTR)Thread->Tcb.StackBase - (ULONG_PTR)Thread->Tcb.StackLimit;
+   Headers->PhysicalMemorySize = MmStats.NrTotalPages * PAGE_SIZE;
+
+   /* Initialize the dump device. */
+   Status = MmCoreDumpFunctions->DumpInit();
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT1("MM: Failed to initialize core dump device.\n");
+      return(Status);
+   }
+
+   /* Initialize the MDL. */
+   MmInitializeMdl(Mdl, MmCoreDumpPageFrame, PAGE_SIZE);
+   Mdl->MdlFlags = MDL_PAGES_LOCKED|MDL_IO_PAGE_READ|MDL_SOURCE_IS_NONPAGED_POOL;
+   MdlMap = (PULONG)(Mdl + 1);
+
+
+   /* Initialize the retrieval offsets. */
+   RetrievalPointers = PagingFileList[MmCoreDumpPageFile]->RetrievalPointers;
+
+   /* Dump the header. */
+   MdlMap[0] = MmGetPhysicalAddress(MmCoreDumpPageFrame).QuadPart >> PAGE_SHIFT;
+#if defined(__GNUC__)
+
+   DiskOffset = MmGetOffsetPageFile(RetrievalPointers, (LARGE_INTEGER)0LL);
+#else
+
+   {
+      const LARGE_INTEGER dummy =
+         {
+            0
+         };
+      DiskOffset = MmGetOffsetPageFile(RetrievalPointers, dummy);
+   }
+#endif
+   DiskOffset.QuadPart += MmCoreDumpLcnMapping.LcnDiskOffset.QuadPart;
+   Status = MmCoreDumpFunctions->DumpWrite(DiskOffset, Mdl);
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT1("MM: Failed to write core dump header\n.");
+      return(Status);
+   }
+   NextOffset += PAGE_SIZE;
+   ;
+   DbgPrint("00");
+
+
+   /* Write out the contents of physical memory. */
+   if (MmCoreDumpType == MM_CORE_DUMP_TYPE_FULL)
+   {
+      for (i = 0; i < MmStats.NrTotalPages; i++)
+      {
+         MdlMap[0] = i;
+         MmCreateVirtualMappingForKernel(MmCoreDumpPageFrame,
+                                        PAGE_READWRITE,
+                                         MdlMap,
+                                        1);
+#if defined(__GNUC__)
+
+         DiskOffset = MmGetOffsetPageFile(RetrievalPointers,
+                                          (LARGE_INTEGER)NextOffset);
+#else
+
+         {
+            LARGE_INTEGER dummy;
+            dummy.QuadPart = NextOffset;
+            DiskOffset = MmGetOffsetPageFile(RetrievalPointers, dummy);
+         }
 #endif
+         DiskOffset.QuadPart += MmCoreDumpLcnMapping.LcnDiskOffset.QuadPart;
+         Status = MmCoreDumpFunctions->DumpWrite(DiskOffset, Mdl);
+        MmRawDeleteVirtualMapping(MmCoreDumpPageFrame);
+         if (!NT_SUCCESS(Status))
+         {
+            DPRINT1("MM: Failed to write page to core dump.\n");
+            return(Status);
+         }
+         if ((i % ((1024*1024) / PAGE_SIZE)) == 0)
+         {
+            DbgPrint("\b\b%.2d", i / ((1024*1024)/PAGE_SIZE));
+         }
+         NextOffset += PAGE_SIZE;
+      }
+   }
+
+   DbgPrint("\n");
+   MmCoreDumpFunctions->DumpFinish();
+   return(STATUS_SUCCESS);
+}
+
+NTSTATUS STDCALL
+MmInitializeCrashDump(HANDLE PageFileHandle, ULONG PageFileNum)
+{
+   PFILE_OBJECT PageFile;
+   PDEVICE_OBJECT PageFileDevice;
+   NTSTATUS Status;
+   PIRP Irp;
+   KEVENT Event;
+   IO_STATUS_BLOCK Iosb;
+   UNICODE_STRING DiskDumpName = RTL_CONSTANT_STRING(L"DiskDump");
+   ANSI_STRING ProcName;
+   PIO_STACK_LOCATION StackPtr;
+   PLDR_DATA_TABLE_ENTRY ModuleObject;
+
+   Status = ZwFsControlFile(PageFileHandle,
+                            0,
+                            NULL,
+                            NULL,
+                            &Iosb,
+                            FSCTL_ROS_QUERY_LCN_MAPPING,
+                            NULL,
+                            0,
+                            &MmCoreDumpLcnMapping,
+                            sizeof(ROS_QUERY_LCN_MAPPING));
+   if (!NT_SUCCESS(Status) ||
+         Iosb.Information != sizeof(ROS_QUERY_LCN_MAPPING))
+   {
+      return(Status);
+   }
+
+   /* Get the underlying storage device. */
+   Status =
+      ObReferenceObjectByHandle(PageFileHandle,
+                                FILE_ALL_ACCESS,
+                                NULL,
+                                KernelMode,
+                                (PVOID*)&PageFile,
+                                NULL);
+   if (!NT_SUCCESS(Status))
+   {
+      return(Status);
+   }
+
+   PageFileDevice = PageFile->Vpb->RealDevice;
+
+   /* Get the dump pointers. */
+   KeInitializeEvent(&Event, NotificationEvent, FALSE);
+   Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_DUMP_POINTERS,
+                                       PageFileDevice,
+                                       NULL,
+                                       0,
+                                       &MmCoreDumpPointers,
+                                       sizeof(MmCoreDumpPointers),
+                                       FALSE,
+                                       &Event,
+                                       &Iosb);
+   if(Irp == NULL)
+   {
+      ObDereferenceObject(PageFile);
+      return(STATUS_NO_MEMORY);// tMk - is this correct return code ???
+   }
+
+   StackPtr = IoGetNextIrpStackLocation(Irp);
+   StackPtr->FileObject = PageFile;
+   StackPtr->DeviceObject = PageFileDevice;
+   StackPtr->Parameters.DeviceIoControl.InputBufferLength = 0;
+   StackPtr->Parameters.DeviceIoControl.OutputBufferLength = sizeof(MmCoreDumpPointers);
+
+   Status = IoCallDriver(PageFileDevice,Irp);
+   if (Status == STATUS_PENDING)
+   {
+      Status = KeWaitForSingleObject(&Event,
+                                     Executive,
+                                     KernelMode,
+                                     FALSE,
+                                     NULL);
+   }
+   if (Status != STATUS_SUCCESS ||
+         Iosb.Information != sizeof(MmCoreDumpPointers))
+   {
+      ObDereferenceObject(PageFile);
+      return(Status);
+   }
+
+   /* Load the diskdump driver. */
+   ModuleObject = LdrGetModuleObject(&DiskDumpName);
+   if (ModuleObject == NULL)
+   {
+      return(STATUS_OBJECT_NAME_NOT_FOUND);
+   }
+   RtlInitAnsiString(&ProcName, "DiskDumpFunctions");
+   Status = LdrGetProcedureAddress(ModuleObject->DllBase,
+                                   &ProcName,
+                                   0,
+                                   (PVOID*)&MmCoreDumpFunctions);
+   if (!NT_SUCCESS(Status))
+   {
+      ObDereferenceObject(PageFile);
+      return(Status);
+   }
+
+   /* Prepare for disk dumping. */
+   Status = MmCoreDumpFunctions->DumpPrepare(PageFileDevice,
+            &MmCoreDumpPointers);
+   if (!NT_SUCCESS(Status))
+   {
+      ObDereferenceObject(PageFile);
+      return(Status);
+   }
+
+   MmCoreDumpPageFile = PageFileNum;
+   ObDereferenceObject(PageFile);
+   return(STATUS_SUCCESS);
+}
 
-NTSTATUS STDCALL 
-NtCreatePagingFile(IN  PUNICODE_STRING PageFileName,
-                  IN   ULONG           MinimumSize,
-                  IN   ULONG           MaximumSize,
-                  OUT  PULONG          ActualSize)
+NTSTATUS STDCALL
+NtCreatePagingFile(IN PUNICODE_STRING FileName,
+                   IN PLARGE_INTEGER InitialSize,
+                   IN PLARGE_INTEGER MaximumSize,
+                   IN ULONG Reserved)
 {
    NTSTATUS Status;
    OBJECT_ATTRIBUTES ObjectAttributes;
@@ -325,89 +784,344 @@ NtCreatePagingFile(IN    PUNICODE_STRING PageFileName,
    PPAGINGFILE PagingFile;
    KIRQL oldIrql;
    ULONG AllocMapSize;
+   FILE_FS_SIZE_INFORMATION FsSizeInformation;
+   PRETRIEVEL_DESCRIPTOR_LIST RetDescList;
+   PRETRIEVEL_DESCRIPTOR_LIST CurrentRetDescList;
    ULONG i;
-   
+   ULONG BytesPerAllocationUnit;
+   LARGE_INTEGER Vcn;
+   ULONG ExtentCount;
+   LARGE_INTEGER MaxVcn;
+   ULONG Count;
+   ULONG Size;
+   KPROCESSOR_MODE PreviousMode;
+   UNICODE_STRING CapturedFileName;
+   LARGE_INTEGER SafeInitialSize, SafeMaximumSize;
+
+   DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
+          FileName, InitialSize->QuadPart);
+
+   if (MiPagingFileCount >= MAX_PAGING_FILES)
+   {
+      return(STATUS_TOO_MANY_PAGING_FILES);
+   }
+
+   PreviousMode = ExGetPreviousMode();
+
+   if (PreviousMode != KernelMode)
+   {
+      _SEH_TRY
+      {
+         SafeInitialSize = ProbeForReadLargeInteger(InitialSize);
+         SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize);
+      }
+      _SEH_HANDLE
+      {
+         Status = _SEH_GetExceptionCode();
+      }
+      _SEH_END;
+
+      if (!NT_SUCCESS(Status))
+      {
+         return Status;
+      }
+   }
+   else
+   {
+      SafeInitialSize = *InitialSize;
+      SafeMaximumSize = *MaximumSize;
+   }
+
+   /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be
+      smaller than the maximum */
+   if (0 != SafeInitialSize.u.HighPart)
+   {
+      return STATUS_INVALID_PARAMETER_2;
+   }
+   if (0 != SafeMaximumSize.u.HighPart)
+   {
+      return STATUS_INVALID_PARAMETER_3;
+   }
+   if (SafeMaximumSize.u.LowPart < SafeInitialSize.u.LowPart)
+   {
+      return STATUS_INVALID_PARAMETER_MIX;
+   }
+
+   Status = ProbeAndCaptureUnicodeString(&CapturedFileName,
+                                         PreviousMode,
+                                         FileName);
+   if (!NT_SUCCESS(Status))
+   {
+      return(Status);
+   }
+
    InitializeObjectAttributes(&ObjectAttributes,
-                             PageFileName,
-                             0,
-                             NULL,
-                             NULL);
-   Status = NtCreateFile(&FileHandle,
-                        FILE_ALL_ACCESS,
-                        &ObjectAttributes,
-                        &IoStatus,
-                        NULL,
-                        0,
-                        0,
-                        FILE_OPEN,
-                        FILE_SYNCHRONOUS_IO_NONALERT,
-                        NULL,
-                        0);
+                              &CapturedFileName,
+                              0,
+                              NULL,
+                              NULL);
+
+   Status = IoCreateFile(&FileHandle,
+                         FILE_ALL_ACCESS,
+                         &ObjectAttributes,
+                         &IoStatus,
+                         NULL,
+                         0,
+                         0,
+                         FILE_OPEN_IF,
+                         FILE_SYNCHRONOUS_IO_NONALERT,
+                         NULL,
+                         0,
+                         CreateFileTypeNone,
+                         NULL,
+                         SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
+
+   ReleaseCapturedUnicodeString(&CapturedFileName,
+                                PreviousMode);
+   if (!NT_SUCCESS(Status))
+   {
+      return(Status);
+   }
+
+   Status = ZwQueryVolumeInformationFile(FileHandle,
+                                         &IoStatus,
+                                         &FsSizeInformation,
+                                         sizeof(FILE_FS_SIZE_INFORMATION),
+                                         FileFsSizeInformation);
+   if (!NT_SUCCESS(Status))
+   {
+      ZwClose(FileHandle);
+      return Status;
+   }
+
+   BytesPerAllocationUnit = FsSizeInformation.SectorsPerAllocationUnit *
+                            FsSizeInformation.BytesPerSector;
+   /* FIXME: If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is
+    * a problem if the paging file is fragmented. Suppose the first cluster
+    * of the paging file is cluster 3042 but cluster 3043 is NOT part of the
+    * paging file but of another file. We can't write a complete page (4096
+    * bytes) to the physical location of cluster 3042 then. */
+   if (BytesPerAllocationUnit % PAGE_SIZE)
+   {
+      DPRINT1("BytesPerAllocationUnit %d is not a multiple of PAGE_SIZE %d\n",
+              BytesPerAllocationUnit, PAGE_SIZE);
+      ZwClose(FileHandle);
+      return STATUS_UNSUCCESSFUL;
+   }
+
+   Status = ZwSetInformationFile(FileHandle,
+                                 &IoStatus,
+                                 &SafeInitialSize,
+                                 sizeof(LARGE_INTEGER),
+                                 FileAllocationInformation);
    if (!NT_SUCCESS(Status))
-     {
-       return(Status);
-     }
-   
+   {
+      ZwClose(FileHandle);
+      return(Status);
+   }
+
    Status = ObReferenceObjectByHandle(FileHandle,
-                                     FILE_ALL_ACCESS,
-                                     IoFileObjectType,
-                                     UserMode,
-                                     (PVOID*)&FileObject,
-                                     NULL);
+                                      FILE_ALL_ACCESS,
+                                      IoFileObjectType,
+                                      PreviousMode,
+                                      (PVOID*)&FileObject,
+                                      NULL);
    if (!NT_SUCCESS(Status))
-     {
-       NtClose(FileHandle);
-       return(Status);
-     }
-   
-   NtClose(FileHandle);
-   
+   {
+      ZwClose(FileHandle);
+      return(Status);
+   }
+
+   CurrentRetDescList = RetDescList = MmAllocRetrievelDescriptorList(PAIRS_PER_RUN);
+
+   if (CurrentRetDescList == NULL)
+   {
+      ObDereferenceObject(FileObject);
+      ZwClose(FileHandle);
+      return(STATUS_NO_MEMORY);
+   }
+
+#if defined(__GNUC__)
+   Vcn.QuadPart = 0LL;
+#else
+
+   Vcn.QuadPart = 0;
+#endif
+
+   ExtentCount = 0;
+   MaxVcn.QuadPart = (SafeInitialSize.QuadPart + BytesPerAllocationUnit - 1) / BytesPerAllocationUnit;
+   while(1)
+   {
+      Status = ZwFsControlFile(FileHandle,
+                               0,
+                               NULL,
+                               NULL,
+                               &IoStatus,
+                               FSCTL_GET_RETRIEVAL_POINTERS,
+                               &Vcn,
+                               sizeof(LARGE_INTEGER),
+                               &CurrentRetDescList->RetrievalPointers,
+                               sizeof(RETRIEVAL_POINTERS_BUFFER) + PAIRS_PER_RUN * 2 * sizeof(LARGE_INTEGER));
+      if (!NT_SUCCESS(Status))
+      {
+         while (RetDescList)
+         {
+            CurrentRetDescList = RetDescList;
+            RetDescList = RetDescList->Next;
+            ExFreePool(CurrentRetDescList);
+         }
+         ObDereferenceObject(FileObject);
+         ZwClose(FileHandle);
+         return(Status);
+      }
+      ExtentCount += CurrentRetDescList->RetrievalPointers.ExtentCount;
+      if (CurrentRetDescList->RetrievalPointers.Extents[CurrentRetDescList->RetrievalPointers.ExtentCount-1].NextVcn.QuadPart < MaxVcn.QuadPart)
+      {
+         CurrentRetDescList->Next = MmAllocRetrievelDescriptorList(PAIRS_PER_RUN);
+         if (CurrentRetDescList->Next == NULL)
+         {
+            while (RetDescList)
+            {
+               CurrentRetDescList = RetDescList;
+               RetDescList = RetDescList->Next;
+               ExFreePool(CurrentRetDescList);
+            }
+            ObDereferenceObject(FileObject);
+            ZwClose(FileHandle);
+            return(STATUS_NO_MEMORY);
+         }
+         Vcn = CurrentRetDescList->RetrievalPointers.Extents[CurrentRetDescList->RetrievalPointers.ExtentCount-1].NextVcn;
+         CurrentRetDescList = CurrentRetDescList->Next;
+      }
+      else
+      {
+         break;
+      }
+   }
+
    PagingFile = ExAllocatePool(NonPagedPool, sizeof(*PagingFile));
    if (PagingFile == NULL)
-     {
-       ObDereferenceObject(FileObject);
-       return(STATUS_NO_MEMORY);
-     }
-   
+   {
+      while (RetDescList)
+      {
+         CurrentRetDescList = RetDescList;
+         RetDescList = RetDescList->Next;
+         ExFreePool(CurrentRetDescList);
+      }
+      ObDereferenceObject(FileObject);
+      ZwClose(FileHandle);
+      return(STATUS_NO_MEMORY);
+   }
+
+   RtlZeroMemory(PagingFile, sizeof(*PagingFile));
+
    PagingFile->FileObject = FileObject;
-   PagingFile->MaximumSize = PagingFile->CurrentSize = MinimumSize;
-   PagingFile->FreePages = MinimumSize;
+   PagingFile->MaximumSize.QuadPart = SafeMaximumSize.QuadPart;
+   PagingFile->CurrentSize.QuadPart = SafeInitialSize.QuadPart;
+   PagingFile->FreePages = (ULONG)(SafeInitialSize.QuadPart / PAGE_SIZE);
    PagingFile->UsedPages = 0;
    KeInitializeSpinLock(&PagingFile->AllocMapLock);
-   
-   AllocMapSize = (MinimumSize / 32) + 1;
-   PagingFile->AllocMap = ExAllocatePool(NonPagedPool, 
-                                        AllocMapSize * sizeof(ULONG));
+
+   AllocMapSize = (PagingFile->FreePages / 32) + 1;
+   PagingFile->AllocMap = ExAllocatePool(NonPagedPool,
+                                         AllocMapSize * sizeof(ULONG));
    PagingFile->AllocMapSize = AllocMapSize;
-   
+
    if (PagingFile->AllocMap == NULL)
-     {
-       ExFreePool(PagingFile);
-       ObDereferenceObject(FileObject);
-       return(STATUS_NO_MEMORY);
-     }
-   
-   KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
-   for (i = 0; i < MAX_PAGING_FILES; i++)
-     {
-       if (PagingFileList[i] == NULL)
-         {
-            PagingFileList[i] = PagingFile;
-            break;
-         }
-     }
-   MiFreeSwapPages = MiFreeSwapPages + MinimumSize;
-   KeReleaseSpinLock(&PagingFileListLock, oldIrql);
-   
-   return(STATUS_SUCCESS);
-}
+   {
+      while (RetDescList)
+      {
+         CurrentRetDescList = RetDescList;
+         RetDescList = RetDescList->Next;
+         ExFreePool(CurrentRetDescList);
+      }
+      ExFreePool(PagingFile);
+      ObDereferenceObject(FileObject);
+      ZwClose(FileHandle);
+      return(STATUS_NO_MEMORY);
+   }
+   DPRINT("ExtentCount: %d\n", ExtentCount);
+   Size = sizeof(RETRIEVAL_POINTERS_BUFFER) + ExtentCount * 2 * sizeof(LARGE_INTEGER);
+   PagingFile->RetrievalPointers = ExAllocatePool(NonPagedPool, Size);
+   if (PagingFile->RetrievalPointers == NULL)
+   {
+      while (RetDescList)
+      {
+         CurrentRetDescList = RetDescList;
+         RetDescList = RetDescList->Next;
+         ExFreePool(CurrentRetDescList);
+      }
+      ExFreePool(PagingFile->AllocMap);
+      ExFreePool(PagingFile);
+      ObDereferenceObject(FileObject);
+      ZwClose(FileHandle);
+      return(STATUS_NO_MEMORY);
+   }
 
+   RtlZeroMemory(PagingFile->AllocMap, AllocMapSize * sizeof(ULONG));
+   RtlZeroMemory(PagingFile->RetrievalPointers, Size);
 
-/* EOF */
+   Count = 0;
+   PagingFile->RetrievalPointers->ExtentCount = ExtentCount;
+   PagingFile->RetrievalPointers->StartingVcn = RetDescList->RetrievalPointers.StartingVcn;
+   CurrentRetDescList = RetDescList;
+   while (CurrentRetDescList)
+   {
+      memcpy(&PagingFile->RetrievalPointers->Extents[Count],
+             CurrentRetDescList->RetrievalPointers.Extents,
+             CurrentRetDescList->RetrievalPointers.ExtentCount * 2 * sizeof(LARGE_INTEGER));
+      Count += CurrentRetDescList->RetrievalPointers.ExtentCount;
+      RetDescList = CurrentRetDescList;
+      CurrentRetDescList = CurrentRetDescList->Next;
+      ExFreePool(RetDescList);
+   }
 
+   if (PagingFile->RetrievalPointers->ExtentCount != ExtentCount ||
+         PagingFile->RetrievalPointers->Extents[ExtentCount - 1].NextVcn.QuadPart != MaxVcn.QuadPart)
+   {
+      ExFreePool(PagingFile->RetrievalPointers);
+      ExFreePool(PagingFile->AllocMap);
+      ExFreePool(PagingFile);
+      ObDereferenceObject(FileObject);
+      ZwClose(FileHandle);
+      return(STATUS_UNSUCCESSFUL);
+   }
 
+   /*
+    * Change the entries from lcn's to volume offset's.
+    */
+   PagingFile->RetrievalPointers->StartingVcn.QuadPart *= BytesPerAllocationUnit;
+   for (i = 0; i < ExtentCount; i++)
+   {
+      PagingFile->RetrievalPointers->Extents[i].Lcn.QuadPart *= BytesPerAllocationUnit;
+      PagingFile->RetrievalPointers->Extents[i].NextVcn.QuadPart *= BytesPerAllocationUnit;
+   }
 
+   KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
+   for (i = 0; i < MAX_PAGING_FILES; i++)
+   {
+      if (PagingFileList[i] == NULL)
+      {
+         PagingFileList[i] = PagingFile;
+         break;
+      }
+   }
+   MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreePages;
+   MiPagingFileCount++;
+   KeReleaseSpinLock(&PagingFileListLock, oldIrql);
 
+   /* Check whether this pagefile can be a crash dump target. */
+   if (MmCoreDumpType != MM_CORE_DUMP_TYPE_NONE &&
+         PagingFile->CurrentSize.QuadPart >= MmCoreDumpSize &&
+         MmCoreDumpPageFile == 0xFFFFFFFF)
+   {
+      MmInitializeCrashDump(FileHandle, i);
+   }
+   ZwClose(FileHandle);
 
+   MmSwapSpaceMessage = FALSE;
 
+   return(STATUS_SUCCESS);
+}
 
+/* EOF */