From 6a5fd8f48795ab1819484b433194ee9357eb8bf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Gardou?= Date: Tue, 11 May 2021 12:03:52 +0200 Subject: [PATCH] [NTOS:MM] Relax requirements with regards to PFN lock when adding & removing entries in Working Sets Once a page is used, holding the WS lock is enough until you want to free it. --- ntoskrnl/mm/ARM3/miarm.h | 9 ++++ ntoskrnl/mm/ARM3/procsup.c | 6 +-- ntoskrnl/mm/ARM3/wslist.cpp | 89 ++++++++++++++++++++----------------- 3 files changed, 61 insertions(+), 43 deletions(-) diff --git a/ntoskrnl/mm/ARM3/miarm.h b/ntoskrnl/mm/ARM3/miarm.h index adb6af3fd91..730acdd8bf1 100644 --- a/ntoskrnl/mm/ARM3/miarm.h +++ b/ntoskrnl/mm/ARM3/miarm.h @@ -1052,6 +1052,15 @@ MM_ANY_WS_LOCK_HELD(IN PETHREAD Thread) (Thread->OwnsSessionWorkingSetShared)); } +FORCEINLINE +BOOLEAN +MM_ANY_WS_LOCK_HELD_EXCLUSIVE(_In_ PETHREAD Thread) +{ + return ((Thread->OwnsProcessWorkingSetExclusive) || + (Thread->OwnsSystemWorkingSetExclusive) || + (Thread->OwnsSessionWorkingSetExclusive)); +} + // // Checks if the process owns the working set lock // diff --git a/ntoskrnl/mm/ARM3/procsup.c b/ntoskrnl/mm/ARM3/procsup.c index aa9133b1929..5f24a8a0b95 100644 --- a/ntoskrnl/mm/ARM3/procsup.c +++ b/ntoskrnl/mm/ARM3/procsup.c @@ -993,6 +993,9 @@ MmInitializeProcessAddressSpace(IN PEPROCESS Process, PageFrameNumber = PFN_FROM_PTE(PointerPte); MiInitializePfn(PageFrameNumber, PointerPte, TRUE); + /* All our pages are now active & valid. Release the lock. */ + MiReleasePfnLock(OldIrql); + /* This should be in hyper space, but not in the mapping range */ Process->Vm.VmWorkingSetList = MmWorkingSetList; ASSERT(((ULONG_PTR)MmWorkingSetList >= MI_MAPPING_RANGE_END) && ((ULONG_PTR)MmWorkingSetList <= HYPER_SPACE_END)); @@ -1016,9 +1019,6 @@ MmInitializeProcessAddressSpace(IN PEPROCESS Process, /* Sanity check */ ASSERT(Process->PhysicalVadRoot == NULL); - /* Release PFN lock */ - MiReleasePfnLock(OldIrql); - /* Release the process working set */ MiUnlockProcessWorkingSet(Process, PsGetCurrentThread()); #ifdef _M_AMD64 diff --git a/ntoskrnl/mm/ARM3/wslist.cpp b/ntoskrnl/mm/ARM3/wslist.cpp index 430e2c1a564..91cd87b354f 100644 --- a/ntoskrnl/mm/ARM3/wslist.cpp +++ b/ntoskrnl/mm/ARM3/wslist.cpp @@ -84,11 +84,15 @@ static void FreeWsleIndex(PMMWSL WsList, ULONG Index) ASSERT(MiPteToAddress(PointerPte) != WsList); PFN_NUMBER Page = PFN_FROM_PTE(PointerPte); - PMMPFN Pfn = MiGetPfnEntry(Page); - MI_SET_PFN_DELETED(Pfn); - MiDecrementShareCount(MiGetPfnEntry(Pfn->u4.PteFrame), Pfn->u4.PteFrame); - MiDecrementShareCount(Pfn, Page); + { + MiPfnLockGuard PfnLock; + + PMMPFN Pfn = MiGetPfnEntry(Page); + MI_SET_PFN_DELETED(Pfn); + MiDecrementShareCount(MiGetPfnEntry(Pfn->u4.PteFrame), Pfn->u4.PteFrame); + MiDecrementShareCount(Pfn, Page); + } PointerPte->u.Long = 0; @@ -172,8 +176,13 @@ static ULONG GetFreeWsleIndex(PMMWSL WsList) PMMPTE PointerPte = MiAddressToPte(&WsList->Wsle[WsList->LastInitializedWsle]); ASSERT(PointerPte->u.Hard.Valid == 0); MMPTE TempPte = GetPteTemplateForWsList(WsList); - TempPte.u.Hard.PageFrameNumber = MiRemoveAnyPage(GetNextPageColorForWsList(WsList)); - MiInitializePfnAndMakePteValid(TempPte.u.Hard.PageFrameNumber, PointerPte, TempPte); + { + MiPfnLockGuard PfnLock; + + TempPte.u.Hard.PageFrameNumber = MiRemoveAnyPage(GetNextPageColorForWsList(WsList)); + MiInitializePfnAndMakePteValid(TempPte.u.Hard.PageFrameNumber, PointerPte, TempPte); + } + WsList->LastInitializedWsle += PAGE_SIZE / sizeof(MMWSLE); } } @@ -187,8 +196,7 @@ VOID RemoveFromWsList(PMMWSL WsList, PVOID Address) { /* Make sure that we are holding the right locks. */ - ASSERT(MM_ANY_WS_LOCK_HELD(PsGetCurrentThread())); - MI_ASSERT_PFN_LOCK_HELD(); + ASSERT(MM_ANY_WS_LOCK_HELD_EXCLUSIVE(PsGetCurrentThread())); PMMPTE PointerPte = MiAddressToPte(Address); @@ -262,37 +270,37 @@ TrimWsList(PMMWSL WsList) /* Please put yourself aside and make place for the younger ones */ PFN_NUMBER Page = PFN_FROM_PTE(PointerPte); - KIRQL OldIrql = MiAcquirePfnLock(); - - PMMPFN Pfn = MiGetPfnEntry(Page); - - /* Not supported yet */ - ASSERT(Pfn->u3.e1.PrototypePte == 0); - ASSERT(!MI_IS_ROS_PFN(Pfn)); - - /* FIXME: Remove this hack when possible */ - if (Pfn->Wsle.u1.e1.LockedInMemory || (Pfn->Wsle.u1.e1.LockedInWs)) { - MiReleasePfnLock(OldIrql); - continue; + MiPfnLockGuard PfnLock; + + PMMPFN Pfn = MiGetPfnEntry(Page); + + /* Not supported yet */ + ASSERT(Pfn->u3.e1.PrototypePte == 0); + ASSERT(!MI_IS_ROS_PFN(Pfn)); + + /* FIXME: Remove this hack when possible */ + if (Pfn->Wsle.u1.e1.LockedInMemory || (Pfn->Wsle.u1.e1.LockedInWs)) + { + continue; + } + + /* We can remove it from the list. Save Protection first */ + ULONG Protection = Entry.u1.e1.Protection; + RemoveFromWsList(WsList, Entry.u1.VirtualAddress); + + /* Dirtify the page, if needed */ + if (PointerPte->u.Hard.Dirty) + Pfn->u3.e1.Modified = 1; + + /* Make this a transition PTE */ + MI_MAKE_TRANSITION_PTE(PointerPte, Page, Protection); + KeInvalidateTlbEntry(MiAddressToPte(PointerPte)); + + /* Drop the share count. This will take care of putting it in the standby or modified list. */ + MiDecrementShareCount(Pfn, Page); } - /* We can remove it from the list. Save Protection first */ - ULONG Protection = Entry.u1.e1.Protection; - RemoveFromWsList(WsList, Entry.u1.VirtualAddress); - - /* Dirtify the page, if needed */ - if (PointerPte->u.Hard.Dirty) - Pfn->u3.e1.Modified = 1; - - /* Make this a transition PTE */ - MI_MAKE_TRANSITION_PTE(PointerPte, Page, Protection); - KeInvalidateTlbEntry(MiAddressToPte(PointerPte)); - - /* Drop the share count. This will take care of putting it in the standby or modified list. */ - MiDecrementShareCount(Pfn, Page); - - MiReleasePfnLock(OldIrql); Ret++; } return Ret; @@ -302,6 +310,7 @@ TrimWsList(PMMWSL WsList) extern "C" { +_Use_decl_annotations_ VOID NTAPI MiInsertInWorkingSetList( @@ -311,9 +320,8 @@ MiInsertInWorkingSetList( { PMMWSL WsList = Vm->VmWorkingSetList; - /* Make sure that we are holding the right locks. */ - ASSERT(MM_ANY_WS_LOCK_HELD(PsGetCurrentThread())); - MI_ASSERT_PFN_LOCK_HELD(); + /* Make sure that we are holding the WS lock. */ + ASSERT(MM_ANY_WS_LOCK_HELD_EXCLUSIVE(PsGetCurrentThread())); PMMPTE PointerPte = MiAddressToPte(Address); @@ -345,6 +353,7 @@ MiInsertInWorkingSetList( Vm->PeakWorkingSetSize = Vm->WorkingSetSize; } +_Use_decl_annotations_ VOID NTAPI MiRemoveFromWorkingSetList( @@ -356,7 +365,7 @@ MiRemoveFromWorkingSetList( Vm->WorkingSetSize -= PAGE_SIZE; } -_Requires_exclusive_lock_held_(WorkingSet->WorkingSetMutex) +_Use_decl_annotations_ VOID NTAPI MiInitializeWorkingSetList(_Inout_ PMMSUPPORT WorkingSet)