[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); MmCreatePageFileMapping(Process, Address, SwapEntry);
MmSetSavedSwapEntryPage(Page, 0); MmSetSavedSwapEntryPage(Page, 0);
} }
#if (_MI_PAGING_LEVELS == 2)
else if(Address < MmSystemRangeStart)
{
AddressSpace->VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
}
#endif
MmUnlockAddressSpace(AddressSpace); MmUnlockAddressSpace(AddressSpace);
MmReleasePageMemoryConsumer(MC_USER, Page); MmReleasePageMemoryConsumer(MC_USER, Page);
PageOp->Status = STATUS_SUCCESS; PageOp->Status = STATUS_SUCCESS;
@ -191,6 +197,9 @@ MmNotPresentFaultVirtualMemory(PMMSUPPORT AddressSpace,
PMM_REGION Region; PMM_REGION Region;
PMM_PAGEOP PageOp; PMM_PAGEOP PageOp;
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); 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 * There is a window between taking the page fault and locking the
@ -326,7 +335,17 @@ MmNotPresentFaultVirtualMemory(PMMSUPPORT AddressSpace,
KeBugCheck(MEMORY_MANAGEMENT); KeBugCheck(MEMORY_MANAGEMENT);
} }
MmSetSavedSwapEntryPage(Page, SwapEntry); 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 * Set the page. If we fail because we are out of memory then
@ -337,16 +356,6 @@ MmNotPresentFaultVirtualMemory(PMMSUPPORT AddressSpace,
Region->Protect, Region->Protect,
&Page, &Page,
1); 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)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("MmCreateVirtualMapping failed, not out of memory\n"); 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++) for (i=0; i < PAGE_ROUND_UP(RegionSize)/PAGE_SIZE; i++)
{ {
PFN_NUMBER Page; PFN_NUMBER Page;
PVOID Address = (char*)BaseAddress + (i*PAGE_SIZE);
if (MmIsPageSwapEntry(Process, if (MmIsPageSwapEntry(Process, Address))
(char*)BaseAddress + (i * PAGE_SIZE)))
{ {
SWAPENTRY SwapEntry; SWAPENTRY SwapEntry;
@ -403,11 +412,17 @@ MmModifyAttributes(PMMSUPPORT AddressSpace,
(char*)BaseAddress + (i * PAGE_SIZE), (char*)BaseAddress + (i * PAGE_SIZE),
&SwapEntry); &SwapEntry);
MmFreeSwapPage(SwapEntry); MmFreeSwapPage(SwapEntry);
#if (_MI_PAGING_LEVELS == 2)
if(Address < MmSystemRangeStart)
{
AddressSpace->VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
}
#endif
} }
else else
{ {
MmDeleteVirtualMapping(Process, MmDeleteVirtualMapping(Process,
(char*)BaseAddress + (i*PAGE_SIZE), Address,
FALSE, NULL, &Page); FALSE, NULL, &Page);
if (Page != 0) if (Page != 0)
{ {
@ -417,10 +432,16 @@ MmModifyAttributes(PMMSUPPORT AddressSpace,
{ {
MmFreeSwapPage(SavedSwapEntry); MmFreeSwapPage(SavedSwapEntry);
MmSetSavedSwapEntryPage(Page, 0); MmSetSavedSwapEntryPage(Page, 0);
} }
MmDeleteRmap(Page, Process, MmDeleteRmap(Page, Process,
(char*)BaseAddress + (i * PAGE_SIZE)); (char*)BaseAddress + (i * PAGE_SIZE));
MmReleasePageMemoryConsumer(MC_USER, Page); 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 #define NDEBUG
#include <debug.h> #include <debug.h>
#include "ARM3/miarm.h"
#if defined (ALLOC_PRAGMA) #if defined (ALLOC_PRAGMA)
#pragma alloc_text(INIT, MmInitializeBalancer) #pragma alloc_text(INIT, MmInitializeBalancer)
#pragma alloc_text(INIT, MmInitializeMemoryConsumer) #pragma alloc_text(INIT, MmInitializeMemoryConsumer)
@ -232,10 +234,40 @@ MiIsBalancerThread(VOID)
(PsGetCurrentThreadId() == MiBalancerThreadId.UniqueThread); (PsGetCurrentThreadId() == MiBalancerThreadId.UniqueThread);
} }
VOID
NTAPI
MiDeletePte(IN PMMPTE PointerPte,
IN PVOID VirtualAddress,
IN PEPROCESS CurrentProcess,
IN PMMPTE PrototypePte);
VOID VOID
NTAPI NTAPI
MmRebalanceMemoryConsumers(VOID) 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 && if (MiBalancerThreadHandle != NULL &&
!MiIsBalancerThread()) !MiIsBalancerThread())
{ {

View file

@ -258,9 +258,22 @@ MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create)
{ {
/* Nobody but page fault should ask for creating the PDE, /* Nobody but page fault should ask for creating the PDE,
* Which imples that Process is the current one */ * Which imples that Process is the current one */
ASSERT(Create == FALSE);
MmDeleteHyperspaceMapping(PdeBase); 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 else
{ {
@ -293,6 +306,7 @@ MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create)
} }
/* This is for kernel land address */ /* This is for kernel land address */
ASSERT(Process == NULL);
PointerPde = MiAddressToPde(Address); PointerPde = MiAddressToPde(Address);
Pt = (PULONG)MiAddressToPte(Address); Pt = (PULONG)MiAddressToPte(Address);
if (PointerPde->u.Hard.Valid == 0) if (PointerPde->u.Hard.Valid == 0)

View file

@ -45,6 +45,8 @@
#define NDEBUG #define NDEBUG
#include <debug.h> #include <debug.h>
#include "ARM3/miarm.h"
MEMORY_AREA MiStaticMemoryAreas[MI_STATIC_MEMORY_AREAS]; MEMORY_AREA MiStaticMemoryAreas[MI_STATIC_MEMORY_AREAS];
ULONG MiStaticMemoryAreaCount; ULONG MiStaticMemoryAreaCount;
@ -688,6 +690,12 @@ IN PMM_AVL_TABLE Table);
* *
* @remarks Lock the address space before calling this function. * @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 NTSTATUS NTAPI
MmFreeMemoryArea( MmFreeMemoryArea(
@ -716,10 +724,10 @@ MmFreeMemoryArea(
Address < (ULONG_PTR)EndAddress; Address < (ULONG_PTR)EndAddress;
Address += PAGE_SIZE) Address += PAGE_SIZE)
{ {
BOOLEAN Dirty = FALSE; BOOLEAN Dirty = FALSE;
SWAPENTRY SwapEntry = 0; SWAPENTRY SwapEntry = 0;
PFN_NUMBER Page = 0; PFN_NUMBER Page = 0;
if (MmIsPageSwapEntry(Process, (PVOID)Address)) if (MmIsPageSwapEntry(Process, (PVOID)Address))
{ {
MmDeletePageFileMapping(Process, (PVOID)Address, &SwapEntry); MmDeletePageFileMapping(Process, (PVOID)Address, &SwapEntry);
@ -733,6 +741,25 @@ MmFreeMemoryArea(
FreePage(FreePageContext, MemoryArea, (PVOID)Address, FreePage(FreePageContext, MemoryArea, (PVOID)Address,
Page, SwapEntry, (BOOLEAN)Dirty); 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 && if (Process != NULL &&

View file

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