diff --git a/ntoskrnl/cache/newcc.h b/ntoskrnl/cache/newcc.h index adbf1c5d926..63f4841229b 100644 --- a/ntoskrnl/cache/newcc.h +++ b/ntoskrnl/cache/newcc.h @@ -53,7 +53,7 @@ CcMdlWriteComplete2(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN PMDL MdlChain); -VOID +BOOLEAN NTAPI CcInitView(VOID); diff --git a/ntoskrnl/cc/cacheman.c b/ntoskrnl/cc/cacheman.c index 4d62314ccd7..2c2c2238c95 100644 --- a/ntoskrnl/cc/cacheman.c +++ b/ntoskrnl/cc/cacheman.c @@ -41,8 +41,15 @@ NTAPI INIT_FUNCTION CcInitializeCacheManager(VOID) { - CcInitView(); - return TRUE; + return CcInitView(); +} + +VOID +NTAPI +CcShutdownSystem(VOID) +{ + /* Inform the lazy writer it has to stop activity */ + CcShutdownLazyWriter(); } /* diff --git a/ntoskrnl/cc/copy.c b/ntoskrnl/cc/copy.c index 15c6ceb81b6..dadae020c76 100644 --- a/ntoskrnl/cc/copy.c +++ b/ntoskrnl/cc/copy.c @@ -34,6 +34,8 @@ ULONG CcFastReadWait; ULONG CcFastReadNoWait; ULONG CcFastReadResourceMiss; +extern KEVENT iLazyWriterNotify; + /* FUNCTIONS *****************************************************************/ VOID @@ -516,14 +518,26 @@ CcFastCopyWrite ( } /* - * @unimplemented + * @implemented */ NTSTATUS NTAPI CcWaitForCurrentLazyWriterActivity ( VOID) { - UNIMPLEMENTED; + 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; } diff --git a/ntoskrnl/cc/fs.c b/ntoskrnl/cc/fs.c index 4958478f3f2..76a073af1be 100644 --- a/ntoskrnl/cc/fs.c +++ b/ntoskrnl/cc/fs.c @@ -20,7 +20,7 @@ /* GLOBALS *****************************************************************/ extern KGUARDED_MUTEX ViewLock; -extern ULONG DirtyPageCount; +extern ULONG CcTotalDirtyPages; NTSTATUS CcRosInternalFreeVacb(PROS_VACB Vacb); @@ -239,7 +239,7 @@ CcPurgeCacheSection ( if (Vacb->Dirty) { RemoveEntryList(&Vacb->DirtyVacbListEntry); - DirtyPageCount -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; + CcTotalDirtyPages -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; } RemoveEntryList(&Vacb->CacheMapVacbListEntry); InsertHeadList(&FreeList, &Vacb->CacheMapVacbListEntry); diff --git a/ntoskrnl/cc/view.c b/ntoskrnl/cc/view.c index 0e37b77efca..8fb7f5333c9 100644 --- a/ntoskrnl/cc/view.c +++ b/ntoskrnl/cc/view.c @@ -43,7 +43,6 @@ LIST_ENTRY DirtyVacbListHead; static LIST_ENTRY VacbLruListHead; -ULONG DirtyPageCount = 0; KGUARDED_MUTEX ViewLock; @@ -51,6 +50,27 @@ NPAGED_LOOKASIDE_LIST iBcbLookasideList; static NPAGED_LOOKASIDE_LIST SharedCacheMapLookasideList; static NPAGED_LOOKASIDE_LIST VacbLookasideList; +/* Counters: + * - Amount of pages flushed by lazy writer + * - Number of times lazy writer ran + */ +ULONG CcLazyWritePages = 0; +ULONG CcLazyWriteIos = 0; + +/* Internal vars (MS): + * - Threshold above which lazy writer will start action + * - Amount of dirty pages + */ +ULONG CcDirtyPageThreshold = 0; +ULONG CcTotalDirtyPages = 0; + +/* Internal vars (ROS): + * - Event to notify lazy writer to shutdown + * - Event to inform watchers lazy writer is done for this loop + */ +KEVENT iLazyWriterShutdown; +KEVENT iLazyWriterNotify; + #if DBG static void CcRosVacbIncRefCount_(PROS_VACB vacb, const char* file, int line) { @@ -145,7 +165,7 @@ CcRosFlushVacb ( Vacb->Dirty = FALSE; RemoveEntryList(&Vacb->DirtyVacbListEntry); - DirtyPageCount -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; + CcTotalDirtyPages -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; CcRosVacbDecRefCount(Vacb); KeReleaseSpinLock(&Vacb->SharedCacheMap->CacheMapLock, oldIrql); @@ -160,7 +180,8 @@ NTAPI CcRosFlushDirtyPages ( ULONG Target, PULONG Count, - BOOLEAN Wait) + BOOLEAN Wait, + BOOLEAN CalledFromLazy) { PLIST_ENTRY current_entry; PROS_VACB current; @@ -191,6 +212,14 @@ CcRosFlushDirtyPages ( CcRosVacbIncRefCount(current); + /* When performing lazy write, don't handle temporary files */ + if (CalledFromLazy && + BooleanFlagOn(current->SharedCacheMap->FileObject->Flags, FO_TEMPORARY_FILE)) + { + CcRosVacbDecRefCount(current); + continue; + } + Locked = current->SharedCacheMap->Callbacks->AcquireForLazyWrite( current->SharedCacheMap->LazyWriteContext, Wait); if (!Locked) @@ -239,8 +268,22 @@ CcRosFlushDirtyPages ( } else { - (*Count) += VACB_MAPPING_GRANULARITY / PAGE_SIZE; - Target -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; + ULONG PagesFreed; + + /* How many pages did we free? */ + PagesFreed = VACB_MAPPING_GRANULARITY / PAGE_SIZE; + (*Count) += PagesFreed; + + /* Make sure we don't overflow target! */ + if (Target < PagesFreed) + { + /* If we would have, jump to zero directly */ + Target = 0; + } + else + { + Target -= PagesFreed; + } } current_entry = DirtyVacbListHead.Flink; @@ -253,6 +296,60 @@ CcRosFlushDirtyPages ( return STATUS_SUCCESS; } +/* FIXME: Someday this could somewhat implement write-behind/read-ahead */ +VOID +NTAPI +CciLazyWriter(PVOID Unused) +{ + LARGE_INTEGER OneSecond; + + OneSecond.QuadPart = (LONGLONG)-1*1000*1000*10; + + while (TRUE) + { + NTSTATUS Status; + ULONG Target, Count = 0; + + /* One per second or until we have to stop */ + Status = KeWaitForSingleObject(&iLazyWriterShutdown, + Executive, + KernelMode, + FALSE, + &OneSecond); + + /* If we succeeed, we've to stop running! */ + if (Status == STATUS_SUCCESS) + { + break; + } + + /* We're not sleeping anymore */ + KeClearEvent(&iLazyWriterNotify); + + /* Only start operations if above threshold */ + DPRINT("TS: %lu, Count: %lu\n", CcDirtyPageThreshold, CcTotalDirtyPages); + if (CcTotalDirtyPages > CcDirtyPageThreshold) + { + /* Our target is one-eighth of the dirty pages */ + 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); + } + } + + /* Inform people waiting on us that we're done */ + KeSetEvent(&iLazyWriterNotify, IO_DISK_INCREMENT, FALSE); + } +} + NTSTATUS CcRosTrimCache ( ULONG Target, @@ -346,7 +443,7 @@ retry: if ((Target > 0) && !FlushedPages) { /* Flush dirty pages to disk */ - CcRosFlushDirtyPages(Target, &PagesFreed, FALSE); + CcRosFlushDirtyPages(Target, &PagesFreed, FALSE, FALSE); FlushedPages = TRUE; /* We can only swap as many pages as we flushed */ @@ -403,7 +500,7 @@ CcRosReleaseVacb ( if (!WasDirty && Vacb->Dirty) { InsertTailList(&DirtyVacbListHead, &Vacb->DirtyVacbListEntry); - DirtyPageCount += VACB_MAPPING_GRANULARITY / PAGE_SIZE; + CcTotalDirtyPages += VACB_MAPPING_GRANULARITY / PAGE_SIZE; } if (Mapped) @@ -499,7 +596,7 @@ CcRosMarkDirtyVacb ( if (!Vacb->Dirty) { InsertTailList(&DirtyVacbListHead, &Vacb->DirtyVacbListEntry); - DirtyPageCount += VACB_MAPPING_GRANULARITY / PAGE_SIZE; + CcTotalDirtyPages += VACB_MAPPING_GRANULARITY / PAGE_SIZE; } else { @@ -552,7 +649,7 @@ CcRosUnmapVacb ( if (!WasDirty && NowDirty) { InsertTailList(&DirtyVacbListHead, &Vacb->DirtyVacbListEntry); - DirtyPageCount += VACB_MAPPING_GRANULARITY / PAGE_SIZE; + CcTotalDirtyPages += VACB_MAPPING_GRANULARITY / PAGE_SIZE; } CcRosVacbDecRefCount(Vacb); @@ -1014,7 +1111,7 @@ CcRosDeleteFileCache ( if (current->Dirty) { RemoveEntryList(¤t->DirtyVacbListEntry); - DirtyPageCount -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; + CcTotalDirtyPages -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; DPRINT1("Freeing dirty VACB\n"); } InsertHeadList(&FreeList, ¤t->CacheMapVacbListEntry); @@ -1230,11 +1327,24 @@ CcGetFileObjectFromSectionPtrs ( } VOID +NTAPI +CcShutdownLazyWriter ( + VOID) +{ + /* Simply set the event, lazy writer will stop when it's done */ + KeSetEvent(&iLazyWriterShutdown, IO_DISK_INCREMENT, FALSE); +} + +BOOLEAN INIT_FUNCTION NTAPI CcInitView ( VOID) { + HANDLE LazyWriter; + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + DPRINT("CcInitView()\n"); InitializeListHead(&DirtyVacbListHead); @@ -1264,7 +1374,50 @@ CcInitView ( MmInitializeMemoryConsumer(MC_CACHE, CcRosTrimCache); + /* Initialize lazy writer events */ + KeInitializeEvent(&iLazyWriterShutdown, SynchronizationEvent, FALSE); + KeInitializeEvent(&iLazyWriterNotify, NotificationEvent, FALSE); + + /* Define lazy writer threshold, depending on system type */ + switch (MmQuerySystemSize()) + { + case MmSmallSystem: + CcDirtyPageThreshold = MmNumberOfPhysicalPages / 8; + break; + + case MmMediumSystem: + CcDirtyPageThreshold = MmNumberOfPhysicalPages / 4; + break; + + case MmLargeSystem: + CcDirtyPageThreshold = MmNumberOfPhysicalPages / 8 + MmNumberOfPhysicalPages / 4; + break; + } + + /* Start the lazy writer thread */ + InitializeObjectAttributes(&ObjectAttributes, + NULL, + OBJ_KERNEL_HANDLE, + NULL, + NULL); + Status = PsCreateSystemThread(&LazyWriter, + THREAD_ALL_ACCESS, + &ObjectAttributes, + NULL, + NULL, + CciLazyWriter, + NULL); + if (!NT_SUCCESS(Status)) + { + return FALSE; + } + + /* Handle is not needed */ + ObCloseHandle(LazyWriter, KernelMode); + CcInitCacheZeroPage(); + + return TRUE; } /* EOF */ diff --git a/ntoskrnl/include/internal/cc.h b/ntoskrnl/include/internal/cc.h index 58d2b15a507..b1bb1ab165d 100644 --- a/ntoskrnl/include/internal/cc.h +++ b/ntoskrnl/include/internal/cc.h @@ -240,10 +240,14 @@ CcRosGetVacb( PROS_VACB *Vacb ); -VOID +BOOLEAN NTAPI CcInitView(VOID); +VOID +NTAPI +CcShutdownLazyWriter(VOID); + NTSTATUS NTAPI CcReadVirtualAddress(PROS_VACB Vacb); @@ -287,7 +291,8 @@ NTAPI CcRosFlushDirtyPages( ULONG Target, PULONG Count, - BOOLEAN Wait + BOOLEAN Wait, + BOOLEAN CalledFromLazy ); VOID @@ -342,6 +347,10 @@ NTSTATUS NTAPI CcTryToInitializeFileCache(PFILE_OBJECT FileObject); +VOID +NTAPI +CcShutdownSystem(VOID); + FORCEINLINE NTSTATUS CcRosAcquireVacbLock( diff --git a/ntoskrnl/mm/mminit.c b/ntoskrnl/mm/mminit.c index 3fff72b7713..7f756cb7786 100644 --- a/ntoskrnl/mm/mminit.c +++ b/ntoskrnl/mm/mminit.c @@ -19,9 +19,6 @@ VOID NTAPI MiInitializeUserPfnBitmap(VOID); -HANDLE MpwThreadHandle; -KEVENT MpwThreadEvent; - BOOLEAN Mm64BitPhysicalAddress = FALSE; ULONG MmReadClusterSize; // @@ -169,76 +166,6 @@ MiDbgDumpAddressSpace(VOID) "Non Paged Pool Expansion PTE Space"); } -VOID -NTAPI -MmMpwThreadMain(PVOID Parameter) -{ - NTSTATUS Status; -#ifndef NEWCC - ULONG PagesWritten; -#endif - LARGE_INTEGER Timeout; - - UNREFERENCED_PARAMETER(Parameter); - - Timeout.QuadPart = -50000000; - - for(;;) - { - Status = KeWaitForSingleObject(&MpwThreadEvent, - 0, - KernelMode, - FALSE, - &Timeout); - if (!NT_SUCCESS(Status)) - { - DbgPrint("MpwThread: Wait failed\n"); - KeBugCheck(MEMORY_MANAGEMENT); - return; - } - -#ifndef NEWCC - PagesWritten = 0; - - // XXX arty -- we flush when evicting pages or destorying cache - // sections. - CcRosFlushDirtyPages(128, &PagesWritten, FALSE); -#endif - } -} - -NTSTATUS -NTAPI -INIT_FUNCTION -MmInitMpwThread(VOID) -{ - KPRIORITY Priority; - NTSTATUS Status; - CLIENT_ID MpwThreadId; - - KeInitializeEvent(&MpwThreadEvent, SynchronizationEvent, FALSE); - - Status = PsCreateSystemThread(&MpwThreadHandle, - THREAD_ALL_ACCESS, - NULL, - NULL, - &MpwThreadId, - MmMpwThreadMain, - NULL); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - - Priority = 27; - NtSetInformationThread(MpwThreadHandle, - ThreadPriority, - &Priority, - sizeof(Priority)); - - return(STATUS_SUCCESS); -} - NTSTATUS NTAPI INIT_FUNCTION @@ -338,11 +265,6 @@ MmInitSystem(IN ULONG Phase, */ MiInitBalancerThread(); - /* - * Initialise the modified page writer. - */ - MmInitMpwThread(); - /* Initialize the balance set manager */ MmInitBsmThread(); diff --git a/ntoskrnl/po/poshtdwn.c b/ntoskrnl/po/poshtdwn.c index 3ebf899bd58..04618c9f546 100644 --- a/ntoskrnl/po/poshtdwn.c +++ b/ntoskrnl/po/poshtdwn.c @@ -279,11 +279,10 @@ PopGracefulShutdown(IN PVOID Context) CmShutdownSystem(); /* Note that modified pages should be written here (MiShutdownSystem) */ -#ifdef NEWCC + /* Flush all user files before we start shutting down IO */ /* This is where modified pages are written back by the IO manager */ CcShutdownSystem(); -#endif /* In this step, the I/O manager does last-chance shutdown notification */ DPRINT("I/O manager shutting down in phase 1\n"); diff --git a/ntoskrnl/po/power.c b/ntoskrnl/po/power.c index 9b96b6016e2..2dee988b347 100644 --- a/ntoskrnl/po/power.c +++ b/ntoskrnl/po/power.c @@ -952,7 +952,8 @@ NtSetSystemPowerState(IN POWER_ACTION SystemAction, #ifndef NEWCC /* Flush dirty cache pages */ - CcRosFlushDirtyPages(-1, &Dummy, FALSE); //HACK: We really should wait here! + /* XXX: Is that still mandatory? As now we'll wait on lazy writer to complete? */ + CcRosFlushDirtyPages(-1, &Dummy, FALSE, FALSE); //HACK: We really should wait here! #else Dummy = 0; #endif