Compare commits
6 Commits
main
...
LazyWriter
Author | SHA1 | Date | |
---|---|---|---|
11683762c3 | |||
3ae19eaf01 | |||
e75a2adeec | |||
1c173364a1 | |||
104a0212e0 | |||
1dec536c4d |
@ -13,8 +13,291 @@
|
|||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
|
|
||||||
/*Internal Function*/
|
/* Move Typedef Later to cctypes.hpp */
|
||||||
|
typedef struct _WRITE_BEHIND_THROUGHPUT
|
||||||
|
{
|
||||||
|
ULONG PagesYetToWrite;
|
||||||
|
ULONG Throughput;
|
||||||
|
} WRITE_BEHIND_THROUGHPUT, *PWRITE_BEHIND_THROUGHPUT;
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
CcOkToAddWriteBehindThread(VOID)
|
||||||
|
{
|
||||||
|
ULONG ActiveExtraWriteBehindThreads = {0};
|
||||||
|
PWRITE_BEHIND_THROUGHPUT ThroughputStats = nullptr;
|
||||||
|
ULONG PagesYetToWrite = {0};
|
||||||
|
ULONG Throughput = {0};
|
||||||
|
ULONG PreviousThroughput = {0};
|
||||||
|
LONG ThroughputTrend = {0};
|
||||||
|
BOOLEAN Result = false;
|
||||||
|
|
||||||
|
ActiveExtraWriteBehindThreads = CcActiveExtraWriteBehindThreads;
|
||||||
|
ThroughputStats = CcThroughputStats;
|
||||||
|
PagesYetToWrite = CcPagesYetToWrite;
|
||||||
|
|
||||||
|
Throughput = ThroughputStats[ActiveExtraWriteBehindThreads].PagesYetToWrite;
|
||||||
|
PreviousThroughput = 0;
|
||||||
|
|
||||||
|
if (Throughput >= PagesYetToWrite)
|
||||||
|
{
|
||||||
|
Throughput -= PagesYetToWrite;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Throughput = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThroughputStats[ActiveExtraWriteBehindThreads].PagesYetToWrite = PagesYetToWrite;
|
||||||
|
Result = true;
|
||||||
|
|
||||||
|
if (ActiveExtraWriteBehindThreads > 0)
|
||||||
|
{
|
||||||
|
PreviousThroughput = ThroughputStats[ActiveExtraWriteBehindThreads - 1].Throughput;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThroughputStats[ActiveExtraWriteBehindThreads].Throughput = Throughput;
|
||||||
|
|
||||||
|
if (Throughput > 0)
|
||||||
|
{
|
||||||
|
ThroughputTrend = CcThroughputTrend;
|
||||||
|
|
||||||
|
if (Throughput < PreviousThroughput)
|
||||||
|
{
|
||||||
|
if (ThroughputTrend > 0)
|
||||||
|
ThroughputTrend = 0;
|
||||||
|
ThroughputTrend--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ThroughputTrend < 0)
|
||||||
|
ThroughputTrend = 0;
|
||||||
|
ThroughputTrend++;
|
||||||
|
}
|
||||||
|
|
||||||
|
CcThroughputTrend = ThroughputTrend;
|
||||||
|
|
||||||
|
if (ThroughputTrend == 3)
|
||||||
|
{
|
||||||
|
CcThroughputTrend = 0;
|
||||||
|
Result = true;
|
||||||
|
|
||||||
|
if (ActiveExtraWriteBehindThreads < CcMaxExtraWriteBehindThreads)
|
||||||
|
{
|
||||||
|
ThroughputStats[ActiveExtraWriteBehindThreads + 1].Throughput = 0;
|
||||||
|
ThroughputStats[ActiveExtraWriteBehindThreads + 1].PagesYetToWrite = PagesYetToWrite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ThroughputTrend == -3)
|
||||||
|
{
|
||||||
|
CcThroughputTrend = 0;
|
||||||
|
Result = true;
|
||||||
|
|
||||||
|
if (ActiveExtraWriteBehindThreads > 0)
|
||||||
|
{
|
||||||
|
ThroughputStats[ActiveExtraWriteBehindThreads - 1].Throughput = 0;
|
||||||
|
ThroughputStats[ActiveExtraWriteBehindThreads - 1].PagesYetToWrite = PagesYetToWrite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CcSetLazyWriteScanQueued(
|
||||||
|
IN ULONG FlushReason,
|
||||||
|
IN BOOLEAN QueuedState)
|
||||||
|
{
|
||||||
|
switch (FlushReason)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
LazyWriter.PendingLowMemoryScan = QueuedState;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
LazyWriter.PendingPowerScan = QueuedState;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
LazyWriter.PendingPeriodicScan = QueuedState;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 8:
|
||||||
|
LazyWriter.PendingTeardownScan = QueuedState;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 16:
|
||||||
|
LazyWriter.PendingCoalescingFlushScan = QueuedState;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
VECTORCALL
|
||||||
|
CcIsLazyWriteScanQueued(
|
||||||
|
_In_ ULONG ReasonForFlush
|
||||||
|
)
|
||||||
|
{
|
||||||
|
switch (ReasonForFlush)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 16:
|
||||||
|
if (LazyWriter.PendingLowMemoryScan ||
|
||||||
|
LazyWriter.PendingPowerScan ||
|
||||||
|
LazyWriter.PendingCoalescingFlushScan)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
if (LazyWriter.PendingPeriodicScan ||
|
||||||
|
LazyWriter.PendingTeardownScan)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case 8:
|
||||||
|
return (BOOLEAN)LazyWriter.PendingTeardownScan;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CcQueueLazyWriteScanThread(
|
||||||
|
_In_ PVOID NULL_PARAM
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(NULL_PARAM);
|
||||||
|
|
||||||
|
ULONG Reason = 0;
|
||||||
|
BOOLEAN NeedAdjustment;
|
||||||
|
NTSTATUS Status;
|
||||||
|
KIRQL OldIrql;
|
||||||
|
PWORK_QUEUE_ENTRY WorkQueueEntry;
|
||||||
|
PVOID WaitObjects[5];
|
||||||
|
|
||||||
|
WaitObjects[0] = &CcLowMemoryEvent;
|
||||||
|
WaitObjects[1] = &CcPowerEvent;
|
||||||
|
WaitObjects[2] = &CcPeriodicEvent;
|
||||||
|
WaitObjects[3] = &CcWaitingForTeardownEvent;
|
||||||
|
WaitObjects[4] = &CcCoalescingFlushEvent;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
NeedAdjustment = false;
|
||||||
|
|
||||||
|
Status = KeWaitForMultipleObjects(
|
||||||
|
5,
|
||||||
|
WaitObjects,
|
||||||
|
WaitAny,
|
||||||
|
WrFreePage,
|
||||||
|
KernelMode,
|
||||||
|
false,
|
||||||
|
NULL,
|
||||||
|
WaitBlockArray);
|
||||||
|
|
||||||
|
switch (Status)
|
||||||
|
{
|
||||||
|
case STATUS_WAIT_0:
|
||||||
|
Reason = 1;
|
||||||
|
NeedAdjustment = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATUS_WAIT_1:
|
||||||
|
Reason = 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATUS_WAIT_2:
|
||||||
|
Reason = 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATUS_WAIT_3:
|
||||||
|
Reason = 8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATUS_WAIT_4:
|
||||||
|
Reason = 16;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CcNumberOfExternalCaches && !IsListEmpty(&CcExternalCacheList))
|
||||||
|
{
|
||||||
|
CcNotifyExternalCaches(Reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
CcAdjustWriteBehindThreadPoolIfNeeded(NeedAdjustment);
|
||||||
|
|
||||||
|
OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
|
||||||
|
|
||||||
|
if (CcIsLazyWriteScanQueued(Reason))
|
||||||
|
{
|
||||||
|
KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CcSetLazyWriteScanQueued(Reason, true);
|
||||||
|
KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(CcAllocateWorkQueueEntry(&WorkQueueEntry)))
|
||||||
|
{
|
||||||
|
KSPIN_LOCK_QUEUE_NUMBER queueNumber = LockQueueMasterLock;
|
||||||
|
SpinLockGuard guard(queueNumber);
|
||||||
|
LazyWriter.ScanActive = false;
|
||||||
|
CcSetLazyWriteScanQueued(Reason, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WorkQueueEntry->Function = 3;
|
||||||
|
WorkQueueEntry->Parameters.Notification.Reason = Reason;
|
||||||
|
|
||||||
|
CcPostWorkQueue(
|
||||||
|
WorkQueueEntry,
|
||||||
|
(Reason != 8) ? &CcRegularWorkQueue : &CcFastTeardownWorkQueue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CcRescheduleLazyWriteScan( IN PLARGE_INTEGER NextScanDelay)
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(NextScanDelay);
|
||||||
|
LARGE_INTEGER Delay = {0};
|
||||||
|
|
||||||
|
if (LazyWriter.ScanActive)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (NextScanDelay && NextScanDelay->QuadPart != 0x7FFFFFFFFFFFFFFF && NextScanDelay->QuadPart != 0)
|
||||||
|
{
|
||||||
|
Delay.QuadPart = NextScanDelay->QuadPart * KeMaximumIncrement;
|
||||||
|
if (Delay.QuadPart > 160000000)
|
||||||
|
Delay.QuadPart = 160000000;
|
||||||
|
if(Delay.QuadPart < 10000000 )
|
||||||
|
Delay = CcIdleDelay;
|
||||||
|
}
|
||||||
|
KeSetCoalescableTimer(&LazyWriter.ScanTimer,CcIdleDelay,0,1000,&LazyWriter.ScanDpc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CcScheduleLazyWriteScan(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
@ -981,44 +1264,7 @@ NTAPI CcLazyWriteScan()
|
|||||||
CcScheduleLazyWriteScan(FALSE);
|
CcScheduleLazyWriteScan(FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NTSTATUS CcWaitForCurrentLazyWriterActivity()
|
|
||||||
{
|
|
||||||
NTSTATUS result;
|
|
||||||
PWORK_QUEUE_ENTRY WorkQueueEntry = nullptr;
|
|
||||||
KEVENT Event = {0};
|
|
||||||
KIRQL irql = {0};
|
|
||||||
|
|
||||||
result = CcAllocateWorkQueueEntry(&WorkQueueEntry);
|
|
||||||
if (NT_SUCCESS(result))
|
|
||||||
{
|
|
||||||
WorkQueueEntry->Function = SetDone;
|
|
||||||
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
||||||
WorkQueueEntry->Parameters.Notification.Reason = (ULONG_PTR)&Event;
|
|
||||||
|
|
||||||
if ((PerfGlobalGroupMask.Masks[4] & 0x20000) != 0)
|
|
||||||
CcPerfLogWorkItemEnqueue(&CcPostTickWorkQueue, WorkQueueEntry, 0, 0);
|
|
||||||
|
|
||||||
irql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
|
|
||||||
|
|
||||||
WorkQueueEntry->WorkQueueLinks.Flink = &CcPostTickWorkQueue;
|
|
||||||
WorkQueueEntry->WorkQueueLinks.Blink = CcPostTickWorkQueue.Blink;
|
|
||||||
CcPostTickWorkQueue.Blink->Flink = &WorkQueueEntry->WorkQueueLinks;
|
|
||||||
CcPostTickWorkQueue.Blink = &WorkQueueEntry->WorkQueueLinks;
|
|
||||||
|
|
||||||
LazyWriter.OtherWork = 1;
|
|
||||||
_InterlockedIncrement(&CcPostTickWorkItemCount);
|
|
||||||
|
|
||||||
CcScheduleLazyWriteScan(1, 1);
|
|
||||||
|
|
||||||
KeReleaseQueuedSpinLock(LockQueueMasterLock, irql);
|
|
||||||
|
|
||||||
result = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|
||||||
|
|
||||||
_InterlockedDecrement(&CcPostTickWorkItemCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
VOID VECTORCALL CcReEngageWorkerThreads(
|
VOID VECTORCALL CcReEngageWorkerThreads(
|
||||||
ULONG NormalThreadsToActivate,
|
ULONG NormalThreadsToActivate,
|
||||||
ULONG ExtraWriteBehindThreadsToActivate
|
ULONG ExtraWriteBehindThreadsToActivate
|
||||||
@ -1087,6 +1333,62 @@ VOID VECTORCALL CcReEngageWorkerThreads(
|
|||||||
ExQueueWorkItem(currentExtraThreadEntry, CriticalWorkQueue);
|
ExQueueWorkItem(currentExtraThreadEntry, CriticalWorkQueue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CcAdjustWriteBehindThreadPool(
|
||||||
|
IN BOOLEAN IsThreadPriorityLow)
|
||||||
|
{
|
||||||
|
if (IsThreadPriorityLow)
|
||||||
|
{
|
||||||
|
CcMaxNumberOfWriteBehindThreads = 1;
|
||||||
|
if (CcAddExtraWriteBehindThreads)
|
||||||
|
{
|
||||||
|
CcAddExtraWriteBehindThreads = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CcMaxNumberOfWriteBehindThreads = (ULONG)-1;
|
||||||
|
if (!IsListEmpty(&CcRegularWorkQueue) && !CcQueueThrottle)
|
||||||
|
{
|
||||||
|
CcReEngageWorkerThreads(CcNumberofWorkerThreads, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
CcAdjustWriteBehindThreadPoolIfNeeded(
|
||||||
|
IN BOOLEAN NeedAdjustment)
|
||||||
|
{
|
||||||
|
BOOLEAN NeedBoost = false;
|
||||||
|
KSPIN_LOCK_QUEUE_NUMBER queueNumber = LockQueueMasterLock;
|
||||||
|
SpinLockGuard guard(queueNumber);
|
||||||
|
|
||||||
|
if (CcPostTickWorkItemCount != 0)
|
||||||
|
{
|
||||||
|
if (CcIsWriteBehindThreadpoolAtLowPriority())
|
||||||
|
{
|
||||||
|
CcAdjustWriteBehindThreadPool(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ auto DirtyPages = (CcTotalDirtyPages + CcPagesWrittenLastTime);
|
||||||
|
if (DirtyPages > 0x2000 || NeedAdjustment)
|
||||||
|
{
|
||||||
|
if (CcIsWriteBehindThreadpoolAtLowPriority())
|
||||||
|
{
|
||||||
|
CcAdjustWriteBehindThreadPool(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!CcExecutingWriteBehindWorkItems && IsListEmpty(&CcRegularWorkQueue))
|
||||||
|
{
|
||||||
|
CcAdjustWriteBehindThreadPool(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
CcWorkerThread(PVOID Parameter)
|
CcWorkerThread(PVOID Parameter)
|
||||||
|
Loading…
Reference in New Issue
Block a user