From: Pierre Schweitzer Date: Sun, 23 Dec 2018 13:43:17 +0000 (+0100) Subject: [NTOSKRNL] Implement write behind in Cc X-Git-Tag: 0.4.13-dev~914 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=7e97071c8b715b16303ac7fa00be652b17f552ec [NTOSKRNL] Implement write behind in Cc 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. --- diff --git a/ntoskrnl/cc/lazywrite.c b/ntoskrnl/cc/lazywrite.c index 8cb5adb2e71..275507e9042 100644 --- a/ntoskrnl/cc/lazywrite.c +++ b/ntoskrnl/cc/lazywrite.c @@ -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()) diff --git a/ntoskrnl/include/internal/cc.h b/ntoskrnl/include/internal/cc.h index 8a5fb738385..10bdb43a86a 100644 --- a/ntoskrnl/include/internal/cc.h +++ b/ntoskrnl/include/internal/cc.h @@ -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;