}
/* 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;
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);
- }
-
- /* If we have deferred writes, try them now! */
- if (!IsListEmpty(&CcDeferredWrites))
- {
- CcPostDeferredWrites();
+ /* 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 */
CcPostWorkQueue(WorkItem, &CcRegularWorkQueue);
}
- /* We're no longer active */
- OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
- LazyWriter.ScanActive = FALSE;
- KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
+ /* If we have deferred writes, try them now! */
+ if (!IsListEmpty(&CcDeferredWrites))
+ {
+ CcPostDeferredWrites();
+ /* Reschedule immediately a lazy writer run
+ * Keep us active to have short idle delay
+ */
+ CcScheduleLazyWriteScan(FALSE);
+ }
+ else
+ {
+ /* We're no longer active */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
+ LazyWriter.ScanActive = FALSE;
+ KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
+ }
}
VOID CcScheduleLazyWriteScan(
IN PVOID Parameter)
{
KIRQL OldIrql;
- BOOLEAN DropThrottle;
+ BOOLEAN DropThrottle, WritePerformed;
PWORK_QUEUE_ITEM Item;
+#if DBG
+ PIRP TopLevel;
+#endif
/* Get back our thread item */
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
+ * Save it to catch buggy drivers (or bugs!)
+ */
+ TopLevel = IoGetTopLevelIrp();
+ if (TopLevel != NULL)
+ {
+ DPRINT1("(%p) TopLevel IRP for this thread: %p\n", PsGetCurrentThread(), TopLevel);
+ }
+#endif
/* Loop till we have jobs */
while (TRUE)
CcPerformReadAhead(WorkItem->Parameters.Read.FileObject);
break;
- case LazyWrite:
+ case WriteBehind:
+ CcWriteBehind();
+ WritePerformed = TRUE;
+ break;
+
+ case LazyScan:
CcLazyWriteScan();
break;
/* One less worker */
--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())
+ {
+ DPRINT1("(%p) Mismatching TopLevel: %p, %p\n", PsGetCurrentThread(), TopLevel, IoGetTopLevelIrp());
+ }
+#endif
}
/*