[NTOSKRNL/MM]

- Stop leaking references to PDEs.
Still one reference left to the TLB mapping at process deletion.

svn path=/trunk/; revision=55763
This commit is contained in:
Jérôme Gardou 2012-02-20 20:51:18 +00:00
parent 30703d5a5d
commit d720941f1e
5 changed files with 181 additions and 22 deletions

View file

@ -113,6 +113,12 @@ MmPageOutVirtualMemory(PMMSUPPORT AddressSpace,
MmCreatePageFileMapping(Process, Address, SwapEntry);
MmSetSavedSwapEntryPage(Page, 0);
}
#if (_MI_PAGING_LEVELS == 2)
else if(Address < MmSystemRangeStart)
{
AddressSpace->VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
}
#endif
MmUnlockAddressSpace(AddressSpace);
MmReleasePageMemoryConsumer(MC_USER, Page);
PageOp->Status = STATUS_SUCCESS;
@ -191,6 +197,9 @@ MmNotPresentFaultVirtualMemory(PMMSUPPORT AddressSpace,
PMM_REGION Region;
PMM_PAGEOP PageOp;
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
#if (_MI_PAGING_LEVELS == 2)
BOOLEAN refPde = TRUE;
#endif
/*
* There is a window between taking the page fault and locking the
@ -326,7 +335,17 @@ MmNotPresentFaultVirtualMemory(PMMSUPPORT AddressSpace,
KeBugCheck(MEMORY_MANAGEMENT);
}
MmSetSavedSwapEntryPage(Page, SwapEntry);
#if (_MI_PAGING_LEVELS == 2)
/* PTE was already "created", no need to reference PDE */
refPde = FALSE;
#endif
}
#if (_MI_PAGING_LEVELS == 2)
/* Add an additional page table reference */
if(refPde) MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
ASSERT(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] <= PTE_COUNT);
#endif
/*
* Set the page. If we fail because we are out of memory then
@ -337,16 +356,6 @@ MmNotPresentFaultVirtualMemory(PMMSUPPORT AddressSpace,
Region->Protect,
&Page,
1);
while (Status == STATUS_NO_MEMORY)
{
MmUnlockAddressSpace(AddressSpace);
Status = MmCreateVirtualMapping(Process,
(PVOID)PAGE_ROUND_DOWN(Address),
Region->Protect,
&Page,
1);
MmLockAddressSpace(AddressSpace);
}
if (!NT_SUCCESS(Status))
{
DPRINT1("MmCreateVirtualMapping failed, not out of memory\n");
@ -393,9 +402,9 @@ MmModifyAttributes(PMMSUPPORT AddressSpace,
for (i=0; i < PAGE_ROUND_UP(RegionSize)/PAGE_SIZE; i++)
{
PFN_NUMBER Page;
PVOID Address = (char*)BaseAddress + (i*PAGE_SIZE);
if (MmIsPageSwapEntry(Process,
(char*)BaseAddress + (i * PAGE_SIZE)))
if (MmIsPageSwapEntry(Process, Address))
{
SWAPENTRY SwapEntry;
@ -403,11 +412,17 @@ MmModifyAttributes(PMMSUPPORT AddressSpace,
(char*)BaseAddress + (i * PAGE_SIZE),
&SwapEntry);
MmFreeSwapPage(SwapEntry);
#if (_MI_PAGING_LEVELS == 2)
if(Address < MmSystemRangeStart)
{
AddressSpace->VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
}
#endif
}
else
{
MmDeleteVirtualMapping(Process,
(char*)BaseAddress + (i*PAGE_SIZE),
Address,
FALSE, NULL, &Page);
if (Page != 0)
{
@ -417,10 +432,16 @@ MmModifyAttributes(PMMSUPPORT AddressSpace,
{
MmFreeSwapPage(SavedSwapEntry);
MmSetSavedSwapEntryPage(Page, 0);
}
}
MmDeleteRmap(Page, Process,
(char*)BaseAddress + (i * PAGE_SIZE));
MmReleasePageMemoryConsumer(MC_USER, Page);
#if (_MI_PAGING_LEVELS == 2)
if(Address < MmSystemRangeStart)
{
AddressSpace->VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
}
#endif
}
}
}

View file

@ -14,6 +14,8 @@
#define NDEBUG
#include <debug.h>
#include "ARM3/miarm.h"
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(INIT, MmInitializeBalancer)
#pragma alloc_text(INIT, MmInitializeMemoryConsumer)
@ -232,10 +234,40 @@ MiIsBalancerThread(VOID)
(PsGetCurrentThreadId() == MiBalancerThreadId.UniqueThread);
}
VOID
NTAPI
MiDeletePte(IN PMMPTE PointerPte,
IN PVOID VirtualAddress,
IN PEPROCESS CurrentProcess,
IN PMMPTE PrototypePte);
VOID
NTAPI
MmRebalanceMemoryConsumers(VOID)
{
#if (_MI_PAGING_LEVELS == 2)
if(!MiIsBalancerThread())
{
/* Clean up the unused PDEs */
ULONG_PTR Address;
KIRQL OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
PMMPDE pointerPde;
for(Address = (ULONG_PTR)MI_LOWEST_VAD_ADDRESS;
Address < (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS;
Address += (PAGE_SIZE * PTE_COUNT))
{
if(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] == 0)
{
pointerPde = MiAddressToPde(Address);
if(pointerPde->u.Hard.Valid)
MiDeletePte(pointerPde, MiPdeToPte(pointerPde), PsGetCurrentProcess(), NULL);
ASSERT(pointerPde->u.Hard.Valid == 0);
}
}
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
}
#endif
if (MiBalancerThreadHandle != NULL &&
!MiIsBalancerThread())
{

View file

@ -258,9 +258,22 @@ MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create)
{
/* Nobody but page fault should ask for creating the PDE,
* Which imples that Process is the current one */
ASSERT(Create == FALSE);
MmDeleteHyperspaceMapping(PdeBase);
return NULL;
if(Create == FALSE)
return NULL;
else
{
KAPC_STATE ApcState;
PULONG ret;
/* Attach to process */
KeStackAttachProcess(&Process->Pcb, &ApcState);
/* Retry */
ret = MmGetPageTableForProcess(Process, Address, TRUE);
/* Get Back to original process */
KeUnstackDetachProcess(&ApcState);
}
}
else
{
@ -293,6 +306,7 @@ MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create)
}
/* This is for kernel land address */
ASSERT(Process == NULL);
PointerPde = MiAddressToPde(Address);
Pt = (PULONG)MiAddressToPte(Address);
if (PointerPde->u.Hard.Valid == 0)

View file

@ -45,6 +45,8 @@
#define NDEBUG
#include <debug.h>
#include "ARM3/miarm.h"
MEMORY_AREA MiStaticMemoryAreas[MI_STATIC_MEMORY_AREAS];
ULONG MiStaticMemoryAreaCount;
@ -688,6 +690,12 @@ IN PMM_AVL_TABLE Table);
*
* @remarks Lock the address space before calling this function.
*/
VOID
NTAPI
MiDeletePte(IN PMMPTE PointerPte,
IN PVOID VirtualAddress,
IN PEPROCESS CurrentProcess,
IN PMMPTE PrototypePte);
NTSTATUS NTAPI
MmFreeMemoryArea(
@ -716,10 +724,10 @@ MmFreeMemoryArea(
Address < (ULONG_PTR)EndAddress;
Address += PAGE_SIZE)
{
BOOLEAN Dirty = FALSE;
SWAPENTRY SwapEntry = 0;
PFN_NUMBER Page = 0;
BOOLEAN Dirty = FALSE;
SWAPENTRY SwapEntry = 0;
PFN_NUMBER Page = 0;
if (MmIsPageSwapEntry(Process, (PVOID)Address))
{
MmDeletePageFileMapping(Process, (PVOID)Address, &SwapEntry);
@ -733,6 +741,25 @@ MmFreeMemoryArea(
FreePage(FreePageContext, MemoryArea, (PVOID)Address,
Page, SwapEntry, (BOOLEAN)Dirty);
}
#if (_MI_PAGING_LEVELS == 2)
/* Remove page table reference */
if((SwapEntry || Page) && ((PVOID)Address < MmSystemRangeStart))
{
ASSERT(AddressSpace != MmGetKernelAddressSpace());
MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
ASSERT(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] < PTE_COUNT);
if(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] == 0)
{
/* No PTE relies on this PDE. Release it */
KIRQL OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
PMMPDE PointerPde = MiAddressToPde(Address);
ASSERT(PointerPde->u.Hard.Valid == 1);
MiDeletePte(PointerPde, MiPdeToPte(PointerPde), Process, NULL);
ASSERT(PointerPde->u.Hard.Valid == 0);
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
}
}
#endif
}
if (Process != NULL &&

View file

@ -57,6 +57,8 @@
#pragma alloc_text(INIT, MmInitSectionImplementation)
#endif
#include "ARM3/miarm.h"
NTSTATUS
NTAPI
MiMapViewInSystemSpace(IN PVOID Section,
@ -1448,6 +1450,15 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
Page = PFN_FROM_SSE(Entry);
MmSharePageEntrySectionSegment(Segment, Offset);
#if (_MI_PAGING_LEVELS == 2)
/* Reference Page Directory Entry */
if(Address < MmSystemRangeStart)
{
MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
ASSERT(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] <= PTE_COUNT);
}
#endif
/* FIXME: Should we call MmCreateVirtualMappingUnsafe if
* (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
@ -1538,6 +1549,15 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
return(STATUS_SUCCESS);
}
#if (_MI_PAGING_LEVELS == 2)
/* Reference Page Directory Entry */
if(Address < MmSystemRangeStart)
{
MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
ASSERT(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] <= PTE_COUNT);
}
#endif
/*
* Satisfying a page fault on a map of /Device/PhysicalMemory is easy
*/
@ -1658,6 +1678,12 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
/*
* Cleanup and release locks
*/
#if (_MI_PAGING_LEVELS == 2)
if(Address < MmSystemRangeStart)
{
MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
}
#endif
MmLockAddressSpace(AddressSpace);
PageOp->Status = Status;
MmspCompleteAndReleasePageOp(PageOp);
@ -1876,7 +1902,10 @@ MmAccessFaultSectionView(PMMSUPPORT AddressSpace,
MmSetPageProtect(Process, Address, Region->Protect);
return(STATUS_SUCCESS);
}
if(OldPage == 0)
DPRINT("OldPage == 0!\n");
/*
* Get or create a pageop
*/
@ -1986,7 +2015,7 @@ MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
BOOLEAN WasDirty;
PFN_NUMBER Page;
PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
if (Process)
{
@ -2022,6 +2051,14 @@ MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
MmReleasePageMemoryConsumer(MC_USER, Page);
}
#if (_MI_PAGING_LEVELS == 2)
if(Address < MmSystemRangeStart)
{
if(Process->VmDeleted) DPRINT1("deleted!!!");
Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
}
#endif
DPRINT("PhysicalAddress %x, Address %x\n", Page << PAGE_SHIFT, Address);
}
@ -2254,6 +2291,13 @@ MmPageOutSectionView(PMMSUPPORT AddressSpace,
{
MmSetSavedSwapEntryPage(Page, 0);
MmLockAddressSpace(AddressSpace);
#if (_MI_PAGING_LEVELS == 2)
/* Page table was dereferenced while deleting the RMAP */
if(Address < MmSystemRangeStart)
{
AddressSpace->VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
}
#endif
Status = MmCreatePageFileMapping(Process,
Address,
SwapEntry);
@ -2281,6 +2325,13 @@ MmPageOutSectionView(PMMSUPPORT AddressSpace,
/*
* For private pages restore the old mappings.
*/
#if (_MI_PAGING_LEVELS == 2)
/* Page table was dereferenced while deleting the RMAP */
if(Address < MmSystemRangeStart)
{
AddressSpace->VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
}
#endif
if (Context.Private)
{
Status = MmCreateVirtualMapping(Process,
@ -2331,6 +2382,13 @@ MmPageOutSectionView(PMMSUPPORT AddressSpace,
* As above: undo our actions.
* FIXME: Also free the swap page.
*/
#if (_MI_PAGING_LEVELS == 2)
/* Page table was dereferenced while deleting the RMAP */
if(Address < MmSystemRangeStart)
{
AddressSpace->VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
}
#endif
MmLockAddressSpace(AddressSpace);
if (Context.Private)
{
@ -2382,6 +2440,13 @@ MmPageOutSectionView(PMMSUPPORT AddressSpace,
if (Context.Private)
{
MmLockAddressSpace(AddressSpace);
#if (_MI_PAGING_LEVELS == 2)
/* Page table was dereferenced while deleting the RMAP */
if(Address < MmSystemRangeStart)
{
AddressSpace->VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
}
#endif
Status = MmCreatePageFileMapping(Process,
Address,
SwapEntry);