[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.
This commit is contained in:
Pierre Schweitzer 2018-12-23 14:43:17 +01:00
parent d5c74ae6fe
commit 7e97071c8b
No known key found for this signature in database
GPG key ID: 7545556C3D585B0B
2 changed files with 51 additions and 12 deletions

View 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())

View 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;