[NTOSKRNL]
authorCameron Gutman <aicommander@gmail.com>
Wed, 30 Nov 2011 17:10:43 +0000 (17:10 +0000)
committerCameron Gutman <aicommander@gmail.com>
Wed, 30 Nov 2011 17:10:43 +0000 (17:10 +0000)
- Optimize CcRosTrimCache by eliminating an extra loop of all segments
- Allow swapping of dirty segments by flushing them first

svn path=/trunk/; revision=54549

reactos/ntoskrnl/cc/view.c

index e881188..b8ce087 100644 (file)
@@ -302,79 +302,80 @@ CcRosTrimCache(ULONG Target, ULONG Priority, PULONG NrFreed)
     ULONG PagesFreed;
     KIRQL oldIrql;
     LIST_ENTRY FreeList;
-    
+    PFN_NUMBER Page;
+    ULONG i;
+
     DPRINT("CcRosTrimCache(Target %d)\n", Target);
+
+    InitializeListHead(&FreeList);
+
+    /* Flush dirty pages to disk */
+    CcRosFlushDirtyPages(Target, NrFreed);
     
+    if ((*NrFreed) != 0) DPRINT1("Flushed %d dirty cache pages to disk\n", (*NrFreed));
+
     *NrFreed = 0;
-    
-    InitializeListHead(&FreeList);
 
     KeAcquireGuardedMutex(&ViewLock);
+
     current_entry = CacheSegmentLRUListHead.Flink;
-    while (current_entry != &CacheSegmentLRUListHead && Target > 0)
+    while (current_entry != &CacheSegmentLRUListHead)
     {
         current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
                                     CacheSegmentLRUListEntry);
         current_entry = current_entry->Flink;
-        
+
         KeAcquireSpinLock(&current->Bcb->BcbLock, &oldIrql);
 
-        if (current->MappedCount > 0 && !current->Dirty && !current->PageOut)
+        /* Reference the cache segment */
+        CcRosCacheSegmentIncRefCount(current);
+
+        /* Check if it's mapped and not dirty */
+        if (current->MappedCount > 0 && !current->Dirty)
         {
-            ULONG i;
-            
-            CcRosCacheSegmentIncRefCount(current);
-            current->PageOut = TRUE;
+            /* We have to break these locks because Cc sucks */
             KeReleaseSpinLock(&current->Bcb->BcbLock, oldIrql);
             KeReleaseGuardedMutex(&ViewLock);
+
+            /* Page out the segment */
             for (i = 0; i < current->Bcb->CacheSegmentSize / PAGE_SIZE; i++)
             {
-                PFN_NUMBER Page;
-                Page = (PFN_NUMBER)(MmGetPhysicalAddress((char*)current->BaseAddress + i * PAGE_SIZE).QuadPart >> PAGE_SHIFT);
+                Page = (PFN_NUMBER)(MmGetPhysicalAddress((PUCHAR)current->BaseAddress + (i * PAGE_SIZE)).QuadPart >> PAGE_SHIFT);
+
                 MmPageOutPhysicalAddress(Page);
             }
+
+            /* Reacquire the locks */
             KeAcquireGuardedMutex(&ViewLock);
             KeAcquireSpinLock(&current->Bcb->BcbLock, &oldIrql);
-            CcRosCacheSegmentDecRefCount(current);
-        }
-        
-        if (current->ReferenceCount == 0)
-        {
-            PagesPerSegment = current->Bcb->CacheSegmentSize / PAGE_SIZE;
-            //            PagesFreed = PagesPerSegment;
-            PagesFreed = min(PagesPerSegment, Target);
-            Target -= PagesFreed;
-            (*NrFreed) += PagesFreed;            
         }
-        
-        KeReleaseSpinLock(&current->Bcb->BcbLock, oldIrql);
-    }
-    
-    current_entry = CacheSegmentLRUListHead.Flink;
-    while (current_entry != &CacheSegmentLRUListHead)
-    {
-        current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
-                                    CacheSegmentLRUListEntry);
-        current->PageOut = FALSE;
-        current_entry = current_entry->Flink;
-        
-        KeAcquireSpinLock(&current->Bcb->BcbLock, &oldIrql);
+
+        /* Dereference the cache segment */
+        CcRosCacheSegmentDecRefCount(current);
+
+        /* Check if we can free this entry now */
         if (current->ReferenceCount == 0)
         {
+            ASSERT(!current->Dirty);
+            ASSERT(!current->MappedCount);
+
             RemoveEntryList(&current->BcbSegmentListEntry);
-            KeReleaseSpinLock(&current->Bcb->BcbLock, oldIrql);
             RemoveEntryList(&current->CacheSegmentListEntry);
             RemoveEntryList(&current->CacheSegmentLRUListEntry);
             InsertHeadList(&FreeList, &current->BcbSegmentListEntry);
+
+            /* Calculate how many pages we freed for Mm */
+            PagesPerSegment = current->Bcb->CacheSegmentSize / PAGE_SIZE;
+            PagesFreed = min(PagesPerSegment, Target);
+            Target -= PagesFreed;
+            (*NrFreed) += PagesFreed;
         }
-        else
-        {
-            KeReleaseSpinLock(&current->Bcb->BcbLock, oldIrql);
-        }
+
+        KeReleaseSpinLock(&current->Bcb->BcbLock, oldIrql);
     }
-    
+
     KeReleaseGuardedMutex(&ViewLock);
-    
+
     while (!IsListEmpty(&FreeList))
     {
         current_entry = RemoveHeadList(&FreeList);
@@ -382,7 +383,9 @@ CcRosTrimCache(ULONG Target, ULONG Priority, PULONG NrFreed)
                                     BcbSegmentListEntry);
         CcRosInternalFreeCacheSegment(current);
     }
-    
+
+    DPRINT1("Evicted %d cache pages\n", (*NrFreed));
+
     return(STATUS_SUCCESS);
 }