[NTOS/MM]
authorJérôme Gardou <jerome.gardou@reactos.org>
Wed, 6 Aug 2014 21:53:09 +0000 (21:53 +0000)
committerJérôme Gardou <jerome.gardou@reactos.org>
Wed, 6 Aug 2014 21:53:09 +0000 (21:53 +0000)
 - Implement MiResolvePageFileFault
 - Add a debug print showing how many ARM3 pages could be used by the balancer

svn path=/trunk/; revision=63821

reactos/ntoskrnl/include/internal/mm.h
reactos/ntoskrnl/mm/ARM3/pagfault.c
reactos/ntoskrnl/mm/balance.c
reactos/ntoskrnl/mm/pagefile.c

index af0d03d..bbf148d 100644 (file)
@@ -648,6 +648,13 @@ VOID
 NTAPI
 MmShowOutOfSpaceMessagePagingFile(VOID);
 
+NTSTATUS
+NTAPI
+MiReadPageFile(
+    _In_ PFN_NUMBER Page,
+    _In_ ULONG PageFileIndex,
+    _In_ ULONG_PTR PageFileOffset);
+
 /* process.c ****************************************************************/
 
 NTSTATUS
index 0236bbf..df4dbeb 100644 (file)
@@ -808,6 +808,96 @@ MiCompleteProtoPteFault(IN BOOLEAN StoreInstruction,
     return STATUS_SUCCESS;
 }
 
+NTSTATUS
+NTAPI
+MiResolvePageFileFault(_In_ BOOLEAN StoreInstruction,
+                       _In_ PVOID FaultingAddress,
+                       _In_ PMMPTE PointerPte,
+                       _In_ PEPROCESS CurrentProcess,
+                       _Inout_ KIRQL *OldIrql)
+{
+    ULONG Color;
+    PFN_NUMBER Page;
+    NTSTATUS Status;
+    MMPTE TempPte = *PointerPte;
+    KEVENT Event;
+    PMMPFN Pfn1;
+    ULONG PageFileIndex = TempPte.u.Soft.PageFileLow;
+    ULONG_PTR PageFileOffset = TempPte.u.Soft.PageFileHigh;
+
+    /* Things we don't support yet */
+    ASSERT(CurrentProcess > HYDRA_PROCESS);
+    ASSERT(*OldIrql != MM_NOIRQL);
+
+    /* We must hold the PFN lock */
+    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+    /* Some sanity checks */
+    ASSERT(TempPte.u.Hard.Valid == 0);
+    ASSERT(TempPte.u.Soft.PageFileHigh != 0);
+    ASSERT(TempPte.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED);
+
+    /* Get any page, it will be overwritten */
+    Color = MI_GET_NEXT_PROCESS_COLOR(CurrentProcess);
+    Page = MiRemoveAnyPage(Color);
+
+    /* Initialize this PFN */
+    MiInitializePfn(Page, PointerPte, StoreInstruction);
+
+    /* Sets the PFN as being in IO operation */
+    Pfn1 = MI_PFN_ELEMENT(Page);
+    ASSERT(Pfn1->u1.Event == NULL);
+    ASSERT(Pfn1->u3.e1.ReadInProgress == 0);
+    ASSERT(Pfn1->u3.e1.WriteInProgress == 0);
+
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+    Pfn1->u1.Event = &Event;
+    Pfn1->u3.e1.ReadInProgress = 1;
+
+    /* We must write the PTE now as the PFN lock will be released while performing the IO operation */
+    TempPte.u.Soft.Transition = 1;
+    TempPte.u.Soft.PageFileLow = 0;
+    TempPte.u.Soft.Prototype = 0;
+    TempPte.u.Trans.PageFrameNumber = Page;
+
+    MI_WRITE_INVALID_PTE(PointerPte, TempPte);
+
+    /* Release the PFN lock while we proceed */
+    KeReleaseQueuedSpinLock(LockQueuePfnLock, *OldIrql);
+
+    /* Do the paging IO */
+    Status = MiReadPageFile(Page, PageFileIndex, PageFileOffset);
+
+    /* Lock the PFN database again */
+    *OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+    /* Nobody should have changed that while we were not looking */
+    ASSERT(Pfn1->u1.Event == &Event);
+    ASSERT(Pfn1->u3.e1.ReadInProgress == 1);
+    ASSERT(Pfn1->u3.e1.WriteInProgress == 0);
+
+    if (!NT_SUCCESS(Status))
+    {
+        /* Malheur! */
+        ASSERT(FALSE);
+        Pfn1->u4.InPageError = 1;
+        Pfn1->u1.ReadStatus = Status;
+    }
+
+    /* This is now a nice and normal PFN */
+    Pfn1->u1.Event = NULL;
+    Pfn1->u3.e1.ReadInProgress = 0;
+
+    /* And the PTE can finally be valid */
+    MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, TempPte.u.Trans.Protection, Page);
+    MI_WRITE_VALID_PTE(PointerPte, TempPte);
+
+    /* Waiters gonna wait */
+    KeSetEvent(&Event, IO_NO_INCREMENT, FALSE);
+
+    return Status;
+}
+
 NTSTATUS
 NTAPI
 MiResolveTransitionFault(IN PVOID FaultingAddress,
@@ -846,8 +936,19 @@ MiResolveTransitionFault(IN PVOID FaultingAddress,
     /* This is from ARM3 -- Windows normally handles this here */
     ASSERT(Pfn1->u4.InPageError == 0);
 
-    /* Not supported in ARM3 */
-    ASSERT(Pfn1->u3.e1.ReadInProgress == 0);
+    /* See if we should wait before terminating the fault */
+    if (Pfn1->u3.e1.ReadInProgress == 1)
+    {
+       DPRINT1("The page is currently being read!\n");
+       ASSERT(Pfn1->u1.Event != NULL);
+       *InPageBlock = Pfn1->u1.Event;
+       if (PointerPte == Pfn1->PteAddress)
+       {
+           DPRINT1("And this if for this particular PTE.\n");
+           /* The PTE will be made valid by the thread serving the fault */
+           return STATUS_SUCCESS; // FIXME: Maybe something more descriptive
+       }
+    }
 
     /* Windows checks there's some free pages and this isn't an in-page error */
     ASSERT(MmAvailablePages > 0);
@@ -1325,6 +1426,30 @@ MiDispatchFault(IN BOOLEAN StoreInstruction,
         /* And now release the lock and leave*/
         KeReleaseQueuedSpinLock(LockQueuePfnLock, LockIrql);
 
+        if (InPageBlock != NULL)
+        {
+               /* The page is being paged in by another process */
+               KeWaitForSingleObject(InPageBlock, WrPageIn, KernelMode, FALSE, NULL);
+        }
+
+        ASSERT(OldIrql == KeGetCurrentIrql());
+        ASSERT(OldIrql <= APC_LEVEL);
+        ASSERT(KeAreAllApcsDisabled() == TRUE);
+        return Status;
+    }
+
+    /* Should we page the data back in ? */
+    if (TempPte.u.Soft.PageFileHigh != 0)
+    {
+        /* Lock the PFN database */
+        LockIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+        /* Resolve */
+        Status = MiResolvePageFileFault(StoreInstruction, Address, PointerPte, Process, &LockIrql);
+
+        /* And now release the lock and leave*/
+        KeReleaseQueuedSpinLock(LockQueuePfnLock, LockIrql);
+
         ASSERT(OldIrql == KeGetCurrentIrql());
         ASSERT(OldIrql <= APC_LEVEL);
         ASSERT(KeAreAllApcsDisabled() == TRUE);
@@ -1333,19 +1458,14 @@ MiDispatchFault(IN BOOLEAN StoreInstruction,
 
     //
     // The PTE must be invalid but not completely empty. It must also not be a
-    // prototype or transition PTE as those scenarii should've been handled above.
+    // prototype a transition or a paged-out PTE as those scenarii should've been handled above.
     // These are all Windows checks
     //
     ASSERT(TempPte.u.Hard.Valid == 0);
     ASSERT(TempPte.u.Soft.Prototype == 0);
     ASSERT(TempPte.u.Soft.Transition == 0);
-    ASSERT(TempPte.u.Long != 0);
-
-    //
-    // No page file software PTEs in ARM3 yet, so this must be a
-    // demand zero page. This is a ReactOS check.
-    //
     ASSERT(TempPte.u.Soft.PageFileHigh == 0);
+    ASSERT(TempPte.u.Long != 0);
 
     //
     // If we got this far, the PTE can only be a demand zero PTE, which is what
index 804c674..d06e0ee 100644 (file)
@@ -355,6 +355,9 @@ MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait,
    return(STATUS_SUCCESS);
 }
 
+
+extern MMPFNLIST MmModifiedPageListByColor[];
+
 VOID NTAPI
 MiBalancerThread(PVOID Unused)
 {
@@ -424,6 +427,9 @@ MiBalancerThread(PVOID Unused)
                   KeBugCheck(NO_PAGES_AVAILABLE);
               }
           } while (InitialTarget != 0);
+
+          if (MmModifiedPageListByColor[0].Total != 0)
+              DPRINT1("There are %u pages ready to be paged out in the modified list.\n", MmModifiedPageListByColor[0].Total);
       }
       else
       {
index f534a66..a1ffb08 100644 (file)
@@ -48,8 +48,8 @@ typedef struct _PAGINGFILE
    PFILE_OBJECT FileObject;
    LARGE_INTEGER MaximumSize;
    LARGE_INTEGER CurrentSize;
-   ULONG FreePages;
-   ULONG UsedPages;
+   PFN_NUMBER FreePages;
+   PFN_NUMBER UsedPages;
    PULONG AllocMap;
    KSPIN_LOCK AllocMapLock;
    ULONG AllocMapSize;
@@ -68,7 +68,7 @@ RETRIEVEL_DESCRIPTOR_LIST, *PRETRIEVEL_DESCRIPTOR_LIST;
 
 #define PAIRS_PER_RUN (1024)
 
-#define MAX_PAGING_FILES  (32)
+#define MAX_PAGING_FILES  (16)
 
 /* List of paging files, both used and free */
 static PPAGINGFILE PagingFileList[MAX_PAGING_FILES];
@@ -77,7 +77,6 @@ static PPAGINGFILE PagingFileList[MAX_PAGING_FILES];
 static KSPIN_LOCK PagingFileListLock;
 
 /* Number of paging files */
-static ULONG MiPagingFileCount;
 ULONG MmNumberOfPagingFiles;
 
 /* Number of pages that are available for swapping */
@@ -140,7 +139,7 @@ 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;
@@ -275,34 +274,44 @@ MmWriteToSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)
    return(Status);
 }
 
+
 NTSTATUS
 NTAPI
 MmReadFromSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)
 {
-   ULONG i;
-   ULONG_PTR offset;
+       return MiReadPageFile(Page, FILE_FROM_ENTRY(SwapEntry), OFFSET_FROM_ENTRY(SwapEntry));
+}
+
+NTSTATUS
+NTAPI
+MiReadPageFile(
+       _In_ PFN_NUMBER Page,
+       _In_ ULONG PageFileIndex,
+       _In_ ULONG_PTR PageFileOffset)
+{
    LARGE_INTEGER file_offset;
    IO_STATUS_BLOCK Iosb;
    NTSTATUS Status;
    KEVENT Event;
    UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)];
    PMDL Mdl = (PMDL)MdlBase;
+   PPAGINGFILE PagingFile;
 
-   DPRINT("MmReadFromSwapPage\n");
+   DPRINT("MiReadSwapFile\n");
 
-   if (SwapEntry == 0)
+   if (PageFileOffset == 0)
    {
       KeBugCheck(MEMORY_MANAGEMENT);
       return(STATUS_UNSUCCESSFUL);
    }
 
-   i = FILE_FROM_ENTRY(SwapEntry);
-   offset = OFFSET_FROM_ENTRY(SwapEntry);
+   ASSERT(PageFileIndex < MAX_PAGING_FILES);
 
-   if (PagingFileList[i]->FileObject == NULL ||
-         PagingFileList[i]->FileObject->DeviceObject == NULL)
+   PagingFile = PagingFileList[PageFileIndex];
+
+   if (PagingFile->FileObject == NULL || PagingFile->FileObject->DeviceObject == NULL)
    {
-      DPRINT1("Bad paging file 0x%.8X\n", SwapEntry);
+      DPRINT1("Bad paging file %u\n", PageFileIndex);
       KeBugCheck(MEMORY_MANAGEMENT);
    }
 
@@ -310,11 +319,11 @@ MmReadFromSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)
    MmBuildMdlFromPages(Mdl, &Page);
    Mdl->MdlFlags |= MDL_PAGES_LOCKED;
 
-   file_offset.QuadPart = offset * PAGE_SIZE;
-   file_offset = MmGetOffsetPageFile(PagingFileList[i]->RetrievalPointers, file_offset);
+   file_offset.QuadPart = PageFileOffset * PAGE_SIZE;
+   file_offset = MmGetOffsetPageFile(PagingFile->RetrievalPointers, file_offset);
 
    KeInitializeEvent(&Event, NotificationEvent, FALSE);
-   Status = IoPageRead(PagingFileList[i]->FileObject,
+   Status = IoPageRead(PagingFile->FileObject,
                        Mdl,
                        &file_offset,
                        &Event,
@@ -348,7 +357,7 @@ MmInitPagingFile(VOID)
    {
       PagingFileList[i] = NULL;
    }
-   MiPagingFileCount = 0;
+   MmNumberOfPagingFiles = 0;
 }
 
 static ULONG
@@ -498,7 +507,7 @@ NtCreatePagingFile(IN PUNICODE_STRING FileName,
    DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
           FileName, InitialSize->QuadPart);
 
-   if (MiPagingFileCount >= MAX_PAGING_FILES)
+   if (MmNumberOfPagingFiles >= MAX_PAGING_FILES)
    {
       return(STATUS_TOO_MANY_PAGING_FILES);
    }
@@ -800,7 +809,7 @@ NtCreatePagingFile(IN PUNICODE_STRING FileName,
       }
    }
    MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreePages;
-   MiPagingFileCount++;
+   MmNumberOfPagingFiles++;
    KeReleaseSpinLock(&PagingFileListLock, oldIrql);
 
    ZwClose(FileHandle);