mirror of
https://github.com/reactos/reactos.git
synced 2025-01-06 06:20:13 +00:00
[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:
parent
680e4604d2
commit
55993182a9
7 changed files with 97 additions and 67 deletions
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue