Compare commits
6 Commits
main
...
LazyWriter
Author | SHA1 | Date | |
---|---|---|---|
11683762c3 | |||
3ae19eaf01 | |||
e75a2adeec | |||
1c173364a1 | |||
104a0212e0 | |||
1dec536c4d |
@ -13,8 +13,291 @@
|
||||
|
||||
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
|
||||
@ -981,44 +1264,7 @@ NTAPI CcLazyWriteScan()
|
||||
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(
|
||||
ULONG NormalThreadsToActivate,
|
||||
ULONG ExtraWriteBehindThreadsToActivate
|
||||
@ -1087,6 +1333,62 @@ VOID VECTORCALL CcReEngageWorkerThreads(
|
||||
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
|
||||
NTAPI
|
||||
CcWorkerThread(PVOID Parameter)
|
||||
|
Loading…
Reference in New Issue
Block a user