Author: ion
Date: Fri Feb 17 07:23:27 2012
New Revision: 55667
URL: http://svn.reactos.org/svn/reactos?rev=55667&view=rev
Log:
[NTOSKRNL]: This second part of Richard's patch implements MmFreeLoaderBlock, which results in 932KB less RAM being used on my 3rd stage test after first boot. It deletes the boot registry, NLS, and heap data.
Modified:
trunk/reactos/ntoskrnl/ex/init.c
trunk/reactos/ntoskrnl/mm/ARM3/mminit.c
Modified: trunk/reactos/ntoskrnl/ex/init.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ex/init.c?rev=556…
==============================================================================
--- trunk/reactos/ntoskrnl/ex/init.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ex/init.c [iso-8859-1] Fri Feb 17 07:23:27 2012
@@ -1285,6 +1285,10 @@
SharedUserData->ImageNumberLow = IMAGE_FILE_MACHINE_NATIVE;
SharedUserData->ImageNumberHigh = IMAGE_FILE_MACHINE_NATIVE;
}
+
+VOID
+NTAPI
+MmFreeLoaderBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock);
VOID
NTAPI
@@ -1906,6 +1910,7 @@
/* Make sure nobody touches the loader block again */
if (LoaderBlock == KeLoaderBlock) KeLoaderBlock = NULL;
+ MmFreeLoaderBlock(LoaderBlock);
LoaderBlock = Context = NULL;
/* Update progress bar */
Modified: trunk/reactos/ntoskrnl/mm/ARM3/mminit.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/mminit.c?…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/mminit.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/mminit.c [iso-8859-1] Fri Feb 17 07:23:27 2012
@@ -1067,6 +1067,116 @@
VOID
NTAPI
INIT_FUNCTION
+MmFreeLoaderBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+ PLIST_ENTRY NextMd;
+ PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
+ ULONG i;
+ PFN_NUMBER BasePage, LoaderPages;
+ PMMPFN Pfn1;
+ KIRQL OldIrql;
+ PPHYSICAL_MEMORY_RUN Buffer, Entry;
+
+ /* Loop the descriptors in order to count them */
+ i = 0;
+ NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextMd != &LoaderBlock->MemoryDescriptorListHead)
+ {
+ MdBlock = CONTAINING_RECORD(NextMd,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+ i++;
+ NextMd = MdBlock->ListEntry.Flink;
+ }
+
+ /* Allocate a structure to hold the physical runs */
+ Buffer = ExAllocatePoolWithTag(NonPagedPool,
+ i * sizeof(PHYSICAL_MEMORY_RUN),
+ 'lMmM');
+ ASSERT(Buffer != NULL);
+ Entry = Buffer;
+
+ /* Loop the descriptors again */
+ NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextMd != &LoaderBlock->MemoryDescriptorListHead)
+ {
+ /* Check what kind this was */
+ MdBlock = CONTAINING_RECORD(NextMd,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+ switch (MdBlock->MemoryType)
+ {
+ /* Registry, NLS, and heap data */
+ case LoaderRegistryData:
+ case LoaderOsloaderHeap:
+ case LoaderNlsData:
+ /* Are all a candidate for deletion */
+ Entry->BasePage = MdBlock->BasePage;
+ Entry->PageCount = MdBlock->PageCount;
+ Entry++;
+
+ /* We keep the rest */
+ default:
+ break;
+ }
+
+ /* Move to the next descriptor */
+ NextMd = MdBlock->ListEntry.Flink;
+ }
+
+ /* Acquire the PFN lock */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ /* Loop the runs */
+ LoaderPages = 0;
+ while (--Entry >= Buffer)
+ {
+ /* See how many pages are in this run */
+ i = Entry->PageCount;
+ BasePage = Entry->BasePage;
+
+ /* Loop each page */
+ Pfn1 = MiGetPfnEntry(BasePage);
+ while (i--)
+ {
+ /* Check if it has references or is in any kind of list */
+ if (!(Pfn1->u3.e2.ReferenceCount) && (!Pfn1->u1.Flink))
+ {
+ /* Set the new PTE address and put this page into the free list */
+ Pfn1->PteAddress = (PMMPTE)(BasePage << PAGE_SHIFT);
+ MiInsertPageInFreeList(BasePage);
+ LoaderPages++;
+ }
+ else if (BasePage)
+ {
+ /* It has a reference, so simply drop it */
+ ASSERT(MI_IS_PHYSICAL_ADDRESS(MiPteToAddress(Pfn1->PteAddress)) == FALSE);
+
+ /* Drop a dereference on this page, which should delete it */
+ Pfn1->PteAddress->u.Long = 0;
+ MI_SET_PFN_DELETED(Pfn1);
+ MiDecrementShareCount(Pfn1, BasePage);
+ LoaderPages++;
+ }
+
+ /* Move to the next page */
+ Pfn1++;
+ BasePage++;
+ }
+ }
+
+ /* Release the PFN lock and flush the TLB */
+ DPRINT1("Loader pages freed: %lx\n", LoaderPages);
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+ KeFlushCurrentTb();
+
+ /* Free our run structure */
+ ExFreePool(Buffer);
+}
+
+VOID
+NTAPI
+INIT_FUNCTION
MiAdjustWorkingSetManagerParameters(IN BOOLEAN Client)
{
/* This function needs to do more work, for now, we tune page minimums */
Author: ion
Date: Fri Feb 17 07:07:47 2012
New Revision: 55666
URL: http://svn.reactos.org/svn/reactos?rev=55666&view=rev
Log:
[NTOSKRNL]: This is kind of embarssing, but after doing a local grep for some of cgutman and zekflop's changes (respectively the patch that had added MmDeleteProcessPageDirectory, and the mshtml fix patch), I fell upon a .patch file. It included 3 memory-leak-fixing patches from richard that had been sent to me during his last days -- which, had I paid attention, would've fixed the MSHTML bug and the memory leaks months ago! I've tried my best to now re-integrate a portion of the patch (the other two portions deal with freeing the loader block, and freeing .INIT sections, and I will commit them later) with the current state of trunk. Some things that patch did, no longer seem to work, and I've commented where appropriate. But in general it does seem to dereference/delete some PTEs that had been left behind before (such as deleted TEBs, and deleted VA mappings). It no longer seems to be able to delete the root PDE nor the shared data page however (this worked in the original patch's timeframe). Zekflop, tkreuzer, please take a look. I hope this will set us on a better path!
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/procsup.c
trunk/reactos/ntoskrnl/mm/ARM3/virtual.c
trunk/reactos/ntoskrnl/mm/amd64/page.c
trunk/reactos/ntoskrnl/mm/i386/page.c
trunk/reactos/ntoskrnl/mm/marea.c
Modified: trunk/reactos/ntoskrnl/mm/ARM3/procsup.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/procsup.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/procsup.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/procsup.c [iso-8859-1] Fri Feb 17 07:07:47 2012
@@ -199,6 +199,9 @@
ASSERT(VadTree->NumberGenericTableElements >= 1);
MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree);
+ /* Delete the pages */
+ MiDeleteVirtualAddresses((ULONG_PTR)Teb, TebEnd, NULL);
+
/* Release the working set */
MiUnlockProcessWorkingSet(Process, Thread);
@@ -219,7 +222,7 @@
IN BOOLEAN GuiStack)
{
PMMPTE PointerPte;
- PFN_NUMBER PageFrameNumber;//, PageTableFrameNumber;
+ PFN_NUMBER PageFrameNumber, PageTableFrameNumber;
PFN_COUNT StackPages;
PMMPFN Pfn1;//, Pfn2;
ULONG i;
@@ -253,13 +256,14 @@
/* Get the PTE's page */
PageFrameNumber = PFN_FROM_PTE(PointerPte);
Pfn1 = MiGetPfnEntry(PageFrameNumber);
-#if 0 // ARM3 might not own the page table, so don't take this risk. Leak it instead!
+#if 1 // ARM3 might not own the page table, so don't take this risk. Leak it instead!
/* Now get the page of the page table mapping it */
PageTableFrameNumber = Pfn1->u4.PteFrame;
- Pfn2 = MiGetPfnEntry(PageTableFrameNumber);
+ //Pfn2 = MiGetPfnEntry(PageTableFrameNumber);
/* Remove a shared reference, since the page is going away */
- MiDecrementShareCount(Pfn2, PageTableFrameNumber);
+ DPRINT("SystemPTE PDE: %lx\n", PageTableFrameNumber);
+ //MiDecrementShareCount(Pfn2, PageTableFrameNumber);
#endif
/* Set the special pending delete marker */
MI_SET_PFN_DELETED(Pfn1);
@@ -1340,6 +1344,102 @@
MmUnlockAddressSpace(&Process->Vm);
}
+VOID
+NTAPI
+MmDeleteProcessAddressSpace2(IN PEPROCESS Process)
+{
+ PMMPFN Pfn1, Pfn2;
+ KIRQL OldIrql;
+ PFN_NUMBER PageFrameIndex;
+ PULONG PageDir;
+ ULONG i;
+
+ //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);
+
+ /* Check for fully initialized process */
+ if (Process->AddressSpaceInitialized == 2)
+ {
+ /* Map the PDE */
+ PageDir = MmCreateHyperspaceMapping(Process->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT);
+ for (i = 0; i < ADDR_TO_PDE_OFFSET(MmSystemRangeStart); i++)
+ {
+ /* Loop all page tables */
+ if (PageDir[i] != 0)
+ {
+ /* Check if they are RosMm-owned */
+ if (MI_IS_ROS_PFN(MiGetPfnEntry(PageDir[i] >> PAGE_SHIFT)))
+ {
+ /* Free them through the RosMm ABI */
+ //DPRINT1("Freeing MC_SYSTEM: %lx\n", PageDir[i]);
+ MmReleasePageMemoryConsumer(MC_SYSTEM, PageDir[i] >> PAGE_SHIFT);
+ }
+ }
+ }
+
+ /* Unmap the PDE */
+ //DPRINT1("Done\n");
+ MmDeleteHyperspaceMapping(PageDir);
+
+ /* Map the working set page and its page table */
+ Pfn1 = MiGetPfnEntry(Process->WorkingSetPage);
+ Pfn2 = MiGetPfnEntry(Pfn1->u4.PteFrame);
+
+ /* Nuke it */
+ MI_SET_PFN_DELETED(Pfn1);
+ MiDecrementShareCount(Pfn2, Pfn1->u4.PteFrame);
+ MiDecrementShareCount(Pfn1, Process->WorkingSetPage);
+ ASSERT((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress));
+
+ /* Now map hyperspace and its page table */
+ PageFrameIndex = Process->Pcb.DirectoryTableBase[1] >> PAGE_SHIFT;
+ Pfn1 = MiGetPfnEntry(PageFrameIndex);
+ Pfn2 = MiGetPfnEntry(Pfn1->u4.PteFrame);
+
+ /* Nuke it */
+ MI_SET_PFN_DELETED(Pfn1);
+ MiDecrementShareCount(Pfn2, Pfn1->u4.PteFrame);
+ MiDecrementShareCount(Pfn1, PageFrameIndex);
+ ASSERT((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress));
+
+ /* Finally, nuke the PDE itself */
+ PageFrameIndex = Process->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT;
+ Pfn1 = MiGetPfnEntry(PageFrameIndex);
+ MI_SET_PFN_DELETED(Pfn1);
+ 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));
+ }
+ else
+ {
+ /* A partly-initialized process should never exit through here */
+ ASSERT(FALSE);
+ }
+
+ /* Release the PFN lock */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+ /* No support for sessions yet */
+ ASSERT(Process->Session == 0);
+
+ /* Clear out the PDE pages */
+ Process->Pcb.DirectoryTableBase[0] = 0;
+ Process->Pcb.DirectoryTableBase[1] = 0;
+}
+
/* SESSION CODE TO MOVE TO SESSION.C ******************************************/
KGUARDED_MUTEX MiSessionIdMutex;
Modified: trunk/reactos/ntoskrnl/mm/ARM3/virtual.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/virtual.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/virtual.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/virtual.c [iso-8859-1] Fri Feb 17 07:07:47 2012
@@ -264,8 +264,21 @@
/* Drop the share count */
MiDecrementShareCount(Pfn1, PageFrameIndex);
- /* No fork yet */
- if (PointerPte <= MiHighestUserPte) ASSERT(PrototypePte == Pfn1->PteAddress);
+ /* Either a fork, or this is the shared user data page */
+ if (PointerPte <= MiHighestUserPte)
+ {
+ /* If it's not the shared user page, then crash, since there's no fork() yet */
+ if ((PAGE_ALIGN(VirtualAddress) != (PVOID)USER_SHARED_DATA) ||
+ (MmHighestUserAddress <= (PVOID)USER_SHARED_DATA))
+ {
+ /* Must be some sort of memory corruption */
+ KeBugCheckEx(MEMORY_MANAGEMENT,
+ 0x400,
+ (ULONG_PTR)PointerPte,
+ (ULONG_PTR)PrototypePte,
+ (ULONG_PTR)Pfn1->PteAddress);
+ }
+ }
}
else
{
@@ -284,7 +297,8 @@
ASSERT(Pfn1->u2.ShareCount == 1);
/* FIXME: Drop the reference on the page table. For now, leak it until RosMM is gone */
- //MiDecrementShareCount(MiGetPfnEntry(Pfn1->u4.PteFrame), Pfn1->u4.PteFrame);
+ //DPRINT1("Dropping a ref...\n");
+ MiDecrementShareCount(MiGetPfnEntry(Pfn1->u4.PteFrame), Pfn1->u4.PteFrame);
/* Mark the PFN for deletion and dereference what should be the last ref */
MI_SET_PFN_DELETED(Pfn1);
@@ -312,6 +326,7 @@
KIRQL OldIrql;
BOOLEAN AddressGap = FALSE;
PSUBSECTION Subsection;
+ PUSHORT UsedPageTableEntries;
/* Get out if this is a fake VAD, RosMm will free the marea pages */
if ((Vad) && (Vad->u.VadFlags.Spare == 1)) return;
@@ -368,6 +383,7 @@
/* Now we should have a valid PDE, mapped in, and still have some VA */
ASSERT(PointerPde->u.Hard.Valid == 1);
ASSERT(Va <= EndingAddress);
+ UsedPageTableEntries = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Va)];
/* Check if this is a section VAD with gaps in it */
if ((AddressGap) && (LastPrototypePte))
@@ -397,6 +413,11 @@
TempPte = *PointerPte;
if (TempPte.u.Long)
{
+ DPRINT("Decrement used PTEs by address: %lx\n", Va);
+ (*UsedPageTableEntries)--;
+ ASSERT((*UsedPageTableEntries) < PTE_COUNT);
+ DPRINT("Refs: %lx\n", (*UsedPageTableEntries));
+
/* Check if the PTE is actually mapped in */
if (TempPte.u.Long & 0xFFFFFC01)
{
@@ -456,6 +477,22 @@
/* The PDE should still be valid at this point */
ASSERT(PointerPde->u.Hard.Valid == 1);
+ DPRINT("Should check if handles for: %p are zero (PDE: %lx)\n", Va, PointerPde->u.Hard.PageFrameNumber);
+ if (!(*UsedPageTableEntries))
+ {
+ DPRINT("They are!\n");
+ if (PointerPde->u.Long != 0)
+ {
+ DPRINT("PDE active: %lx in %16s\n", PointerPde->u.Hard.PageFrameNumber, CurrentProcess->ImageFileName);
+
+ /* Delete the PTE proper */
+ MiDeletePte(PointerPde,
+ MiPteToAddress(PointerPde),
+ CurrentProcess,
+ NULL);
+ }
+ }
+
/* Release the lock and get out if we're done */
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
if (Va > EndingAddress) return;
Modified: trunk/reactos/ntoskrnl/mm/amd64/page.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/amd64/page.c?r…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/amd64/page.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/amd64/page.c [iso-8859-1] Fri Feb 17 07:07:47 2012
@@ -188,29 +188,6 @@
}
}
-VOID
-NTAPI
-MmDeleteProcessPageDirectory(PEPROCESS Process)
-{
- PFN_NUMBER TableBasePfn;
- PMMPTE PageDir;
-
- /* Get the page directory PFN */
- TableBasePfn = Process->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT;
-
- /* Map the page directory in hyperspace */
- PageDir = (PMMPTE)MmCreateHyperspaceMapping(TableBasePfn);
-
- /* Free the hyperspace mapping page (ARM3) */
- //MmDeletePageTablePfn(PageDir[ADDR_TO_PDE_OFFSET(HYPERSPACE)].u.Hard.PageFrameNumber, 3);
-
- /* Delete the hyperspace mapping */
- MmDeleteHyperspaceMapping(PageDir);
-
- /* Recursively free the page directories */
- MmDeletePageTablePfn(TableBasePfn, 4);
-}
-
static
PMMPTE
MiGetPteForProcess(
Modified: trunk/reactos/ntoskrnl/mm/i386/page.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/i386/page.c?re…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/i386/page.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/i386/page.c [iso-8859-1] Fri Feb 17 07:07:47 2012
@@ -198,62 +198,6 @@
return(Attributes);
}
-VOID
-FORCEINLINE
-MmDeletePageDirectoryEntry(PMMPDE PointerPde)
-{
- KIRQL OldIrql;
- PMMPFN Page;
-
- Page = MiGetPfnEntry(PointerPde->u.Hard.PageFrameNumber);
-
- /* This should not be a legacy allocation*/
- ASSERT(MI_IS_ROS_PFN(Page) == FALSE);
-
- OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-
- /* Free it using the ARM3 API */
- MI_SET_PFN_DELETED(Page);
- MiDecrementShareCount(Page, PointerPde->u.Hard.PageFrameNumber);
-
- KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
-}
-
-VOID
-NTAPI
-MmDeleteProcessPageDirectory(PEPROCESS Process)
-{
- PMMPDE PdeBase, PointerPde;
- ULONG PdeOffset;
- KIRQL OldIrql;
-
- /* Map the page directory in hyperspace */
- PdeBase = MiMapPageInHyperSpace(PsGetCurrentProcess(),
- Process->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT,
- &OldIrql);
-
- /* Loop the user land page directory */
- for (PdeOffset = 0; PdeOffset < MiGetPdeOffset(MmSystemRangeStart); PdeOffset++)
- {
- PointerPde = PdeBase + PdeOffset;
- /* Check if a valid PDE exists here */
- if (PointerPde->u.Hard.Valid)
- {
- /* Free the page that backs it */
- MmDeletePageDirectoryEntry(PointerPde);
- }
- }
-
- /* Free the hyperspace mapping page (ARM3) */
- MmDeletePageDirectoryEntry(PdeBase + MiGetPdeOffset(HYPERSPACE));
-
- /* Delete the hyperspace mapping */
- MiUnmapPageInHyperSpace(PsGetCurrentProcess(), PdeBase, OldIrql);
-
- /* Free the PDE page itself (ARM3) */
- MmDeletePageDirectoryEntry((PMMPDE)&Process->Pcb.DirectoryTableBase[0]);
-}
-
/* Taken from ARM3/pagfault.c */
BOOLEAN
FORCEINLINE
Modified: trunk/reactos/ntoskrnl/mm/marea.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/marea.c?rev=55…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/marea.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/marea.c [iso-8859-1] Fri Feb 17 07:07:47 2012
@@ -994,6 +994,10 @@
}
}
+VOID
+NTAPI
+MmDeleteProcessAddressSpace2(IN PEPROCESS Process);
+
NTSTATUS
NTAPI
MmDeleteProcessAddressSpace(PEPROCESS Process)
@@ -1036,11 +1040,10 @@
}
}
- MmDeleteProcessPageDirectory(Process);
-
MmUnlockAddressSpace(&Process->Vm);
DPRINT("Finished MmReleaseMmInfo()\n");
+ MmDeleteProcessAddressSpace2(Process);
return(STATUS_SUCCESS);
}