From 9aec0d47eba3413226e4c4cf37a6381183c8268f Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Gardou?= Date: Wed, 6 Aug 2014 21:53:09 +0000 Subject: [PATCH] [NTOS/MM] - 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 | 7 ++ reactos/ntoskrnl/mm/ARM3/pagfault.c | 138 +++++++++++++++++++++++-- reactos/ntoskrnl/mm/balance.c | 6 ++ reactos/ntoskrnl/mm/pagefile.c | 49 +++++---- 4 files changed, 171 insertions(+), 29 deletions(-) diff --git a/reactos/ntoskrnl/include/internal/mm.h b/reactos/ntoskrnl/include/internal/mm.h index af0d03d464d..bbf148ddc7a 100644 --- a/reactos/ntoskrnl/include/internal/mm.h +++ b/reactos/ntoskrnl/include/internal/mm.h @@ -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 diff --git a/reactos/ntoskrnl/mm/ARM3/pagfault.c b/reactos/ntoskrnl/mm/ARM3/pagfault.c index 0236bbf1655..df4dbebe248 100644 --- a/reactos/ntoskrnl/mm/ARM3/pagfault.c +++ b/reactos/ntoskrnl/mm/ARM3/pagfault.c @@ -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 diff --git a/reactos/ntoskrnl/mm/balance.c b/reactos/ntoskrnl/mm/balance.c index 804c674763e..d06e0ee4434 100644 --- a/reactos/ntoskrnl/mm/balance.c +++ b/reactos/ntoskrnl/mm/balance.c @@ -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 { diff --git a/reactos/ntoskrnl/mm/pagefile.c b/reactos/ntoskrnl/mm/pagefile.c index f534a66e1df..a1ffb08cc22 100644 --- a/reactos/ntoskrnl/mm/pagefile.c +++ b/reactos/ntoskrnl/mm/pagefile.c @@ -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); -- 2.17.1