[NTOSKRNL] Don't need all access for file object
[reactos.git] / ntoskrnl / mm / pagefile.c
index b26e523..9855578 100644 (file)
@@ -21,6 +21,7 @@
  * FILE:            ntoskrnl/mm/pagefile.c
  * PURPOSE:         Paging file functions
  * PROGRAMMER:      David Welch (welch@mcmail.com)
+ *                  Pierre Schweitzer
  * UPDATE HISTORY:
  *                  Created 22/05/98
  */
 #pragma alloc_text(INIT, MmInitPagingFile)
 #endif
 
-PVOID
-NTAPI
-MiFindExportedRoutineByName(IN PVOID DllBase,
-                            IN PANSI_STRING ExportName);
-
-/* TYPES *********************************************************************/
-
-typedef struct _PAGINGFILE
-{
-   LIST_ENTRY PagingFileListEntry;
-   PFILE_OBJECT FileObject;
-   LARGE_INTEGER MaximumSize;
-   LARGE_INTEGER CurrentSize;
-   ULONG FreePages;
-   ULONG UsedPages;
-   PULONG AllocMap;
-   KSPIN_LOCK AllocMapLock;
-   ULONG AllocMapSize;
-   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 */
-static PPAGINGFILE PagingFileList[MAX_PAGING_FILES];
+PMMPAGING_FILE MmPagingFile[MAX_PAGING_FILES];
 
 /* Lock for examining the list of paging files */
-static KSPIN_LOCK PagingFileListLock;
+KGUARDED_MUTEX MmPageFileCreationLock;
 
 /* Number of paging files */
-static ULONG MiPagingFileCount;
 ULONG MmNumberOfPagingFiles;
 
 /* Number of pages that are available for swapping */
@@ -115,6 +84,9 @@ static PFN_COUNT MiReservedSwapPages;
 #define OFFSET_FROM_ENTRY(i) ((i) >> 11)
 #define ENTRY_FROM_FILE_OFFSET(i, j) ((i) | ((j) << 11) | 0x400)
 
+/* Make sure there can be only 16 paging files */
+C_ASSERT(FILE_FROM_ENTRY(0xffffffff) < MAX_PAGING_FILES);
+
 static BOOLEAN MmSwapSpaceMessage = FALSE;
 
 /* FUNCTIONS *****************************************************************/
@@ -137,10 +109,10 @@ MmIsFileObjectAPagingFile(PFILE_OBJECT FileObject)
     ULONG i;
 
     /* Loop through all the paging files */
-    for (i = 0; i < MiPagingFileCount; i++)
+    for (i = 0; i < MmNumberOfPagingFiles; i++)
     {
         /* Check if this is one of them */
-        if (PagingFileList[i]->FileObject == FileObject) return TRUE;
+        if (MmPagingFile[i]->FileObject == FileObject) return TRUE;
     }
 
     /* Nothing found */
@@ -151,714 +123,676 @@ VOID
 NTAPI
 MmShowOutOfSpaceMessagePagingFile(VOID)
 {
-   if (!MmSwapSpaceMessage)
-   {
-      DPRINT1("MM: Out of swap space.\n");
-      MmSwapSpaceMessage = TRUE;
-   }
-}
-
-static LARGE_INTEGER
-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(MEMORY_MANAGEMENT);
-#if defined(__GNUC__)
-
-   return (LARGE_INTEGER)0LL;
-#else
-
-   {
-      const LARGE_INTEGER dummy =
-         {
-            0
-         };
-      return dummy;
-   }
-#endif
+    if (!MmSwapSpaceMessage)
+    {
+        DPRINT1("MM: Out of swap space.\n");
+        MmSwapSpaceMessage = TRUE;
+    }
 }
 
 NTSTATUS
 NTAPI
 MmWriteToSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)
 {
-   ULONG i;
-   ULONG_PTR 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(MEMORY_MANAGEMENT);
-      return(STATUS_UNSUCCESSFUL);
-   }
-
-   i = FILE_FROM_ENTRY(SwapEntry);
-   offset = OFFSET_FROM_ENTRY(SwapEntry);
-
-   if (i >= MAX_PAGING_FILES)
-   {
-      DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry);
-      KeBugCheck(MEMORY_MANAGEMENT);
-   }
-   if (PagingFileList[i]->FileObject == NULL ||
-         PagingFileList[i]->FileObject->DeviceObject == NULL)
-   {
-      DPRINT1("Bad paging file 0x%.8X\n", SwapEntry);
-      KeBugCheck(MEMORY_MANAGEMENT);
-   }
-
-   MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
-   MmBuildMdlFromPages(Mdl, &Page);
-   Mdl->MdlFlags |= MDL_PAGES_LOCKED;
-
-   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;
-   }
-
-   if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
-   {
-      MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
-   }
-   return(Status);
+    ULONG i;
+    ULONG_PTR 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(MEMORY_MANAGEMENT);
+        return(STATUS_UNSUCCESSFUL);
+    }
+
+    i = FILE_FROM_ENTRY(SwapEntry);
+    offset = OFFSET_FROM_ENTRY(SwapEntry) - 1;
+
+    if (MmPagingFile[i]->FileObject == NULL ||
+            MmPagingFile[i]->FileObject->DeviceObject == NULL)
+    {
+        DPRINT1("Bad paging file 0x%.8X\n", SwapEntry);
+        KeBugCheck(MEMORY_MANAGEMENT);
+    }
+
+    MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
+    MmBuildMdlFromPages(Mdl, &Page);
+    Mdl->MdlFlags |= MDL_PAGES_LOCKED;
+
+    file_offset.QuadPart = offset * PAGE_SIZE;
+
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+    Status = IoSynchronousPageWrite(MmPagingFile[i]->FileObject,
+                                    Mdl,
+                                    &file_offset,
+                                    &Event,
+                                    &Iosb);
+    if (Status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+        Status = Iosb.Status;
+    }
+
+    if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
+    {
+        MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
+    }
+    return(Status);
 }
 
+
 NTSTATUS
 NTAPI
 MmReadFromSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)
 {
-   ULONG i;
-   ULONG_PTR 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(MEMORY_MANAGEMENT);
-      return(STATUS_UNSUCCESSFUL);
-   }
-
-   i = FILE_FROM_ENTRY(SwapEntry);
-   offset = OFFSET_FROM_ENTRY(SwapEntry);
-
-   if (i >= MAX_PAGING_FILES)
-   {
-      DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry);
-      KeBugCheck(MEMORY_MANAGEMENT);
-   }
-   if (PagingFileList[i]->FileObject == NULL ||
-         PagingFileList[i]->FileObject->DeviceObject == NULL)
-   {
-      DPRINT1("Bad paging file 0x%.8X\n", SwapEntry);
-      KeBugCheck(MEMORY_MANAGEMENT);
-   }
-
-   MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
-   MmBuildMdlFromPages(Mdl, &Page);
-   Mdl->MdlFlags |= MDL_PAGES_LOCKED;
-
-   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,
-                       &Event,
-                       &Iosb);
-   if (Status == STATUS_PENDING)
-   {
-      KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
-      Status = Iosb.Status;
-   }
-   if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
-   {
-      MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
-   }
-   return(Status);
+    return MiReadPageFile(Page, FILE_FROM_ENTRY(SwapEntry), OFFSET_FROM_ENTRY(SwapEntry) - 1);
 }
 
-VOID
-INIT_FUNCTION
+NTSTATUS
 NTAPI
-MmInitPagingFile(VOID)
+MiReadPageFile(
+    _In_ PFN_NUMBER Page,
+    _In_ ULONG PageFileIndex,
+    _In_ ULONG_PTR PageFileOffset)
 {
-   ULONG i;
+    LARGE_INTEGER file_offset;
+    IO_STATUS_BLOCK Iosb;
+    NTSTATUS Status;
+    KEVENT Event;
+    UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)];
+    PMDL Mdl = (PMDL)MdlBase;
+    PMMPAGING_FILE PagingFile;
 
-   KeInitializeSpinLock(&PagingFileListLock);
+    DPRINT("MiReadSwapFile\n");
 
-   MiFreeSwapPages = 0;
-   MiUsedSwapPages = 0;
-   MiReservedSwapPages = 0;
+    if (PageFileOffset == 0)
+    {
+        KeBugCheck(MEMORY_MANAGEMENT);
+        return(STATUS_UNSUCCESSFUL);
+    }
 
-   for (i = 0; i < MAX_PAGING_FILES; i++)
-   {
-      PagingFileList[i] = NULL;
-   }
-   MiPagingFileCount = 0;
-}
+    ASSERT(PageFileIndex < MAX_PAGING_FILES);
 
-BOOLEAN
-NTAPI
-MmReserveSwapPages(ULONG Nr)
-{
-   KIRQL oldIrql;
-   ULONG MiAvailSwapPages;
-
-   KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
-   MiAvailSwapPages =
-      (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);
+    PagingFile = MmPagingFile[PageFileIndex];
+
+    if (PagingFile->FileObject == NULL || PagingFile->FileObject->DeviceObject == NULL)
+    {
+        DPRINT1("Bad paging file %u\n", PageFileIndex);
+        KeBugCheck(MEMORY_MANAGEMENT);
+    }
+
+    MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
+    MmBuildMdlFromPages(Mdl, &Page);
+    Mdl->MdlFlags |= MDL_PAGES_LOCKED;
+
+    file_offset.QuadPart = PageFileOffset * PAGE_SIZE;
+
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+    Status = IoPageRead(PagingFile->FileObject,
+                        Mdl,
+                        &file_offset,
+                        &Event,
+                        &Iosb);
+    if (Status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+        Status = Iosb.Status;
+    }
+    if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
+    {
+        MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
+    }
+    return(Status);
 }
 
 VOID
+INIT_FUNCTION
 NTAPI
-MmDereserveSwapPages(ULONG Nr)
+MmInitPagingFile(VOID)
 {
-   KIRQL oldIrql;
+    ULONG i;
 
-   KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
-   MiReservedSwapPages = MiReservedSwapPages - Nr;
-   KeReleaseSpinLock(&PagingFileListLock, oldIrql);
-}
+    KeInitializeGuardedMutex(&MmPageFileCreationLock);
 
-static ULONG
-MiAllocPageFromPagingFile(PPAGINGFILE PagingFile)
-{
-   KIRQL oldIrql;
-   ULONG i, j;
-
-   KeAcquireSpinLock(&PagingFile->AllocMapLock, &oldIrql);
-
-   for (i = 0; i < PagingFile->AllocMapSize; i++)
-   {
-      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(0xFFFFFFFF);
+    MiFreeSwapPages = 0;
+    MiUsedSwapPages = 0;
+    MiReservedSwapPages = 0;
+
+    for (i = 0; i < MAX_PAGING_FILES; i++)
+    {
+        MmPagingFile[i] = NULL;
+    }
+    MmNumberOfPagingFiles = 0;
 }
 
 VOID
 NTAPI
 MmFreeSwapPage(SWAPENTRY Entry)
 {
-   ULONG i;
-   ULONG_PTR off;
-   KIRQL oldIrql;
+    ULONG i;
+    ULONG_PTR off;
+    PMMPAGING_FILE PagingFile;
 
-   i = FILE_FROM_ENTRY(Entry);
-   off = OFFSET_FROM_ENTRY(Entry);
+    i = FILE_FROM_ENTRY(Entry);
+    off = OFFSET_FROM_ENTRY(Entry) - 1;
 
-   if (i >= MAX_PAGING_FILES)
-   {
-      DPRINT1("Bad swap entry 0x%.8X\n", Entry);
-      KeBugCheck(MEMORY_MANAGEMENT);
-   }
+    KeAcquireGuardedMutex(&MmPageFileCreationLock);
 
-   KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
-   if (PagingFileList[i] == NULL)
-   {
-      KeBugCheck(MEMORY_MANAGEMENT);
-   }
-   KeAcquireSpinLockAtDpcLevel(&PagingFileList[i]->AllocMapLock);
+    PagingFile = MmPagingFile[i];
+    if (PagingFile == NULL)
+    {
+        KeBugCheck(MEMORY_MANAGEMENT);
+    }
 
-   PagingFileList[i]->AllocMap[off >> 5] &= (~(1 << (off % 32)));
+    RtlClearBit(PagingFile->Bitmap, off >> 5);
 
-   PagingFileList[i]->FreePages++;
-   PagingFileList[i]->UsedPages--;
+    PagingFile->FreeSpace++;
+    PagingFile->CurrentUsage--;
 
-   MiFreeSwapPages++;
-   MiUsedSwapPages--;
+    MiFreeSwapPages++;
+    MiUsedSwapPages--;
 
-   KeReleaseSpinLockFromDpcLevel(&PagingFileList[i]->AllocMapLock);
-   KeReleaseSpinLock(&PagingFileListLock, oldIrql);
-}
-
-BOOLEAN
-NTAPI
-MmIsAvailableSwapPage(VOID)
-{
-   return(MiFreeSwapPages > 0);
+    KeReleaseGuardedMutex(&MmPageFileCreationLock);
 }
 
 SWAPENTRY
 NTAPI
 MmAllocSwapPage(VOID)
 {
-   KIRQL oldIrql;
-   ULONG i;
-   ULONG off;
-   SWAPENTRY entry;
-
-   KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
-
-   if (MiFreeSwapPages == 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 == 0xFFFFFFFF)
-         {
-            KeBugCheck(MEMORY_MANAGEMENT);
-            KeReleaseSpinLock(&PagingFileListLock, oldIrql);
-            return(STATUS_UNSUCCESSFUL);
-         }
-         MiUsedSwapPages++;
-         MiFreeSwapPages--;
-         KeReleaseSpinLock(&PagingFileListLock, oldIrql);
-
-         entry = ENTRY_FROM_FILE_OFFSET(i, off);
-         return(entry);
-      }
-   }
-
-   KeReleaseSpinLock(&PagingFileListLock, oldIrql);
-   KeBugCheck(MEMORY_MANAGEMENT);
-   return(0);
-}
+    ULONG i;
+    ULONG off;
+    SWAPENTRY entry;
 
-static PRETRIEVEL_DESCRIPTOR_LIST FASTCALL
-MmAllocRetrievelDescriptorList(ULONG Pairs)
-{
-   ULONG Size;
-   PRETRIEVEL_DESCRIPTOR_LIST RetDescList;
+    KeAcquireGuardedMutex(&MmPageFileCreationLock);
+
+    if (MiFreeSwapPages == 0)
+    {
+        KeReleaseGuardedMutex(&MmPageFileCreationLock);
+        return(0);
+    }
+
+    for (i = 0; i < MAX_PAGING_FILES; i++)
+    {
+        if (MmPagingFile[i] != NULL &&
+                MmPagingFile[i]->FreeSpace >= 1)
+        {
+            off = RtlFindClearBitsAndSet(MmPagingFile[i]->Bitmap, 1, 0);
+            if (off == 0xFFFFFFFF)
+            {
+                KeBugCheck(MEMORY_MANAGEMENT);
+                KeReleaseGuardedMutex(&MmPageFileCreationLock);
+                return(STATUS_UNSUCCESSFUL);
+            }
+            MiUsedSwapPages++;
+            MiFreeSwapPages--;
+            KeReleaseGuardedMutex(&MmPageFileCreationLock);
 
-   Size = sizeof(RETRIEVEL_DESCRIPTOR_LIST) + Pairs * 2 * sizeof(LARGE_INTEGER);
-   RetDescList = ExAllocatePool(NonPagedPool, Size);
-   if (RetDescList)
-   {
-      RtlZeroMemory(RetDescList, Size);
-   }
+            entry = ENTRY_FROM_FILE_OFFSET(i, off + 1);
+            return(entry);
+        }
+    }
 
-   return RetDescList;
+    KeReleaseGuardedMutex(&MmPageFileCreationLock);
+    KeBugCheck(MEMORY_MANAGEMENT);
+    return(0);
 }
 
 NTSTATUS NTAPI
 NtCreatePagingFile(IN PUNICODE_STRING FileName,
-                   IN PLARGE_INTEGER InitialSize,
+                   IN PLARGE_INTEGER MinimumSize,
                    IN PLARGE_INTEGER MaximumSize,
                    IN ULONG Reserved)
 {
-   NTSTATUS Status;
-   OBJECT_ATTRIBUTES ObjectAttributes;
-   HANDLE FileHandle;
-   IO_STATUS_BLOCK IoStatus;
-   PFILE_OBJECT FileObject;
-   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)
-   {
-      _SEH2_TRY
-      {
-         SafeInitialSize = ProbeForReadLargeInteger(InitialSize);
-         SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize);
-      }
-      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-      {
-          /* Return the exception code */
-          _SEH2_YIELD(return _SEH2_GetExceptionCode());
-      }
-      _SEH2_END;
-   }
-   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,
-                              &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))
-   {
-      ZwClose(FileHandle);
-      return(Status);
-   }
-
-   Status = ObReferenceObjectByHandle(FileHandle,
-                                      FILE_ALL_ACCESS,
-                                      IoFileObjectType,
-                                      PreviousMode,
-                                      (PVOID*)&FileObject,
-                                      NULL);
-   if (!NT_SUCCESS(Status))
-   {
-      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
+    NTSTATUS Status;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    HANDLE FileHandle;
+    IO_STATUS_BLOCK IoStatus;
+    PFILE_OBJECT FileObject;
+    PMMPAGING_FILE PagingFile;
+    ULONG AllocMapSize;
+    ULONG Count;
+    KPROCESSOR_MODE PreviousMode;
+    UNICODE_STRING PageFileName;
+    LARGE_INTEGER SafeMinimumSize, SafeMaximumSize, AllocationSize;
+    FILE_FS_DEVICE_INFORMATION FsDeviceInfo;
+    SECURITY_DESCRIPTOR SecurityDescriptor;
+    PACL Dacl;
+    PWSTR Buffer;
+
+    DPRINT("NtCreatePagingFile(FileName %wZ, MinimumSize %I64d)\n",
+           FileName, MinimumSize->QuadPart);
+
+    PAGED_CODE();
+
+    if (MmNumberOfPagingFiles >= MAX_PAGING_FILES)
+    {
+        return STATUS_TOO_MANY_PAGING_FILES;
+    }
 
-   ExtentCount = 0;
-   MaxVcn.QuadPart = (SafeInitialSize.QuadPart + BytesPerAllocationUnit - 1) / BytesPerAllocationUnit;
-   while(1)
-   {
-      Status = ZwFsControlFile(FileHandle,
-                               0,
-                               NULL,
+    PreviousMode = ExGetPreviousMode();
+
+    if (PreviousMode != KernelMode)
+    {
+        if (SeSinglePrivilegeCheck(SeCreatePagefilePrivilege, PreviousMode) != TRUE)
+        {
+            return STATUS_PRIVILEGE_NOT_HELD;
+        }
+
+        _SEH2_TRY
+        {
+            SafeMinimumSize = ProbeForReadLargeInteger(MinimumSize);
+            SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize);
+
+            PageFileName.Length = FileName->Length;
+            PageFileName.MaximumLength = FileName->MaximumLength;
+            PageFileName.Buffer = FileName->Buffer;
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Return the exception code */
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+    else
+    {
+        SafeMinimumSize = *MinimumSize;
+        SafeMaximumSize = *MaximumSize;
+
+        PageFileName.Length = FileName->Length;
+        PageFileName.MaximumLength = FileName->MaximumLength;
+        PageFileName.Buffer = FileName->Buffer;
+    }
+
+    /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be
+       smaller than the maximum */
+    if (0 != SafeMinimumSize.u.HighPart)
+    {
+        return STATUS_INVALID_PARAMETER_2;
+    }
+    if (0 != SafeMaximumSize.u.HighPart)
+    {
+        return STATUS_INVALID_PARAMETER_3;
+    }
+    if (SafeMaximumSize.u.LowPart < SafeMinimumSize.u.LowPart)
+    {
+        return STATUS_INVALID_PARAMETER_MIX;
+    }
+
+    /* Validate name length */
+    if (PageFileName.Length > 128 * sizeof(WCHAR))
+    {
+        return STATUS_OBJECT_NAME_INVALID;
+    }
+
+    /* We won't care about any potential UNICODE_NULL */
+    PageFileName.MaximumLength = PageFileName.Length;
+    /* Allocate a buffer to keep name copy */
+    Buffer = ExAllocatePoolWithTag(PagedPool, PageFileName.Length, TAG_MM);
+    if (Buffer == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Copy name */
+    if (PreviousMode != KernelMode)
+    {
+        _SEH2_TRY
+        {
+            if (PageFileName.Length != 0)
+            {
+                ProbeForRead(PageFileName.Buffer, PageFileName.Length, sizeof(WCHAR));
+            }
+
+            RtlCopyMemory(Buffer, PageFileName.Buffer, PageFileName.Length);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            ExFreePoolWithTag(Buffer, TAG_MM);
+
+            /* Return the exception code */
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+    else
+    {
+        RtlCopyMemory(Buffer, PageFileName.Buffer, PageFileName.Length);
+    }
+
+    /* Erase caller's buffer with ours */
+    PageFileName.Buffer = Buffer;
+
+    /* Create the security descriptor for the page file */
+    Status = RtlCreateSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
+    if (!NT_SUCCESS(Status))
+    {
+        ExFreePoolWithTag(Buffer, TAG_MM);
+        return Status;
+    }
+
+    /* Create the DACL: we will only allow two SIDs */
+    Count = sizeof(ACL) + (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
+                          (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid));
+    Dacl = ExAllocatePoolWithTag(PagedPool, Count, 'lcaD');
+    if (Dacl == NULL)
+    {
+        ExFreePoolWithTag(Buffer, TAG_MM);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Initialize the DACL */
+    Status = RtlCreateAcl(Dacl, Count, ACL_REVISION);
+    if (!NT_SUCCESS(Status))
+    {
+        ExFreePoolWithTag(Dacl, 'lcaD');
+        ExFreePoolWithTag(Buffer, TAG_MM);
+        return Status;
+    }
+
+    /* Grant full access to admins */
+    Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeAliasAdminsSid);
+    if (!NT_SUCCESS(Status))
+    {
+        ExFreePoolWithTag(Dacl, 'lcaD');
+        ExFreePoolWithTag(Buffer, TAG_MM);
+        return Status;
+    }
+
+    /* Grant full access to SYSTEM */
+    Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeLocalSystemSid);
+    if (!NT_SUCCESS(Status))
+    {
+        ExFreePoolWithTag(Dacl, 'lcaD');
+        ExFreePoolWithTag(Buffer, TAG_MM);
+        return Status;
+    }
+
+    /* Attach the DACL to the security descriptor */
+    Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl, FALSE);
+    if (!NT_SUCCESS(Status))
+    {
+        ExFreePoolWithTag(Dacl, 'lcaD');
+        ExFreePoolWithTag(Buffer, TAG_MM);
+        return Status;
+    }
+
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &PageFileName,
+                               OBJ_KERNEL_HANDLE,
                                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)
+                               &SecurityDescriptor);
+
+    /* Make sure we can at least store a complete page:
+     * 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. */
+    AllocationSize.QuadPart = SafeMinimumSize.QuadPart + PAGE_SIZE;
+
+    /* First, attempt to replace the page file, if existing */
+    Status = IoCreateFile(&FileHandle,
+                          SYNCHRONIZE | WRITE_DAC | FILE_READ_DATA | FILE_WRITE_DATA,
+                          &ObjectAttributes,
+                          &IoStatus,
+                          &AllocationSize,
+                          FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
+                          FILE_SHARE_WRITE,
+                          FILE_SUPERSEDE,
+                          FILE_DELETE_ON_CLOSE | FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING,
+                          NULL,
+                          0,
+                          CreateFileTypeNone,
+                          NULL,
+                          SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
+    /* If we failed, relax a bit constraints, someone may be already holding the
+     * the file, so share write, don't attempt to replace and don't delete on close
+     * (basically, don't do anything conflicting)
+     * This can happen if the caller attempts to extend a page file.
+     */
+    if (!NT_SUCCESS(Status))
+    {
+        ULONG i;
+
+        Status = IoCreateFile(&FileHandle,
+                              SYNCHRONIZE | FILE_WRITE_DATA,
+                              &ObjectAttributes,
+                              &IoStatus,
+                              &AllocationSize,
+                              FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
+                              FILE_SHARE_WRITE | FILE_SHARE_READ,
+                              FILE_OPEN,
+                              FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING,
+                              NULL,
+                              0,
+                              CreateFileTypeNone,
+                              NULL,
+                              SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
+        if (!NT_SUCCESS(Status))
+        {
+            ExFreePoolWithTag(Dacl, 'lcaD');
+            ExFreePoolWithTag(Buffer, TAG_MM);
+            return Status;
+        }
+
+        /* We opened it! Check we are that "someone" ;-)
+         * First, get the opened file object.
+         */
+        Status = ObReferenceObjectByHandle(FileHandle,
+                                           FILE_READ_DATA | FILE_WRITE_DATA,
+                                           IoFileObjectType,
+                                           KernelMode,
+                                           (PVOID*)&FileObject,
+                                           NULL);
+        if (!NT_SUCCESS(Status))
+        {
+            ZwClose(FileHandle);
+            ExFreePoolWithTag(Dacl, 'lcaD');
+            ExFreePoolWithTag(Buffer, TAG_MM);
+            return Status;
+        }
+
+        /* Find if it matches a previous page file */
+        PagingFile = NULL;
+
+        /* FIXME: should be calling unsafe instead,
+         * we should already be in a guarded region
+         */
+        KeAcquireGuardedMutex(&MmPageFileCreationLock);
+        if (MmNumberOfPagingFiles > 0)
+        {
+            i = 0;
+
+            while (MmPagingFile[i]->FileObject->SectionObjectPointer != FileObject->SectionObjectPointer)
             {
-               CurrentRetDescList = RetDescList;
-               RetDescList = RetDescList->Next;
-               ExFreePool(CurrentRetDescList);
+                ++i;
+                if (i >= MmNumberOfPagingFiles)
+                {
+                    break;
+                }
             }
+
+            /* This is the matching page file */
+            PagingFile = MmPagingFile[i];
+        }
+
+        /* If we didn't find the page file, fail */
+        if (PagingFile == NULL)
+        {
+            KeReleaseGuardedMutex(&MmPageFileCreationLock);
             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)
-   {
-      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.QuadPart = SafeMaximumSize.QuadPart;
-   PagingFile->CurrentSize.QuadPart = SafeInitialSize.QuadPart;
-   PagingFile->FreePages = (ULONG)(SafeInitialSize.QuadPart / PAGE_SIZE);
-   PagingFile->UsedPages = 0;
-   KeInitializeSpinLock(&PagingFile->AllocMapLock);
-
-   AllocMapSize = (PagingFile->FreePages / 32) + 1;
-   PagingFile->AllocMap = ExAllocatePool(NonPagedPool,
-                                         AllocMapSize * sizeof(ULONG));
-   PagingFile->AllocMapSize = AllocMapSize;
-
-   if (PagingFile->AllocMap == NULL)
-   {
-      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);
-
-   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);
-
-   ZwClose(FileHandle);
-
-   MmSwapSpaceMessage = FALSE;
-
-   return(STATUS_SUCCESS);
+            ExFreePoolWithTag(Dacl, 'lcaD');
+            ExFreePoolWithTag(Buffer, TAG_MM);
+            return STATUS_NOT_FOUND;
+        }
+
+        /* Don't allow page file shrinking */
+        if (PagingFile->MinimumSize > (SafeMinimumSize.QuadPart >> PAGE_SHIFT))
+        {
+            KeReleaseGuardedMutex(&MmPageFileCreationLock);
+            ObDereferenceObject(FileObject);
+            ZwClose(FileHandle);
+            ExFreePoolWithTag(Dacl, 'lcaD');
+            ExFreePoolWithTag(Buffer, TAG_MM);
+            return STATUS_INVALID_PARAMETER_2;
+        }
+
+        if ((SafeMaximumSize.QuadPart >> PAGE_SHIFT) < PagingFile->MaximumSize)
+        {
+            KeReleaseGuardedMutex(&MmPageFileCreationLock);
+            ObDereferenceObject(FileObject);
+            ZwClose(FileHandle);
+            ExFreePoolWithTag(Dacl, 'lcaD');
+            ExFreePoolWithTag(Buffer, TAG_MM);
+            return STATUS_INVALID_PARAMETER_3;
+        }
+
+        /* FIXME: implement parameters checking and page file extension */
+        UNIMPLEMENTED;
+
+        KeReleaseGuardedMutex(&MmPageFileCreationLock);
+        ObDereferenceObject(FileObject);
+        ZwClose(FileHandle);
+        ExFreePoolWithTag(Dacl, 'lcaD');
+        ExFreePoolWithTag(Buffer, TAG_MM);
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed creating page file: %lx\n", Status);
+        ExFreePoolWithTag(Dacl, 'lcaD');
+        ExFreePoolWithTag(Buffer, TAG_MM);
+        return Status;
+    }
+
+    /* Set the security descriptor */
+    if (NT_SUCCESS(IoStatus.Status))
+    {
+        Status = ZwSetSecurityObject(FileHandle, DACL_SECURITY_INFORMATION, &SecurityDescriptor);
+        if (!NT_SUCCESS(Status))
+        {
+            ExFreePoolWithTag(Dacl, 'lcaD');
+            ZwClose(FileHandle);
+            ExFreePoolWithTag(Buffer, TAG_MM);
+            return Status;
+        }
+    }
+
+    /* DACL is no longer needed, free it */
+    ExFreePoolWithTag(Dacl, 'lcaD');
+
+    /* FIXME: To enable once page file managment is moved to ARM3 */
+#if 0
+    /* Check we won't overflow commit limit with the page file */
+    if (MmTotalCommitLimitMaximum + (SafeMaximumSize.QuadPart >> PAGE_SHIFT) <= MmTotalCommitLimitMaximum)
+    {
+        ZwClose(FileHandle);
+        ExFreePoolWithTag(Buffer, TAG_MM);
+        return STATUS_INVALID_PARAMETER_3;
+    }
+#endif
+
+    /* Set its end of file to minimal size */
+    Status = ZwSetInformationFile(FileHandle,
+                                  &IoStatus,
+                                  &SafeMinimumSize,
+                                  sizeof(LARGE_INTEGER),
+                                  FileEndOfFileInformation);
+    if (!NT_SUCCESS(Status) || !NT_SUCCESS(IoStatus.Status))
+    {
+        ZwClose(FileHandle);
+        ExFreePoolWithTag(Buffer, TAG_MM);
+        return Status;
+    }
+
+    Status = ObReferenceObjectByHandle(FileHandle,
+                                       FILE_READ_DATA | FILE_WRITE_DATA,
+                                       IoFileObjectType,
+                                       KernelMode,
+                                       (PVOID*)&FileObject,
+                                       NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        ZwClose(FileHandle);
+        ExFreePoolWithTag(Buffer, TAG_MM);
+        return Status;
+    }
+
+    /* Deny page file creation on a floppy disk */
+    FsDeviceInfo.Characteristics = 0;
+    IoQueryVolumeInformation(FileObject, FileFsDeviceInformation, sizeof(FsDeviceInfo), &FsDeviceInfo, &Count);
+    if (BooleanFlagOn(FsDeviceInfo.Characteristics, FILE_FLOPPY_DISKETTE))
+    {
+        ObDereferenceObject(FileObject);
+        ZwClose(FileHandle);
+        ExFreePoolWithTag(Buffer, TAG_MM);
+        return STATUS_FLOPPY_VOLUME;
+    }
+
+    PagingFile = ExAllocatePoolWithTag(NonPagedPool, sizeof(*PagingFile), TAG_MM);
+    if (PagingFile == NULL)
+    {
+        ObDereferenceObject(FileObject);
+        ZwClose(FileHandle);
+        ExFreePoolWithTag(Buffer, TAG_MM);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(PagingFile, sizeof(*PagingFile));
+
+    PagingFile->FileHandle = FileHandle;
+    PagingFile->FileObject = FileObject;
+    PagingFile->MaximumSize = (SafeMaximumSize.QuadPart >> PAGE_SHIFT);
+    PagingFile->Size = (SafeMinimumSize.QuadPart >> PAGE_SHIFT);
+    PagingFile->MinimumSize = (SafeMinimumSize.QuadPart >> PAGE_SHIFT);
+    /* First page is never used: it's the header
+     * TODO: write it
+     */
+    PagingFile->FreeSpace = (ULONG)(SafeMinimumSize.QuadPart / PAGE_SIZE) - 1;
+    PagingFile->CurrentUsage = 0;
+    PagingFile->PageFileName = PageFileName;
+    ASSERT(PagingFile->Size == PagingFile->FreeSpace + PagingFile->CurrentUsage + 1);
+
+    AllocMapSize = sizeof(RTL_BITMAP) + (((PagingFile->MaximumSize + 31) / 32) * sizeof(ULONG));
+    PagingFile->Bitmap = ExAllocatePoolWithTag(NonPagedPool,
+                                               AllocMapSize,
+                                               TAG_MM);
+    if (PagingFile->Bitmap == NULL)
+    {
+        ExFreePoolWithTag(PagingFile, TAG_MM);
+        ObDereferenceObject(FileObject);
+        ZwClose(FileHandle);
+        ExFreePoolWithTag(Buffer, TAG_MM);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlInitializeBitMap(PagingFile->Bitmap,
+                        (PULONG)(PagingFile->Bitmap + 1),
+                        (ULONG)(PagingFile->MaximumSize));
+    RtlClearAllBits(PagingFile->Bitmap);
+
+    /* FIXME: should be calling unsafe instead,
+     * we should already be in a guarded region
+     */
+    KeAcquireGuardedMutex(&MmPageFileCreationLock);
+    ASSERT(MmPagingFile[MmNumberOfPagingFiles] == NULL);
+    MmPagingFile[MmNumberOfPagingFiles] = PagingFile;
+    MmNumberOfPagingFiles++;
+    MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreeSpace;
+    KeReleaseGuardedMutex(&MmPageFileCreationLock);
+
+    MmSwapSpaceMessage = FALSE;
+
+    return STATUS_SUCCESS;
 }
 
 /* EOF */