diff --git a/ntoskrnl/cc/cacheman.c b/ntoskrnl/cc/cacheman.c index 1718ddebca2..aacf818c8af 100644 --- a/ntoskrnl/cc/cacheman.c +++ b/ntoskrnl/cc/cacheman.c @@ -52,6 +52,7 @@ CcInitializeCacheManager(VOID) /* Initialize lazy-writer lists */ InitializeListHead(&CcIdleWorkerThreadList); InitializeListHead(&CcRegularWorkQueue); + InitializeListHead(&CcPostTickWorkQueue); /* Define lazy writer threshold and the amount of workers, * depending on the system type @@ -106,9 +107,6 @@ CcInitializeCacheManager(VOID) /* Lookaside list for our work items */ ExInitializeNPagedLookasideList(&CcTwilightLookasideList, NULL, NULL, 0, sizeof(WORK_QUEUE_ENTRY), 'KWcC', 0); - /* HACK: for lazy writer watching */ - KeInitializeEvent(&iLazyWriterNotify, NotificationEvent, FALSE); - return TRUE; } diff --git a/ntoskrnl/cc/copy.c b/ntoskrnl/cc/copy.c index 194526c559d..ca39f7cc180 100644 --- a/ntoskrnl/cc/copy.c +++ b/ntoskrnl/cc/copy.c @@ -35,8 +35,6 @@ ULONG CcFastReadWait; ULONG CcFastReadNoWait; ULONG CcFastReadResourceMiss; -extern KEVENT iLazyWriterNotify; - /* FUNCTIONS *****************************************************************/ VOID @@ -598,30 +596,6 @@ CcFastCopyWrite ( ASSERT(Success == TRUE); } -/* - * @implemented - */ -NTSTATUS -NTAPI -CcWaitForCurrentLazyWriterActivity ( - VOID) -{ - NTSTATUS Status; - - /* Lazy writer is done when its event is set */ - Status = KeWaitForSingleObject(&iLazyWriterNotify, - Executive, - KernelMode, - FALSE, - NULL); - if (!NT_SUCCESS(Status)) - { - return Status; - } - - return STATUS_SUCCESS; -} - /* * @implemented */ diff --git a/ntoskrnl/cc/lazywrite.c b/ntoskrnl/cc/lazywrite.c index bda7ca27de3..d38c6938b57 100644 --- a/ntoskrnl/cc/lazywrite.c +++ b/ntoskrnl/cc/lazywrite.c @@ -33,6 +33,7 @@ ULONG CcLazyWriteIos = 0; * - Lookaside list where to allocate work items * - Queue for regular work items * - Available worker threads + * - Queue for stuff to be queued after lazy writer is done * - Marker for throttling queues * - Number of ongoing workers * - Three seconds delay for lazy writer @@ -44,6 +45,7 @@ LAZY_WRITER LazyWriter; NPAGED_LOOKASIDE_LIST CcTwilightLookasideList; LIST_ENTRY CcRegularWorkQueue; LIST_ENTRY CcIdleWorkerThreadList; +LIST_ENTRY CcPostTickWorkQueue; BOOLEAN CcQueueThrottle = FALSE; ULONG CcNumberActiveWorkerThreads = 0; LARGE_INTEGER CcFirstDelay = RTL_CONSTANT_LARGE_INTEGER((LONGLONG)-1*3000*1000*10); @@ -51,10 +53,6 @@ LARGE_INTEGER CcIdleDelay = RTL_CONSTANT_LARGE_INTEGER((LONGLONG)-1*1000*1000*10 LARGE_INTEGER CcNoDelay = RTL_CONSTANT_LARGE_INTEGER((LONGLONG)0); ULONG CcNumberWorkerThreads; -/* Internal vars (ROS): - */ -KEVENT iLazyWriterNotify; - /* FUNCTIONS *****************************************************************/ VOID @@ -127,10 +125,25 @@ CcLazyWriteScan(VOID) { ULONG Target; ULONG Count; + KIRQL OldIrql; PLIST_ENTRY ListEntry; + LIST_ENTRY ToPost; + PWORK_QUEUE_ENTRY WorkItem; - /* We're not sleeping anymore */ - KeClearEvent(&iLazyWriterNotify); + /* Do we have entries to queue after we're done? */ + InitializeListHead(&ToPost); + OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); + if (LazyWriter.OtherWork) + { + while (!IsListEmpty(&CcPostTickWorkQueue)) + { + ListEntry = RemoveHeadList(&CcPostTickWorkQueue); + WorkItem = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ENTRY, WorkQueueLinks); + InsertTailList(&ToPost, &WorkItem->WorkQueueLinks); + } + LazyWriter.OtherWork = FALSE; + } + KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); /* Our target is one-eighth of the dirty pages */ Target = CcTotalDirtyPages / 8; @@ -146,9 +159,6 @@ CcLazyWriteScan(VOID) DPRINT1("Lazy writer done (%d)\n", Count); } - /* Inform people waiting on us that we're done */ - KeSetEvent(&iLazyWriterNotify, IO_DISK_INCREMENT, FALSE); - /* Likely not optimal, but let's handle one deferred write now! */ ListEntry = ExInterlockedRemoveHeadList(&CcDeferredWrites, &CcDeferredWriteSpinLock); if (ListEntry != NULL) @@ -178,6 +188,13 @@ CcLazyWriteScan(VOID) } } + while (!IsListEmpty(&ToPost)) + { + ListEntry = RemoveHeadList(&ToPost); + WorkItem = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ENTRY, WorkQueueLinks); + CcPostWorkQueue(WorkItem, &CcRegularWorkQueue); + } + /* We're no longer active */ LazyWriter.ScanActive = FALSE; } @@ -281,3 +298,47 @@ CcWorkerThread( --CcNumberActiveWorkerThreads; KeReleaseQueuedSpinLock(LockQueueWorkQueueLock, OldIrql); } + +/* + * @implemented + */ +NTSTATUS +NTAPI +CcWaitForCurrentLazyWriterActivity ( + VOID) +{ + KIRQL OldIrql; + KEVENT WaitEvent; + PWORK_QUEUE_ENTRY WorkItem; + + /* Allocate a work item */ + WorkItem = ExAllocateFromNPagedLookasideList(&CcTwilightLookasideList); + if (WorkItem == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* We want lazy writer to set our event */ + WorkItem->Function = SetDone; + KeInitializeEvent(&WaitEvent, NotificationEvent, FALSE); + WorkItem->Parameters.Event.Event = &WaitEvent; + + /* Use the post tick queue */ + OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); + InsertTailList(&CcPostTickWorkQueue, &WorkItem->WorkQueueLinks); + + /* Inform the lazy writer it will have to handle the post tick queue */ + LazyWriter.OtherWork = TRUE; + /* And if it's not running, queue a lazy writer run + * And start it NOW, we want the response now + */ + if (!LazyWriter.ScanActive) + { + CcScheduleLazyWriteScan(TRUE); + } + + KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); + + /* And now, wait until lazy writer replies */ + return KeWaitForSingleObject(&WaitEvent, Executive, KernelMode, FALSE, NULL); +} diff --git a/ntoskrnl/include/internal/cc.h b/ntoskrnl/include/internal/cc.h index 18d34ef550c..820cf7a2cb1 100644 --- a/ntoskrnl/include/internal/cc.h +++ b/ntoskrnl/include/internal/cc.h @@ -48,8 +48,8 @@ extern KSPIN_LOCK CcDeferredWriteSpinLock; extern ULONG CcNumberWorkerThreads; extern LIST_ENTRY CcIdleWorkerThreadList; extern LIST_ENTRY CcRegularWorkQueue; +extern LIST_ENTRY CcPostTickWorkQueue; extern NPAGED_LOOKASIDE_LIST CcTwilightLookasideList; -extern KEVENT iLazyWriterNotify; typedef struct _PF_SCENARIO_ID {