[NTOSKRNL/MM]

- finally, release user shared data at process address space cleanup.
 - release PDE pages that might not be freed at process end.
 - Let the caller handle PDE release when deleting a PTE
 - restore Richard's ASSERT : All user PDE pages are now freed!

svn path=/trunk/; revision=55770
This commit is contained in:
Jérôme Gardou 2012-02-21 00:32:24 +00:00
parent 680e4604d2
commit 55993182a9
7 changed files with 97 additions and 67 deletions

View file

@ -931,8 +931,11 @@ MiDecrementShareCount(IN PMMPFN Pfn1,
ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
if (Pfn1->u3.e2.ReferenceCount == 1)
{
/* In ReactOS, this path should always be hit with a deleted PFN */
ASSERT(MI_IS_PFN_DELETED(Pfn1) == TRUE);
if(Pfn1->u3.e1.PrototypePte == 0)
{
/* In ReactOS, this path should always be hit with a deleted PFN */
ASSERT(MI_IS_PFN_DELETED(Pfn1) == TRUE);
}
/* Clear the last reference */
Pfn1->u3.e2.ReferenceCount = 0;

View file

@ -1349,6 +1349,8 @@ MmCleanProcessAddressSpace(IN PEPROCESS Process)
/* Free the VAD memory */
ExFreePool(Vad);
}
/* Delete the shared user data section */
MiDeleteVirtualAddresses(USER_SHARED_DATA, USER_SHARED_DATA, NULL);
/* Release the address space */
MmUnlockAddressSpace(&Process->Vm);
@ -1363,14 +1365,6 @@ MmDeleteProcessAddressSpace2(IN PEPROCESS Process)
PFN_NUMBER PageFrameIndex;
//ASSERT(Process->CommitCharge == 0);
/* Delete the shared user data section (Should be done in clean, not delete) */
ASSERT(MmHighestUserAddress > (PVOID)USER_SHARED_DATA);
KeAttachProcess(&Process->Pcb);
//DPRINT1("Killing shared user data page no longer works -- has someone changed ARM3 in a way to make this fail now?\n");
//MiDeleteVirtualAddresses(USER_SHARED_DATA, USER_SHARED_DATA, NULL);
//DPRINT1("Done\n");
KeDetachProcess();
/* Acquire the PFN lock */
OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
@ -1407,11 +1401,8 @@ MmDeleteProcessAddressSpace2(IN PEPROCESS Process)
MiDecrementShareCount(Pfn1, PageFrameIndex);
MiDecrementShareCount(Pfn1, PageFrameIndex);
/* HACK: In Richard's original patch this ASSERT did work */
//DPRINT1("Ref count: %lx %lx\n", Pfn1->u3.e2.ReferenceCount, Pfn1->u2.ShareCount);
//ASSERT((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress));
if(!((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress)))
DPRINT1("Ref count: %lx %lx\n", Pfn1->u3.e2.ReferenceCount, Pfn1->u2.ShareCount);
/* Page table is now dead. Bye bye... */
ASSERT((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress));
}
else
{

View file

@ -258,9 +258,6 @@ MiDeletePte(IN PMMPTE PointerPte,
#if (_MI_PAGING_LEVELS == 2)
}
#endif
/* Drop the reference on the page table. */
MiDecrementShareCount(MiGetPfnEntry(PFN_FROM_PTE(PointerPde)), PFN_FROM_PTE(PointerPde));
/* Drop the share count */
MiDecrementShareCount(Pfn1, PageFrameIndex);

View file

@ -250,6 +250,9 @@ MmRebalanceMemoryConsumers(VOID)
{
/* Clean up the unused PDEs */
ULONG_PTR Address;
PEPROCESS Process = PsGetCurrentProcess();
/* Acquire PFN lock */
KIRQL OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
PMMPDE pointerPde;
for(Address = (ULONG_PTR)MI_LOWEST_VAD_ADDRESS;
@ -260,10 +263,11 @@ MmRebalanceMemoryConsumers(VOID)
{
pointerPde = MiAddressToPde(Address);
if(pointerPde->u.Hard.Valid)
MiDeletePte(pointerPde, MiPdeToPte(pointerPde), PsGetCurrentProcess(), NULL);
MiDeletePte(pointerPde, MiPdeToPte(pointerPde), Process, NULL);
ASSERT(pointerPde->u.Hard.Valid == 0);
}
}
/* Release lock */
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
}
#endif

View file

@ -248,6 +248,10 @@ MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create)
PMMPDE PdeBase;
ULONG PdeOffset = MiGetPdeOffset(Address);
/* Nobody but page fault should ask for creating the PDE,
* Which imples that Process is the current one */
ASSERT(Create == FALSE);
PdeBase = MmCreateHyperspaceMapping(PTE_TO_PFN(Process->Pcb.DirectoryTableBase[0]));
if (PdeBase == NULL)
{
@ -256,24 +260,8 @@ MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create)
PointerPde = PdeBase + PdeOffset;
if (PointerPde->u.Hard.Valid == 0)
{
/* Nobody but page fault should ask for creating the PDE,
* Which imples that Process is the current one */
MmDeleteHyperspaceMapping(PdeBase);
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);
}
return NULL;
}
else
{
@ -717,9 +705,10 @@ MmCreatePageFileMapping(PEPROCESS Process,
KeBugCheck(MEMORY_MANAGEMENT);
}
Pt = MmGetPageTableForProcess(Process, Address, TRUE);
Pt = MmGetPageTableForProcess(Process, Address, FALSE);
if (Pt == NULL)
{
/* Nobody should page out an address that hasn't even been mapped */
KeBugCheck(MEMORY_MANAGEMENT);
}
Pte = InterlockedExchangePte(Pt, SwapEntry << 1);

View file

@ -1066,6 +1066,37 @@ MmDeleteProcessAddressSpace(PEPROCESS Process)
KeBugCheck(MEMORY_MANAGEMENT);
}
}
#if (_MI_PAGING_LEVELS == 2)
{
KIRQL OldIrql;
PMMPDE pointerPde;
/* Attach to Process */
KeAttachProcess(&Process->Pcb);
/* Acquire PFN lock */
OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
for(Address = MI_LOWEST_VAD_ADDRESS;
Address < MM_HIGHEST_VAD_ADDRESS;
Address =(PVOID)((ULONG_PTR)Address + (PAGE_SIZE * PTE_COUNT)))
{
/* At this point all references should be dead */
ASSERT(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] == 0);
pointerPde = MiAddressToPde(Address);
/* Unlike in ARM3, we don't necesarrily free the PDE page as soon as reference reaches 0,
* so we must clean up a bit when process closes */
if(pointerPde->u.Hard.Valid)
MiDeletePte(pointerPde, MiPdeToPte(pointerPde), Process, NULL);
ASSERT(pointerPde->u.Hard.Valid == 0);
}
/* Release lock */
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
/* Detach */
KeDetachProcess();
}
#endif
MmUnlockAddressSpace(&Process->Vm);

View file

@ -119,6 +119,7 @@ typedef struct
ULONG Offset;
BOOLEAN WasDirty;
BOOLEAN Private;
PEPROCESS CallingProcess;
}
MM_SECTION_PAGEOUT_CONTEXT;
@ -2052,10 +2053,11 @@ MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
}
#if (_MI_PAGING_LEVELS == 2)
if(Address < MmSystemRangeStart)
/* If this is for the calling process, we take care of te reference in the main function */
if((Address < MmSystemRangeStart) && (Process != PageOutContext->CallingProcess))
{
if(Process->VmDeleted) DPRINT1("deleted!!!");
Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
ASSERT(Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] < PTE_COUNT);
}
#endif
@ -2091,6 +2093,7 @@ MmPageOutSectionView(PMMSUPPORT AddressSpace,
*/
Context.Segment = MemoryArea->Data.SectionData.Segment;
Context.Section = MemoryArea->Data.SectionData.Section;
Context.CallingProcess = Process;
Context.Offset = (ULONG)((ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
+ MemoryArea->Data.SectionData.ViewOffset);
@ -2223,6 +2226,14 @@ MmPageOutSectionView(PMMSUPPORT AddressSpace,
}
if (!Context.WasDirty && SwapEntry != 0)
{
#if (_MI_PAGING_LEVELS == 2)
/* We keep the pagefile index global to the segment, not in the PTE */
if(Address < MmSystemRangeStart)
{
Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
ASSERT(Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] < PTE_COUNT);
}
#endif
MmSetSavedSwapEntryPage(Page, 0);
MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, MAKE_SWAP_SSE(SwapEntry));
MmReleasePageMemoryConsumer(MC_USER, Page);
@ -2241,6 +2252,14 @@ MmPageOutSectionView(PMMSUPPORT AddressSpace,
}
if (!Context.WasDirty || SwapEntry != 0)
{
#if (_MI_PAGING_LEVELS == 2)
/* We keep the pagefile index global to the segment, not in the PTE */
if(Address < MmSystemRangeStart)
{
Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
ASSERT(Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] < PTE_COUNT);
}
#endif
MmSetSavedSwapEntryPage(Page, 0);
if (SwapEntry != 0)
{
@ -2254,6 +2273,14 @@ MmPageOutSectionView(PMMSUPPORT AddressSpace,
}
else if (!Context.Private && DirectMapped)
{
#if (_MI_PAGING_LEVELS == 2)
/* Read only page, no need for a pagefile entry -> PDE-- */
if(Address < MmSystemRangeStart)
{
Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
ASSERT(Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] < PTE_COUNT);
}
#endif
if (SwapEntry != 0)
{
DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
@ -2282,6 +2309,14 @@ MmPageOutSectionView(PMMSUPPORT AddressSpace,
Address);
KeBugCheck(MEMORY_MANAGEMENT);
}
#if (_MI_PAGING_LEVELS == 2)
/* Non dirty, non private, non direct-mapped -> PDE-- */
if(Address < MmSystemRangeStart)
{
Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
ASSERT(Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] < PTE_COUNT);
}
#endif
MmReleasePageMemoryConsumer(MC_USER, Page);
PageOp->Status = STATUS_SUCCESS;
MmspCompleteAndReleasePageOp(PageOp);
@ -2291,13 +2326,6 @@ 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);
@ -2325,13 +2353,6 @@ 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,
@ -2382,13 +2403,6 @@ 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)
{
@ -2440,13 +2454,6 @@ 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);
@ -2458,6 +2465,14 @@ MmPageOutSectionView(PMMSUPPORT AddressSpace,
}
else
{
#if (_MI_PAGING_LEVELS == 2)
/* We keep the pagefile index global to the segment, not in the PTE */
if(Address < MmSystemRangeStart)
{
Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
ASSERT(Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] < PTE_COUNT);
}
#endif
Entry = MAKE_SWAP_SSE(SwapEntry);
MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
}