From 494445d381a0d7f066e669bd8c786c178cffc2d2 Mon Sep 17 00:00:00 2001 From: Art Yerkes Date: Thu, 3 May 2012 21:05:06 +0000 Subject: [PATCH] [NTOSKRNL] Account for wait entries delaying a view attribute change and interacting with the machinery in CoW copying code, specifically making CoW insert and revoke a wait while copying the page, and make the CoW copy function take both pages as arguments rather than relying on the address space. Also alter the MM_WAIT_ENTRY value a bit to take into account an assert that it must have bit 0x800 set. svn path=/trunk/; revision=56488 --- reactos/ntoskrnl/cache/section/newmm.h | 2 +- reactos/ntoskrnl/include/internal/mm.h | 4 +-- reactos/ntoskrnl/mm/i386/page.c | 1 + reactos/ntoskrnl/mm/section.c | 47 ++++++++++++++++++-------- 4 files changed, 36 insertions(+), 18 deletions(-) diff --git a/reactos/ntoskrnl/cache/section/newmm.h b/reactos/ntoskrnl/cache/section/newmm.h index cdca5a36e94..77447d94a1f 100644 --- a/reactos/ntoskrnl/cache/section/newmm.h +++ b/reactos/ntoskrnl/cache/section/newmm.h @@ -4,7 +4,7 @@ /* TYPES *********************************************************************/ -#define MM_WAIT_ENTRY 0x7ffff800 +#define MM_WAIT_ENTRY 0x7ffffc00 #define PFN_FROM_SSE(E) ((PFN_NUMBER)((E) >> PAGE_SHIFT)) #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001) #define MM_IS_WAIT_PTE(E) \ diff --git a/reactos/ntoskrnl/include/internal/mm.h b/reactos/ntoskrnl/include/internal/mm.h index 9df909082a6..5e09fe474ab 100644 --- a/reactos/ntoskrnl/include/internal/mm.h +++ b/reactos/ntoskrnl/include/internal/mm.h @@ -955,8 +955,8 @@ ExAllocatePageWithPhysPage(PFN_NUMBER Page); NTSTATUS NTAPI MiCopyFromUserPage( - PFN_NUMBER Page, - PVOID SourceAddress + PFN_NUMBER NewPage, + PFN_NUMBER OldPage ); NTSTATUS diff --git a/reactos/ntoskrnl/mm/i386/page.c b/reactos/ntoskrnl/mm/i386/page.c index 2a533796c48..5136870cdbb 100644 --- a/reactos/ntoskrnl/mm/i386/page.c +++ b/reactos/ntoskrnl/mm/i386/page.c @@ -558,6 +558,7 @@ MmDeletePageFileMapping(PEPROCESS Process, PVOID Address, if ((Pte & PA_PRESENT) || !(Pte & 0x800)) { + DPRINT1("Pte %x (want not 1 and 0x800)\n", Pte); KeBugCheck(MEMORY_MANAGEMENT); } diff --git a/reactos/ntoskrnl/mm/section.c b/reactos/ntoskrnl/mm/section.c index babf5193542..03990c6c9a9 100644 --- a/reactos/ntoskrnl/mm/section.c +++ b/reactos/ntoskrnl/mm/section.c @@ -959,22 +959,24 @@ BOOLEAN MiIsPageFromCache(PMEMORY_AREA MemoryArea, NTSTATUS NTAPI -MiCopyFromUserPage(PFN_NUMBER DestPage, PVOID SourceAddress) +MiCopyFromUserPage(PFN_NUMBER DestPage, PFN_NUMBER SrcPage) { PEPROCESS Process; - KIRQL Irql; - PVOID TempAddress; + KIRQL Irql, Irql2; + PVOID DestAddress, SrcAddress; - ASSERT((ULONG_PTR)SourceAddress % PAGE_SIZE == 0); Process = PsGetCurrentProcess(); - TempAddress = MiMapPageInHyperSpace(Process, DestPage, &Irql); - if (TempAddress == NULL) + DestAddress = MiMapPageInHyperSpace(Process, DestPage, &Irql); + SrcAddress = MiMapPageInHyperSpace(Process, SrcPage, &Irql2); + if (DestAddress == NULL || SrcAddress == NULL) { return(STATUS_NO_MEMORY); } - ASSERT((ULONG_PTR)TempAddress % PAGE_SIZE == 0); - RtlCopyMemory(TempAddress, SourceAddress, PAGE_SIZE); - MiUnmapPageInHyperSpace(Process, TempAddress, Irql); + ASSERT((ULONG_PTR)DestAddress % PAGE_SIZE == 0); + ASSERT((ULONG_PTR)SrcAddress % PAGE_SIZE == 0); + RtlCopyMemory(DestAddress, SrcAddress, PAGE_SIZE); + MiUnmapPageInHyperSpace(Process, SrcAddress, Irql2); + MiUnmapPageInHyperSpace(Process, DestAddress, Irql); return(STATUS_SUCCESS); } @@ -1620,6 +1622,7 @@ MmAccessFaultSectionView(PMMSUPPORT AddressSpace, PMM_REGION Region; ULONG_PTR Entry; PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); + SWAPENTRY SwapEntry; DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace, MemoryArea, Address); @@ -1699,6 +1702,10 @@ MmAccessFaultSectionView(PMMSUPPORT AddressSpace, return(STATUS_MM_RESTART_OPERATION); } + MmDeleteRmap(OldPage, Process, PAddress); + MmDeleteVirtualMapping(Process, PAddress, FALSE, NULL, NULL); + MmCreatePageFileMapping(Process, PAddress, MM_WAIT_ENTRY); + /* * Release locks now we have the pageop */ @@ -1720,17 +1727,14 @@ MmAccessFaultSectionView(PMMSUPPORT AddressSpace, /* * Copy the old page */ - MiCopyFromUserPage(NewPage, PAddress); + MiCopyFromUserPage(NewPage, OldPage); MmLockAddressSpace(AddressSpace); - /* - * Delete the old entry. - */ - MmDeleteVirtualMapping(Process, Address, FALSE, NULL, NULL); /* * Set the PTE to point to the new page */ + MmDeletePageFileMapping(Process, PAddress, &SwapEntry); Status = MmCreateVirtualMapping(Process, PAddress, Region->Protect, @@ -1751,7 +1755,7 @@ MmAccessFaultSectionView(PMMSUPPORT AddressSpace, /* * Unshare the old page. */ - MmDeleteRmap(OldPage, Process, PAddress); + DPRINT("Swapping page (Old %x New %x)\n", OldPage, NewPage); MmInsertRmap(NewPage, Process, PAddress); MmLockSectionSegment(Segment); MmUnsharePageEntrySectionSegment(Section, Segment, &Offset, FALSE, FALSE, NULL); @@ -2388,9 +2392,18 @@ MmAlterViewAttributes(PMMSUPPORT AddressSpace, { for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++) { + SWAPENTRY SwapEntry; PVOID Address = (char*)BaseAddress + (i * PAGE_SIZE); ULONG Protect = NewProtect; + /* Wait for a wait entry to disappear */ + do { + MmGetPageFileMapping(Process, Address, &SwapEntry); + if (SwapEntry != MM_WAIT_ENTRY) + break; + MiWaitForPageEvent(Process, Address); + } while (TRUE); + /* * If we doing COW for this segment then check if the page is * already private. @@ -2404,6 +2417,10 @@ MmAlterViewAttributes(PMMSUPPORT AddressSpace, Offset.QuadPart = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress + MemoryArea->Data.SectionData.ViewOffset.QuadPart; Entry = MmGetPageEntrySectionSegment(Segment, &Offset); + /* + * An MM_WAIT_ENTRY is ok in this case... It'll just count as + * IS_SWAP_FROM_SSE and we'll do the right thing. + */ Page = MmGetPfnForProcess(Process, Address); Protect = PAGE_READONLY;