Skip to content

Commit d720941

Browse files
committed
[NTOSKRNL/MM]
- Stop leaking references to PDEs. Still one reference left to the TLB mapping at process deletion. svn path=/trunk/; revision=55763
1 parent 30703d5 commit d720941

File tree

5 files changed

+181
-22
lines changed

5 files changed

+181
-22
lines changed

reactos/ntoskrnl/mm/anonmem.c

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ MmPageOutVirtualMemory(PMMSUPPORT AddressSpace,
113113
MmCreatePageFileMapping(Process, Address, SwapEntry);
114114
MmSetSavedSwapEntryPage(Page, 0);
115115
}
116+
#if (_MI_PAGING_LEVELS == 2)
117+
else if(Address < MmSystemRangeStart)
118+
{
119+
AddressSpace->VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
120+
}
121+
#endif
116122
MmUnlockAddressSpace(AddressSpace);
117123
MmReleasePageMemoryConsumer(MC_USER, Page);
118124
PageOp->Status = STATUS_SUCCESS;
@@ -191,6 +197,9 @@ MmNotPresentFaultVirtualMemory(PMMSUPPORT AddressSpace,
191197
PMM_REGION Region;
192198
PMM_PAGEOP PageOp;
193199
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
200+
#if (_MI_PAGING_LEVELS == 2)
201+
BOOLEAN refPde = TRUE;
202+
#endif
194203

195204
/*
196205
* There is a window between taking the page fault and locking the
@@ -326,7 +335,17 @@ MmNotPresentFaultVirtualMemory(PMMSUPPORT AddressSpace,
326335
KeBugCheck(MEMORY_MANAGEMENT);
327336
}
328337
MmSetSavedSwapEntryPage(Page, SwapEntry);
338+
339+
#if (_MI_PAGING_LEVELS == 2)
340+
/* PTE was already "created", no need to reference PDE */
341+
refPde = FALSE;
342+
#endif
329343
}
344+
#if (_MI_PAGING_LEVELS == 2)
345+
/* Add an additional page table reference */
346+
if(refPde) MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
347+
ASSERT(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] <= PTE_COUNT);
348+
#endif
330349

331350
/*
332351
* Set the page. If we fail because we are out of memory then
@@ -337,16 +356,6 @@ MmNotPresentFaultVirtualMemory(PMMSUPPORT AddressSpace,
337356
Region->Protect,
338357
&Page,
339358
1);
340-
while (Status == STATUS_NO_MEMORY)
341-
{
342-
MmUnlockAddressSpace(AddressSpace);
343-
Status = MmCreateVirtualMapping(Process,
344-
(PVOID)PAGE_ROUND_DOWN(Address),
345-
Region->Protect,
346-
&Page,
347-
1);
348-
MmLockAddressSpace(AddressSpace);
349-
}
350359
if (!NT_SUCCESS(Status))
351360
{
352361
DPRINT1("MmCreateVirtualMapping failed, not out of memory\n");
@@ -393,21 +402,27 @@ MmModifyAttributes(PMMSUPPORT AddressSpace,
393402
for (i=0; i < PAGE_ROUND_UP(RegionSize)/PAGE_SIZE; i++)
394403
{
395404
PFN_NUMBER Page;
405+
PVOID Address = (char*)BaseAddress + (i*PAGE_SIZE);
396406

397-
if (MmIsPageSwapEntry(Process,
398-
(char*)BaseAddress + (i * PAGE_SIZE)))
407+
if (MmIsPageSwapEntry(Process, Address))
399408
{
400409
SWAPENTRY SwapEntry;
401410

402411
MmDeletePageFileMapping(Process,
403412
(char*)BaseAddress + (i * PAGE_SIZE),
404413
&SwapEntry);
405414
MmFreeSwapPage(SwapEntry);
415+
#if (_MI_PAGING_LEVELS == 2)
416+
if(Address < MmSystemRangeStart)
417+
{
418+
AddressSpace->VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
419+
}
420+
#endif
406421
}
407422
else
408423
{
409424
MmDeleteVirtualMapping(Process,
410-
(char*)BaseAddress + (i*PAGE_SIZE),
425+
Address,
411426
FALSE, NULL, &Page);
412427
if (Page != 0)
413428
{
@@ -417,10 +432,16 @@ MmModifyAttributes(PMMSUPPORT AddressSpace,
417432
{
418433
MmFreeSwapPage(SavedSwapEntry);
419434
MmSetSavedSwapEntryPage(Page, 0);
420-
}
435+
}
421436
MmDeleteRmap(Page, Process,
422437
(char*)BaseAddress + (i * PAGE_SIZE));
423438
MmReleasePageMemoryConsumer(MC_USER, Page);
439+
#if (_MI_PAGING_LEVELS == 2)
440+
if(Address < MmSystemRangeStart)
441+
{
442+
AddressSpace->VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
443+
}
444+
#endif
424445
}
425446
}
426447
}

reactos/ntoskrnl/mm/balance.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#define NDEBUG
1515
#include <debug.h>
1616

17+
#include "ARM3/miarm.h"
18+
1719
#if defined (ALLOC_PRAGMA)
1820
#pragma alloc_text(INIT, MmInitializeBalancer)
1921
#pragma alloc_text(INIT, MmInitializeMemoryConsumer)
@@ -232,10 +234,40 @@ MiIsBalancerThread(VOID)
232234
(PsGetCurrentThreadId() == MiBalancerThreadId.UniqueThread);
233235
}
234236

237+
VOID
238+
NTAPI
239+
MiDeletePte(IN PMMPTE PointerPte,
240+
IN PVOID VirtualAddress,
241+
IN PEPROCESS CurrentProcess,
242+
IN PMMPTE PrototypePte);
243+
235244
VOID
236245
NTAPI
237246
MmRebalanceMemoryConsumers(VOID)
238247
{
248+
#if (_MI_PAGING_LEVELS == 2)
249+
if(!MiIsBalancerThread())
250+
{
251+
/* Clean up the unused PDEs */
252+
ULONG_PTR Address;
253+
KIRQL OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
254+
PMMPDE pointerPde;
255+
for(Address = (ULONG_PTR)MI_LOWEST_VAD_ADDRESS;
256+
Address < (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS;
257+
Address += (PAGE_SIZE * PTE_COUNT))
258+
{
259+
if(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] == 0)
260+
{
261+
pointerPde = MiAddressToPde(Address);
262+
if(pointerPde->u.Hard.Valid)
263+
MiDeletePte(pointerPde, MiPdeToPte(pointerPde), PsGetCurrentProcess(), NULL);
264+
ASSERT(pointerPde->u.Hard.Valid == 0);
265+
}
266+
}
267+
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
268+
}
269+
#endif
270+
239271
if (MiBalancerThreadHandle != NULL &&
240272
!MiIsBalancerThread())
241273
{

reactos/ntoskrnl/mm/i386/page.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,22 @@ MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create)
258258
{
259259
/* Nobody but page fault should ask for creating the PDE,
260260
* Which imples that Process is the current one */
261-
ASSERT(Create == FALSE);
262261
MmDeleteHyperspaceMapping(PdeBase);
263-
return NULL;
262+
if(Create == FALSE)
263+
return NULL;
264+
else
265+
{
266+
KAPC_STATE ApcState;
267+
PULONG ret;
268+
/* Attach to process */
269+
KeStackAttachProcess(&Process->Pcb, &ApcState);
270+
271+
/* Retry */
272+
ret = MmGetPageTableForProcess(Process, Address, TRUE);
273+
274+
/* Get Back to original process */
275+
KeUnstackDetachProcess(&ApcState);
276+
}
264277
}
265278
else
266279
{
@@ -293,6 +306,7 @@ MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create)
293306
}
294307

295308
/* This is for kernel land address */
309+
ASSERT(Process == NULL);
296310
PointerPde = MiAddressToPde(Address);
297311
Pt = (PULONG)MiAddressToPte(Address);
298312
if (PointerPde->u.Hard.Valid == 0)

reactos/ntoskrnl/mm/marea.c

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@
4545
#define NDEBUG
4646
#include <debug.h>
4747

48+
#include "ARM3/miarm.h"
49+
4850
MEMORY_AREA MiStaticMemoryAreas[MI_STATIC_MEMORY_AREAS];
4951
ULONG MiStaticMemoryAreaCount;
5052

@@ -688,6 +690,12 @@ IN PMM_AVL_TABLE Table);
688690
*
689691
* @remarks Lock the address space before calling this function.
690692
*/
693+
VOID
694+
NTAPI
695+
MiDeletePte(IN PMMPTE PointerPte,
696+
IN PVOID VirtualAddress,
697+
IN PEPROCESS CurrentProcess,
698+
IN PMMPTE PrototypePte);
691699

692700
NTSTATUS NTAPI
693701
MmFreeMemoryArea(
@@ -716,10 +724,10 @@ MmFreeMemoryArea(
716724
Address < (ULONG_PTR)EndAddress;
717725
Address += PAGE_SIZE)
718726
{
719-
BOOLEAN Dirty = FALSE;
720-
SWAPENTRY SwapEntry = 0;
721-
PFN_NUMBER Page = 0;
722-
727+
BOOLEAN Dirty = FALSE;
728+
SWAPENTRY SwapEntry = 0;
729+
PFN_NUMBER Page = 0;
730+
723731
if (MmIsPageSwapEntry(Process, (PVOID)Address))
724732
{
725733
MmDeletePageFileMapping(Process, (PVOID)Address, &SwapEntry);
@@ -733,6 +741,25 @@ MmFreeMemoryArea(
733741
FreePage(FreePageContext, MemoryArea, (PVOID)Address,
734742
Page, SwapEntry, (BOOLEAN)Dirty);
735743
}
744+
#if (_MI_PAGING_LEVELS == 2)
745+
/* Remove page table reference */
746+
if((SwapEntry || Page) && ((PVOID)Address < MmSystemRangeStart))
747+
{
748+
ASSERT(AddressSpace != MmGetKernelAddressSpace());
749+
MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
750+
ASSERT(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] < PTE_COUNT);
751+
if(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] == 0)
752+
{
753+
/* No PTE relies on this PDE. Release it */
754+
KIRQL OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
755+
PMMPDE PointerPde = MiAddressToPde(Address);
756+
ASSERT(PointerPde->u.Hard.Valid == 1);
757+
MiDeletePte(PointerPde, MiPdeToPte(PointerPde), Process, NULL);
758+
ASSERT(PointerPde->u.Hard.Valid == 0);
759+
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
760+
}
761+
}
762+
#endif
736763
}
737764

738765
if (Process != NULL &&

reactos/ntoskrnl/mm/section.c

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
#pragma alloc_text(INIT, MmInitSectionImplementation)
5858
#endif
5959

60+
#include "ARM3/miarm.h"
61+
6062
NTSTATUS
6163
NTAPI
6264
MiMapViewInSystemSpace(IN PVOID Section,
@@ -1448,6 +1450,15 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
14481450
Page = PFN_FROM_SSE(Entry);
14491451

14501452
MmSharePageEntrySectionSegment(Segment, Offset);
1453+
1454+
#if (_MI_PAGING_LEVELS == 2)
1455+
/* Reference Page Directory Entry */
1456+
if(Address < MmSystemRangeStart)
1457+
{
1458+
MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
1459+
ASSERT(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] <= PTE_COUNT);
1460+
}
1461+
#endif
14511462

14521463
/* FIXME: Should we call MmCreateVirtualMappingUnsafe if
14531464
* (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
@@ -1538,6 +1549,15 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
15381549
return(STATUS_SUCCESS);
15391550
}
15401551

1552+
#if (_MI_PAGING_LEVELS == 2)
1553+
/* Reference Page Directory Entry */
1554+
if(Address < MmSystemRangeStart)
1555+
{
1556+
MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
1557+
ASSERT(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] <= PTE_COUNT);
1558+
}
1559+
#endif
1560+
15411561
/*
15421562
* Satisfying a page fault on a map of /Device/PhysicalMemory is easy
15431563
*/
@@ -1658,6 +1678,12 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
16581678
/*
16591679
* Cleanup and release locks
16601680
*/
1681+
#if (_MI_PAGING_LEVELS == 2)
1682+
if(Address < MmSystemRangeStart)
1683+
{
1684+
MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
1685+
}
1686+
#endif
16611687
MmLockAddressSpace(AddressSpace);
16621688
PageOp->Status = Status;
16631689
MmspCompleteAndReleasePageOp(PageOp);
@@ -1876,7 +1902,10 @@ MmAccessFaultSectionView(PMMSUPPORT AddressSpace,
18761902
MmSetPageProtect(Process, Address, Region->Protect);
18771903
return(STATUS_SUCCESS);
18781904
}
1879-
1905+
1906+
if(OldPage == 0)
1907+
DPRINT("OldPage == 0!\n");
1908+
18801909
/*
18811910
* Get or create a pageop
18821911
*/
@@ -1986,7 +2015,7 @@ MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
19862015
MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
19872016
BOOLEAN WasDirty;
19882017
PFN_NUMBER Page;
1989-
2018+
19902019
PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
19912020
if (Process)
19922021
{
@@ -2022,6 +2051,14 @@ MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
20222051
MmReleasePageMemoryConsumer(MC_USER, Page);
20232052
}
20242053

2054+
#if (_MI_PAGING_LEVELS == 2)
2055+
if(Address < MmSystemRangeStart)
2056+
{
2057+
if(Process->VmDeleted) DPRINT1("deleted!!!");
2058+
Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
2059+
}
2060+
#endif
2061+
20252062
DPRINT("PhysicalAddress %x, Address %x\n", Page << PAGE_SHIFT, Address);
20262063
}
20272064

@@ -2254,6 +2291,13 @@ MmPageOutSectionView(PMMSUPPORT AddressSpace,
22542291
{
22552292
MmSetSavedSwapEntryPage(Page, 0);
22562293
MmLockAddressSpace(AddressSpace);
2294+
#if (_MI_PAGING_LEVELS == 2)
2295+
/* Page table was dereferenced while deleting the RMAP */
2296+
if(Address < MmSystemRangeStart)
2297+
{
2298+
AddressSpace->VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
2299+
}
2300+
#endif
22572301
Status = MmCreatePageFileMapping(Process,
22582302
Address,
22592303
SwapEntry);
@@ -2281,6 +2325,13 @@ MmPageOutSectionView(PMMSUPPORT AddressSpace,
22812325
/*
22822326
* For private pages restore the old mappings.
22832327
*/
2328+
#if (_MI_PAGING_LEVELS == 2)
2329+
/* Page table was dereferenced while deleting the RMAP */
2330+
if(Address < MmSystemRangeStart)
2331+
{
2332+
AddressSpace->VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
2333+
}
2334+
#endif
22842335
if (Context.Private)
22852336
{
22862337
Status = MmCreateVirtualMapping(Process,
@@ -2331,6 +2382,13 @@ MmPageOutSectionView(PMMSUPPORT AddressSpace,
23312382
* As above: undo our actions.
23322383
* FIXME: Also free the swap page.
23332384
*/
2385+
#if (_MI_PAGING_LEVELS == 2)
2386+
/* Page table was dereferenced while deleting the RMAP */
2387+
if(Address < MmSystemRangeStart)
2388+
{
2389+
AddressSpace->VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
2390+
}
2391+
#endif
23342392
MmLockAddressSpace(AddressSpace);
23352393
if (Context.Private)
23362394
{
@@ -2382,6 +2440,13 @@ MmPageOutSectionView(PMMSUPPORT AddressSpace,
23822440
if (Context.Private)
23832441
{
23842442
MmLockAddressSpace(AddressSpace);
2443+
#if (_MI_PAGING_LEVELS == 2)
2444+
/* Page table was dereferenced while deleting the RMAP */
2445+
if(Address < MmSystemRangeStart)
2446+
{
2447+
AddressSpace->VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
2448+
}
2449+
#endif
23852450
Status = MmCreatePageFileMapping(Process,
23862451
Address,
23872452
SwapEntry);

0 commit comments

Comments
 (0)