mirror of
https://github.com/reactos/reactos.git
synced 2025-07-31 19:01:48 +00:00
[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:
parent
30703d5a5d
commit
d720941f1e
5 changed files with 181 additions and 22 deletions
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 &&
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue