[NTOSKRNL] Properly implement lazy writer activity watching.
authorPierre Schweitzer <pierre@reactos.org>
Wed, 7 Feb 2018 17:56:13 +0000 (18:56 +0100)
committerPierre Schweitzer <pierre@reactos.org>
Wed, 7 Feb 2018 20:37:17 +0000 (21:37 +0100)
We get rid of the old iLazyWriterNotify event in favor of work items
that contain an event that lazy writer will set once its done.
To implement this, we rely on the newly introduced CcPostTickWorkQueue work queue
that will contain work items that are to be queued once lazy writer is done.

Move the CcWaitForCurrentLazyWriterActivity() implementation to the
lazy writer file, and reimplemented it using the new support mechanisms

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

index 1718dde..aacf818 100644 (file)
@@ -52,6 +52,7 @@ CcInitializeCacheManager(VOID)
     /* Initialize lazy-writer lists */
     InitializeListHead(&CcIdleWorkerThreadList);
     InitializeListHead(&CcRegularWorkQueue);
+    InitializeListHead(&CcPostTickWorkQueue);
 
     /* Define lazy writer threshold and the amount of workers,
       * depending on the system type
@@ -106,9 +107,6 @@ CcInitializeCacheManager(VOID)
     /* Lookaside list for our work items */
     ExInitializeNPagedLookasideList(&CcTwilightLookasideList, NULL, NULL, 0, sizeof(WORK_QUEUE_ENTRY), 'KWcC', 0);
 
-    /* HACK: for lazy writer watching */
-    KeInitializeEvent(&iLazyWriterNotify, NotificationEvent, FALSE);
-
     return TRUE;
 }
 
index 194526c..ca39f7c 100644 (file)
@@ -35,8 +35,6 @@ ULONG CcFastReadWait;
 ULONG CcFastReadNoWait;
 ULONG CcFastReadResourceMiss;
 
-extern KEVENT iLazyWriterNotify;
-
 /* FUNCTIONS *****************************************************************/
 
 VOID
@@ -598,30 +596,6 @@ CcFastCopyWrite (
     ASSERT(Success == TRUE);
 }
 
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-CcWaitForCurrentLazyWriterActivity (
-    VOID)
-{
-    NTSTATUS Status;
-
-    /* Lazy writer is done when its event is set */
-    Status = KeWaitForSingleObject(&iLazyWriterNotify,
-                                   Executive,
-                                   KernelMode,
-                                   FALSE,
-                                   NULL);
-    if (!NT_SUCCESS(Status))
-    {
-        return Status;
-    }
-
-    return STATUS_SUCCESS;
-}
-
 /*
  * @implemented
  */
index bda7ca2..d38c693 100644 (file)
@@ -33,6 +33,7 @@ ULONG CcLazyWriteIos = 0;
  * - Lookaside list where to allocate work items
  * - Queue for regular work items
  * - Available worker threads
+ * - Queue for stuff to be queued after lazy writer is done
  * - Marker for throttling queues
  * - Number of ongoing workers
  * - Three seconds delay for lazy writer 
@@ -44,6 +45,7 @@ LAZY_WRITER LazyWriter;
 NPAGED_LOOKASIDE_LIST CcTwilightLookasideList;
 LIST_ENTRY CcRegularWorkQueue;
 LIST_ENTRY CcIdleWorkerThreadList;
+LIST_ENTRY CcPostTickWorkQueue;
 BOOLEAN CcQueueThrottle = FALSE;
 ULONG CcNumberActiveWorkerThreads = 0;
 LARGE_INTEGER CcFirstDelay = RTL_CONSTANT_LARGE_INTEGER((LONGLONG)-1*3000*1000*10);
@@ -51,10 +53,6 @@ LARGE_INTEGER CcIdleDelay = RTL_CONSTANT_LARGE_INTEGER((LONGLONG)-1*1000*1000*10
 LARGE_INTEGER CcNoDelay = RTL_CONSTANT_LARGE_INTEGER((LONGLONG)0);
 ULONG CcNumberWorkerThreads;
 
-/* Internal vars (ROS):
- */
-KEVENT iLazyWriterNotify;
-
 /* FUNCTIONS *****************************************************************/
 
 VOID
@@ -127,10 +125,25 @@ CcLazyWriteScan(VOID)
 {
     ULONG Target;
     ULONG Count;
+    KIRQL OldIrql;
     PLIST_ENTRY ListEntry;
+    LIST_ENTRY ToPost;
+    PWORK_QUEUE_ENTRY WorkItem;
 
-    /* We're not sleeping anymore */
-    KeClearEvent(&iLazyWriterNotify);
+    /* Do we have entries to queue after we're done? */
+    InitializeListHead(&ToPost);
+    OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
+    if (LazyWriter.OtherWork)
+    {
+        while (!IsListEmpty(&CcPostTickWorkQueue))
+        {
+            ListEntry = RemoveHeadList(&CcPostTickWorkQueue);
+            WorkItem = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ENTRY, WorkQueueLinks);
+            InsertTailList(&ToPost, &WorkItem->WorkQueueLinks);
+        }
+        LazyWriter.OtherWork = FALSE;
+    }
+    KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
 
     /* Our target is one-eighth of the dirty pages */
     Target = CcTotalDirtyPages / 8;
@@ -146,9 +159,6 @@ CcLazyWriteScan(VOID)
         DPRINT1("Lazy writer done (%d)\n", Count);
     }
 
-    /* Inform people waiting on us that we're done */
-    KeSetEvent(&iLazyWriterNotify, IO_DISK_INCREMENT, FALSE);
-
     /* Likely not optimal, but let's handle one deferred write now! */
     ListEntry = ExInterlockedRemoveHeadList(&CcDeferredWrites, &CcDeferredWriteSpinLock);
     if (ListEntry != NULL)
@@ -178,6 +188,13 @@ CcLazyWriteScan(VOID)
         }
     }
 
+    while (!IsListEmpty(&ToPost))
+    {
+        ListEntry = RemoveHeadList(&ToPost);
+        WorkItem = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ENTRY, WorkQueueLinks);
+        CcPostWorkQueue(WorkItem, &CcRegularWorkQueue);
+    }
+
     /* We're no longer active */
     LazyWriter.ScanActive = FALSE;
 }
@@ -281,3 +298,47 @@ CcWorkerThread(
     --CcNumberActiveWorkerThreads;
     KeReleaseQueuedSpinLock(LockQueueWorkQueueLock, OldIrql);
 }
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+CcWaitForCurrentLazyWriterActivity (
+    VOID)
+{
+    KIRQL OldIrql;
+    KEVENT WaitEvent;
+    PWORK_QUEUE_ENTRY WorkItem;
+
+    /* Allocate a work item */
+    WorkItem = ExAllocateFromNPagedLookasideList(&CcTwilightLookasideList);
+    if (WorkItem == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* We want lazy writer to set our event */
+    WorkItem->Function = SetDone;
+    KeInitializeEvent(&WaitEvent, NotificationEvent, FALSE);
+    WorkItem->Parameters.Event.Event = &WaitEvent;
+
+    /* Use the post tick queue */
+    OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
+    InsertTailList(&CcPostTickWorkQueue, &WorkItem->WorkQueueLinks);
+
+    /* Inform the lazy writer it will have to handle the post tick queue */
+    LazyWriter.OtherWork = TRUE;
+    /* And if it's not running, queue a lazy writer run
+     * And start it NOW, we want the response now
+     */
+    if (!LazyWriter.ScanActive)
+    {
+        CcScheduleLazyWriteScan(TRUE);
+    }
+
+    KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
+
+    /* And now, wait until lazy writer replies */
+    return KeWaitForSingleObject(&WaitEvent, Executive, KernelMode, FALSE, NULL);
+}
index 18d34ef..820cf7a 100644 (file)
@@ -48,8 +48,8 @@ extern KSPIN_LOCK CcDeferredWriteSpinLock;
 extern ULONG CcNumberWorkerThreads;
 extern LIST_ENTRY CcIdleWorkerThreadList;
 extern LIST_ENTRY CcRegularWorkQueue;
+extern LIST_ENTRY CcPostTickWorkQueue;
 extern NPAGED_LOOKASIDE_LIST CcTwilightLookasideList;
-extern KEVENT iLazyWriterNotify;
 
 typedef struct _PF_SCENARIO_ID
 {