https://git.reactos.org/?p=reactos.git;a=commitdiff;h=2b14056600bae80532f7ab9320fdc0853a55e30a

commit 2b14056600bae80532f7ab9320fdc0853a55e30a
Author:     Doug Lyons <[email protected]>
AuthorDate: Wed Sep 6 06:34:25 2023 -0500
Commit:     GitHub <[email protected]>
CommitDate: Wed Sep 6 13:34:25 2023 +0200

    [NTOS:CC][NTOS:MM] Add back CcRosTrimCache and add Delay for MM to work. 
(#5630)
    
    
    MM/CC Add back CcRosTrimCache as suggested by Thomas Faber which was 
removed in 0.4.15-dev-1717-g       d8cdb89fb03006595dc40ac23db5267b8d9d9c09
    and call it once in a while also during read-operations.
    
    fixes JIRA issue: CORE-17624 'Cannot copy files > RAMsize anymore using 
TotalCommander'
    
    
    1st testbot results on top of 0.4.15-dev-6526-g8d35887
    VBox: https://reactos.org/testman/compare.php?ids=89111,89120 (additional 
random reboot in winhttp:winhttp)
    KVM: https://reactos.org/testman/compare.php?ids=89110,89119
    We do assume that reboot to be unrelated.
    
    2nd testbot results on top of 0.4.15-dev-6526-g8d35887
    VBox: https://reactos.org/testman/compare.php?ids=89111,89232
    KVM: https://reactos.org/testman/compare.php?ids=89110,89233
---
 ntoskrnl/cc/view.c    | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++
 ntoskrnl/mm/balance.c |  23 ++++++++++
 2 files changed, 141 insertions(+)

diff --git a/ntoskrnl/cc/view.c b/ntoskrnl/cc/view.c
index 0e6917ea18a..efa4c8523d4 100644
--- a/ntoskrnl/cc/view.c
+++ b/ntoskrnl/cc/view.c
@@ -449,6 +449,124 @@ CcRosFlushDirtyPages (
     return STATUS_SUCCESS;
 }
 
+VOID
+CcRosTrimCache(
+    _In_ ULONG Target,
+    _Out_ PULONG NrFreed)
+/*
+ * FUNCTION: Try to free some memory from the file cache.
+ * ARGUMENTS:
+ *       Target - The number of pages to be freed.
+ *       NrFreed - Points to a variable where the number of pages
+ *                 actually freed is returned.
+ */
+{
+    PLIST_ENTRY current_entry;
+    PROS_VACB current;
+    ULONG PagesFreed;
+    KIRQL oldIrql;
+    LIST_ENTRY FreeList;
+    PFN_NUMBER Page;
+    ULONG i;
+    BOOLEAN FlushedPages = FALSE;
+
+    DPRINT("CcRosTrimCache(Target %lu)\n", Target);
+
+    InitializeListHead(&FreeList);
+
+    *NrFreed = 0;
+
+retry:
+    oldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
+
+    current_entry = VacbLruListHead.Flink;
+    while (current_entry != &VacbLruListHead)
+    {
+        ULONG Refs;
+
+        current = CONTAINING_RECORD(current_entry,
+                                    ROS_VACB,
+                                    VacbLruListEntry);
+        current_entry = current_entry->Flink;
+
+        KeAcquireSpinLockAtDpcLevel(&current->SharedCacheMap->CacheMapLock);
+
+        /* Reference the VACB */
+        CcRosVacbIncRefCount(current);
+
+        /* Check if it's mapped and not dirty */
+        if (InterlockedCompareExchange((PLONG)&current->MappedCount, 0, 0) > 0 
&& !current->Dirty)
+        {
+            /* Page out the VACB */
+            for (i = 0; i < VACB_MAPPING_GRANULARITY / PAGE_SIZE; i++)
+            {
+                Page = 
(PFN_NUMBER)(MmGetPhysicalAddress((PUCHAR)current->BaseAddress + (i * 
PAGE_SIZE)).QuadPart >> PAGE_SHIFT);
+
+                MmPageOutPhysicalAddress(Page);
+            }
+        }
+
+        /* Dereference the VACB */
+        Refs = CcRosVacbDecRefCount(current);
+
+        /* Check if we can free this entry now */
+        if (Refs < 2)
+        {
+            ASSERT(!current->Dirty);
+            ASSERT(!current->MappedCount);
+            ASSERT(Refs == 1);
+
+            RemoveEntryList(&current->CacheMapVacbListEntry);
+            RemoveEntryList(&current->VacbLruListEntry);
+            InitializeListHead(&current->VacbLruListEntry);
+            InsertHeadList(&FreeList, &current->CacheMapVacbListEntry);
+
+            /* Calculate how many pages we freed for Mm */
+            PagesFreed = min(VACB_MAPPING_GRANULARITY / PAGE_SIZE, Target);
+            Target -= PagesFreed;
+            (*NrFreed) += PagesFreed;
+        }
+
+        KeReleaseSpinLockFromDpcLevel(&current->SharedCacheMap->CacheMapLock);
+    }
+
+    KeReleaseQueuedSpinLock(LockQueueMasterLock, oldIrql);
+
+    /* Try flushing pages if we haven't met our target */
+    if ((Target > 0) && !FlushedPages)
+    {
+        /* Flush dirty pages to disk */
+        CcRosFlushDirtyPages(Target, &PagesFreed, FALSE, FALSE);
+        FlushedPages = TRUE;
+
+        /* We can only swap as many pages as we flushed */
+        if (PagesFreed < Target) Target = PagesFreed;
+
+        /* Check if we flushed anything */
+        if (PagesFreed != 0)
+        {
+            /* Try again after flushing dirty pages */
+            DPRINT("Flushed %lu dirty cache pages to disk\n", PagesFreed);
+            goto retry;
+        }
+    }
+
+    while (!IsListEmpty(&FreeList))
+    {
+        ULONG Refs;
+
+        current_entry = RemoveHeadList(&FreeList);
+        current = CONTAINING_RECORD(current_entry,
+                                    ROS_VACB,
+                                    CacheMapVacbListEntry);
+        InitializeListHead(&current->CacheMapVacbListEntry);
+        Refs = CcRosVacbDecRefCount(current);
+        ASSERT(Refs == 0);
+    }
+
+    DPRINT("Evicted %lu cache pages\n", (*NrFreed));
+}
+
 NTSTATUS
 CcRosReleaseVacb (
     PROS_SHARED_CACHE_MAP SharedCacheMap,
diff --git a/ntoskrnl/mm/balance.c b/ntoskrnl/mm/balance.c
index ab71d0f195b..f33189dc247 100644
--- a/ntoskrnl/mm/balance.c
+++ b/ntoskrnl/mm/balance.c
@@ -316,6 +316,15 @@ MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN 
CanWait,
                             PPFN_NUMBER AllocatedPage)
 {
     PFN_NUMBER Page;
+    static INT i = 0;
+    static LARGE_INTEGER TinyTime = {{-1L, -1L}};
+
+    /* Delay some requests for the Memory Manager to recover pages */
+    if (i++ >= 100)
+    {
+        KeDelayExecutionThread(KernelMode, FALSE, &TinyTime);
+        i = 0;
+    }
 
     /*
      * Actually allocate the page.
@@ -335,6 +344,10 @@ MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN 
CanWait,
     return(STATUS_SUCCESS);
 }
 
+VOID
+CcRosTrimCache(
+    _In_ ULONG Target,
+    _Out_ PULONG NrFreed);
 
 VOID NTAPI
 MiBalancerThread(PVOID Unused)
@@ -361,6 +374,8 @@ MiBalancerThread(PVOID Unused)
         if (Status == STATUS_WAIT_0 || Status == STATUS_WAIT_1)
         {
             ULONG InitialTarget = 0;
+            ULONG Target;
+            ULONG NrFreedPages;
 
             do
             {
@@ -372,6 +387,14 @@ MiBalancerThread(PVOID Unused)
                     InitialTarget = MiTrimMemoryConsumer(i, InitialTarget);
                 }
 
+                /* Trim cache */
+                Target = max(InitialTarget, abs(MiMinimumAvailablePages - 
MmAvailablePages));
+                if (Target)
+                {
+                    CcRosTrimCache(Target, &NrFreedPages);
+                    InitialTarget -= min(NrFreedPages, InitialTarget);
+                }
+
                 /* No pages left to swap! */
                 if (InitialTarget != 0 &&
                         InitialTarget == OldTarget)

Reply via email to