https://git.reactos.org/?p=reactos.git;a=commitdiff;h=69daff72d2607e514a4c8…
commit 69daff72d2607e514a4c8590c26c009da7f9d5b1
Author: Jérôme Gardou <jerome.gardou(a)reactos.org>
AuthorDate: Sat Oct 1 22:48:46 2022 +0200
Commit: Timo Kreuzer <timo.kreuzer(a)reactos.org>
CommitDate: Sat Jul 29 14:00:44 2023 +0300
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;
- }
-
- /* If we freed at least one VACB, return success */
- if (cFreed != 0)
- {
- Freed = TRUE;
+ return FALSE;
}
- /* If caller asked for free count, return it */
- if (Count != NULL)
- {
- *Count = cFreed;
- }
+ /* This must be its last ref */
+ NT_VERIFY(CcRosVacbDecRefCount(to_free) == 0);
- 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);