From 69daff72d2607e514a4c8590c26c009da7f9d5b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Gardou?= Date: Sat, 1 Oct 2022 22:48:46 +0200 Subject: [PATCH] NTOS:CC Free some VACBs when we're under memory pressure --- ntoskrnl/cc/lazywrite.c | 10 ++++ ntoskrnl/cc/view.c | 88 ++++++++++++---------------------- ntoskrnl/include/internal/cc.h | 4 ++ 3 files changed, 44 insertions(+), 58 deletions(-) diff --git a/ntoskrnl/cc/lazywrite.c b/ntoskrnl/cc/lazywrite.c index 607a469d20d..87216bf3bef 100644 --- a/ntoskrnl/cc/lazywrite.c +++ b/ntoskrnl/cc/lazywrite.c @@ -130,6 +130,16 @@ CcWriteBehind(VOID) ++CcLazyWriteIos; DPRINT("Lazy writer done (%d)\n", Count); } + + /* Make sure we're not throttling writes after this */ + while (MmAvailablePages < MmThrottleTop) + { + /* Break if we can't even find one to free */ + if (!CcRosFreeOneUnusedVacb()) + { + break; + } + } } VOID diff --git a/ntoskrnl/cc/view.c b/ntoskrnl/cc/view.c index a40272f8f34..25d066abd03 100644 --- a/ntoskrnl/cc/view.c +++ b/ntoskrnl/cc/view.c @@ -595,34 +595,26 @@ CcRosUnmarkDirtyVacb ( } } -static BOOLEAN -CcRosFreeUnusedVacb ( - PULONG Count) +CcRosFreeOneUnusedVacb( + VOID) { - ULONG cFreed; - BOOLEAN Freed; KIRQL oldIrql; - PROS_VACB current; - LIST_ENTRY FreeList; PLIST_ENTRY current_entry; - - cFreed = 0; - Freed = FALSE; - InitializeListHead(&FreeList); + PROS_VACB to_free = NULL; oldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); /* Browse all the available VACB */ current_entry = VacbLruListHead.Flink; - while (current_entry != &VacbLruListHead) + while ((current_entry != &VacbLruListHead) && (to_free == NULL)) { ULONG Refs; + PROS_VACB current; current = CONTAINING_RECORD(current_entry, ROS_VACB, VacbLruListEntry); - current_entry = current_entry->Flink; KeAcquireSpinLockAtDpcLevel(¤t->SharedCacheMap->CacheMapLock); @@ -634,47 +626,32 @@ CcRosFreeUnusedVacb ( ASSERT(!current->MappedCount); ASSERT(Refs == 1); - /* Reset and move to free list */ + /* Reset it, this is the one we want to free */ RemoveEntryList(¤t->CacheMapVacbListEntry); + InitializeListHead(¤t->CacheMapVacbListEntry); RemoveEntryList(¤t->VacbLruListEntry); InitializeListHead(¤t->VacbLruListEntry); - InsertHeadList(&FreeList, ¤t->CacheMapVacbListEntry); + + to_free = current; } KeReleaseSpinLockFromDpcLevel(¤t->SharedCacheMap->CacheMapLock); + current_entry = current_entry->Flink; } KeReleaseQueuedSpinLock(LockQueueMasterLock, oldIrql); - /* And now, free any of the found VACB, that'll free memory! */ - while (!IsListEmpty(&FreeList)) + /* And now, free the VACB that we found, if any. */ + if (to_free == NULL) { - ULONG Refs; - - current_entry = RemoveHeadList(&FreeList); - current = CONTAINING_RECORD(current_entry, - ROS_VACB, - CacheMapVacbListEntry); - InitializeListHead(¤t->CacheMapVacbListEntry); - Refs = CcRosVacbDecRefCount(current); - ASSERT(Refs == 0); - ++cFreed; + return FALSE; } - /* If we freed at least one VACB, return success */ - if (cFreed != 0) - { - Freed = TRUE; - } + /* This must be its last ref */ + NT_VERIFY(CcRosVacbDecRefCount(to_free) == 0); - /* If caller asked for free count, return it */ - if (Count != NULL) - { - *Count = cFreed; - } - - return Freed; + return TRUE; } static @@ -690,7 +667,6 @@ CcRosCreateVacb ( NTSTATUS Status; KIRQL oldIrql; ULONG Refs; - BOOLEAN Retried; SIZE_T ViewSize = VACB_MAPPING_GRANULARITY; ASSERT(SharedCacheMap); @@ -711,28 +687,24 @@ CcRosCreateVacb ( CcRosVacbIncRefCount(current); - Retried = FALSE; -Retry: - /* Map VACB in system space */ - Status = MmMapViewInSystemSpaceEx(SharedCacheMap->Section, ¤t->BaseAddress, &ViewSize, ¤t->FileOffset, 0); - - if (!NT_SUCCESS(Status)) + while (TRUE) { - ULONG Freed; - /* If no space left, try to prune unused VACB - * to recover space to map our VACB - * If it succeed, retry to map, otherwise - * just fail. - */ - if (!Retried && CcRosFreeUnusedVacb(&Freed)) + /* Map VACB in system space */ + Status = MmMapViewInSystemSpaceEx(SharedCacheMap->Section, ¤t->BaseAddress, &ViewSize, ¤t->FileOffset, 0); + if (NT_SUCCESS(Status)) { - DPRINT("Prunned %d VACB, trying again\n", Freed); - Retried = TRUE; - goto Retry; + break; } - ExFreeToNPagedLookasideList(&VacbLookasideList, current); - return Status; + /* + * If no space left, try to prune one unused VACB to recover space to map our VACB. + * If it succeeds, retry to map, otherwise just fail. + */ + if (!CcRosFreeOneUnusedVacb()) + { + ExFreeToNPagedLookasideList(&VacbLookasideList, current); + return Status; + } } #if DBG diff --git a/ntoskrnl/include/internal/cc.h b/ntoskrnl/include/internal/cc.h index a56118a8558..90c315901d1 100644 --- a/ntoskrnl/include/internal/cc.h +++ b/ntoskrnl/include/internal/cc.h @@ -509,3 +509,7 @@ CcRosVacbDecRefCount( } #define CcRosVacbGetRefCount(vacb) InterlockedCompareExchange((PLONG)&(vacb)->ReferenceCount, 0, 0) #endif + +BOOLEAN +CcRosFreeOneUnusedVacb( + VOID);