[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
This commit is contained in:
Art Yerkes
2012-05-03 21:05:06 +00:00
parent 3768cccb0e
commit 494445d381
4 changed files with 36 additions and 18 deletions
+1 -1
View File
@@ -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) \
+2 -2
View File
@@ -955,8 +955,8 @@ ExAllocatePageWithPhysPage(PFN_NUMBER Page);
NTSTATUS
NTAPI
MiCopyFromUserPage(
PFN_NUMBER Page,
PVOID SourceAddress
PFN_NUMBER NewPage,
PFN_NUMBER OldPage
);
NTSTATUS
+1
View File
@@ -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);
}
+32 -15
View File
@@ -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;