[NTOSKRNL] Implement write behind in Cc
authorPierre Schweitzer <pierre@reactos.org>
Sun, 23 Dec 2018 13:43:17 +0000 (14:43 +0100)
committerPierre Schweitzer <pierre@reactos.org>
Sun, 23 Dec 2018 13:45:38 +0000 (14:45 +0100)
For now, this is just a split between scan and flush that
were both done during lazy scan previously.
Lazy scan shouldn't perform any write operation, but only
queue a write behind operation.

Our implementation is far from the original, as it seems
our lazy scan should queue a write behind operation per
shared cache map. Right now, we only perform global
operation.

ntoskrnl/cc/lazywrite.c
ntoskrnl/include/internal/cc.h

index 8cb5adb..275507e 100644 (file)
@@ -109,15 +109,33 @@ CcScanDpc(
     }
 
     /* And post it, it will be for lazy write */
-    WorkItem->Function = LazyWrite;
+    WorkItem->Function = LazyScan;
     CcPostWorkQueue(WorkItem, &CcRegularWorkQueue);
 }
 
+VOID
+CcWriteBehind(VOID)
+{
+    ULONG Target, Count;
+
+    Target = CcTotalDirtyPages / 8;
+    if (Target != 0)
+    {
+        /* Flush! */
+        DPRINT("Lazy writer starting (%d)\n", Target);
+        CcRosFlushDirtyPages(Target, &Count, FALSE, TRUE);
+
+        /* And update stats */
+        CcLazyWritePages += Count;
+        ++CcLazyWriteIos;
+        DPRINT("Lazy writer done (%d)\n", Count);
+    }
+}
+
 VOID
 CcLazyWriteScan(VOID)
 {
     ULONG Target;
-    ULONG Count;
     KIRQL OldIrql;
     PLIST_ENTRY ListEntry;
     LIST_ENTRY ToPost;
@@ -142,14 +160,15 @@ CcLazyWriteScan(VOID)
     Target = CcTotalDirtyPages / 8;
     if (Target != 0)
     {
-        /* Flush! */
-        DPRINT("Lazy writer starting (%d)\n", Target);
-        CcRosFlushDirtyPages(Target, &Count, FALSE, TRUE);
+        /* There is stuff to flush, schedule a write-behind operation */
 
-        /* And update stats */
-        CcLazyWritePages += Count;
-        ++CcLazyWriteIos;
-        DPRINT("Lazy writer done (%d)\n", Count);
+        /* Allocate a work item */
+        WorkItem = ExAllocateFromNPagedLookasideList(&CcTwilightLookasideList);
+        if (WorkItem != NULL)
+        {
+            WorkItem->Function = WriteBehind;
+            CcPostWorkQueue(WorkItem, &CcRegularWorkQueue);
+        }
     }
 
     /* Post items that were due for end of run */
@@ -208,7 +227,7 @@ CcWorkerThread(
     IN PVOID Parameter)
 {
     KIRQL OldIrql;
-    BOOLEAN DropThrottle;
+    BOOLEAN DropThrottle, WritePerformed;
     PWORK_QUEUE_ITEM Item;
 #if DBG
     PIRP TopLevel;
@@ -218,6 +237,8 @@ CcWorkerThread(
     Item = Parameter;
     /* And by default, don't touch throttle */
     DropThrottle = FALSE;
+    /* No write performed */
+    WritePerformed =  FALSE;
 
 #if DBG
     /* Top level IRP should be clean when started
@@ -285,7 +306,12 @@ CcWorkerThread(
                 CcPerformReadAhead(WorkItem->Parameters.Read.FileObject);
                 break;
 
-            case LazyWrite:
+            case WriteBehind:
+                CcWriteBehind();
+                WritePerformed = TRUE;
+                break;
+
+            case LazyScan:
                 CcLazyWriteScan();
                 break;
 
@@ -309,6 +335,19 @@ CcWorkerThread(
     --CcNumberActiveWorkerThreads;
     KeReleaseQueuedSpinLock(LockQueueWorkQueueLock, OldIrql);
 
+    /* If there are pending write openations and we have at least 20 dirty pages */
+    if (!IsListEmpty(&CcDeferredWrites) && CcTotalDirtyPages >= 20)
+    {
+        /* And if we performed a write operation previously, then
+         * stress the system a bit and reschedule a scan to find
+         * stuff to write
+         */
+        if (WritePerformed)
+        {
+            CcLazyWriteScan();
+        }
+    }
+
 #if DBG
     /* Top level shouldn't have changed */
     if (TopLevel != IoGetTopLevelIrp())
index 8a5fb73..10bdb43 100644 (file)
@@ -278,7 +278,7 @@ typedef enum _WORK_QUEUE_FUNCTIONS
 {
     ReadAhead = 1,
     WriteBehind = 2,
-    LazyWrite = 3,
+    LazyScan = 3,
     SetDone = 4,
 } WORK_QUEUE_FUNCTIONS, *PWORK_QUEUE_FUNCTIONS;