reactos/ntoskrnl/cc/view.c

1465 lines
42 KiB
C
Raw Normal View History

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/cc/view.c
* PURPOSE: Cache manager
*
* PROGRAMMERS: David Welch (welch@mcmail.com)
* Pierre Schweitzer (pierre@reactos.org)
*/
/* NOTES **********************************************************************
*
* This is not the NT implementation of a file cache nor anything much like
* it.
*
* The general procedure for a filesystem to implement a read or write
* dispatch routine is as follows
*
* (1) If caching for the FCB hasn't been initiated then so do by calling
* CcInitializeFileCache.
*
* (2) For each 4k region which is being read or written obtain a cache page
* by calling CcRequestCachePage.
*
* (3) If either the page is being read or not completely written, and it is
* not up to date then read its data from the underlying medium. If the read
* fails then call CcReleaseCachePage with VALID as FALSE and return a error.
*
* (4) Copy the data into or out of the page as necessary.
*
* (5) Release the cache page
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(INIT, CcInitView)
#endif
/* GLOBALS *******************************************************************/
LIST_ENTRY DirtyVacbListHead;
static LIST_ENTRY VacbLruListHead;
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
KGUARDED_MUTEX ViewLock;
NPAGED_LOOKASIDE_LIST iBcbLookasideList;
static NPAGED_LOOKASIDE_LIST SharedCacheMapLookasideList;
static NPAGED_LOOKASIDE_LIST VacbLookasideList;
/* Internal vars (MS):
* - Threshold above which lazy writer will start action
* - Amount of dirty pages
* - List for deferred writes
* - Spinlock when dealing with the deferred list
* - List for "clean" shared cache maps
*/
ULONG CcDirtyPageThreshold = 0;
ULONG CcTotalDirtyPages = 0;
LIST_ENTRY CcDeferredWrites;
KSPIN_LOCK CcDeferredWriteSpinLock;
LIST_ENTRY CcCleanSharedCacheMapList;
#if DBG
static void CcRosVacbIncRefCount_(PROS_VACB vacb, const char* file, int line)
{
++vacb->ReferenceCount;
if (vacb->SharedCacheMap->Trace)
{
DbgPrint("(%s:%i) VACB %p ++RefCount=%lu, Dirty %u, PageOut %lu\n",
file, line, vacb, vacb->ReferenceCount, vacb->Dirty, vacb->PageOut);
}
}
static void CcRosVacbDecRefCount_(PROS_VACB vacb, const char* file, int line)
{
ASSERT(vacb->ReferenceCount != 0);
--vacb->ReferenceCount;
ASSERT(!(vacb->ReferenceCount == 0 && vacb->Dirty));
if (vacb->SharedCacheMap->Trace)
{
DbgPrint("(%s:%i) VACB %p --RefCount=%lu, Dirty %u, PageOut %lu\n",
file, line, vacb, vacb->ReferenceCount, vacb->Dirty, vacb->PageOut);
}
}
#define CcRosVacbIncRefCount(vacb) CcRosVacbIncRefCount_(vacb,__FILE__,__LINE__)
#define CcRosVacbDecRefCount(vacb) CcRosVacbDecRefCount_(vacb,__FILE__,__LINE__)
#else
#define CcRosVacbIncRefCount(vacb) (++((vacb)->ReferenceCount))
#define CcRosVacbDecRefCount(vacb) (--((vacb)->ReferenceCount))
#endif
NTSTATUS
CcRosInternalFreeVacb(PROS_VACB Vacb);
/* FUNCTIONS *****************************************************************/
VOID
NTAPI
CcRosTraceCacheMap (
PROS_SHARED_CACHE_MAP SharedCacheMap,
BOOLEAN Trace )
{
#if DBG
KIRQL oldirql;
PLIST_ENTRY current_entry;
PROS_VACB current;
if (!SharedCacheMap)
return;
SharedCacheMap->Trace = Trace;
if (Trace)
{
DPRINT1("Enabling Tracing for CacheMap 0x%p:\n", SharedCacheMap);
KeAcquireGuardedMutex(&ViewLock);
KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldirql);
current_entry = SharedCacheMap->CacheMapVacbListHead.Flink;
while (current_entry != &SharedCacheMap->CacheMapVacbListHead)
{
current = CONTAINING_RECORD(current_entry, ROS_VACB, CacheMapVacbListEntry);
current_entry = current_entry->Flink;
DPRINT1(" VACB 0x%p enabled, RefCount %lu, Dirty %u, PageOut %lu\n",
current, current->ReferenceCount, current->Dirty, current->PageOut );
}
KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql);
KeReleaseGuardedMutex(&ViewLock);
}
else
{
DPRINT1("Disabling Tracing for CacheMap 0x%p:\n", SharedCacheMap);
}
#else
UNREFERENCED_PARAMETER(SharedCacheMap);
UNREFERENCED_PARAMETER(Trace);
#endif
}
NTSTATUS
NTAPI
CcRosFlushVacb (
PROS_VACB Vacb)
2002-08-14 David Welch <welch@computer2.darkstar.org> * subsys/smss/init.c (SmPagingFilesQueryRoutine): If possible take the size of the paging file from the registry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/section.c (MmCreateDataFileSection): Extend the section if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/pagefile.c (NtCreatePagingFile): Set the file size using the FileAllocationInformation class. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/anonmem.c (MmWritePageVirtualMemory): Implemented function to write anonymous memory pages to the swap file. * ntoskrnl/mm/anonmem.c (MmFreeVirtualMemoryPage): Free any swap page associated with the page. * ntoskrnl/mm/mpw.c (MmWriteDirtyPages): New function to find pages to write to disk. * ntoskrnl/mm/mpw.c (MmMpwThreadMain): Implemented MPW functionality. * ntoskrnl/mm/rmap.c (MmWritePagePhysicalAddress): New function to write a single page back to disk. * ntoskrnl/mm/rmap.c (MmSetCleanAllRmaps, MmSetDirtyAllRmaps, MmIsDirtyPageRmap): New rmap function to support the MPW thread. * ntoskrnl/mm/section.c (MmWritePageSectionView): Implemented function to write back section pages. * ntoskrnl/mm/section.c (MmFreeSectionPage): Free any swap entry associated with the page; mark pages shared with the cache as dirty if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/ldr/loader.c (LdrPEProcessModule): Set name of the module into the module text structure. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/io/rw.c (NtReadFile, NtWriteFile): Use the correct test for whether to wait for the completion of i/o. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cm/ntfunc.c (NtFlushKey): Request synchronous i/o from NtOpenFile. * ntoskrnl/cm/regfile (CmiInitPermanentRegistryHive): Request synchronous i/o from NtCreateFile. * ntoskrnl/dbg/kdb_stabs.c (LdrpLoadModuleSymbols): Request synchronous i/o from NtOpenFile. * ntoskrnl/ldr/sysdll.c (LdrpMapSystemDll): Request synchronous i/o from NtOpenFile. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosSuggestFreeCacheSegment): Maintain the correct reference count. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosFlushCacheSegment): New function to write back a modified cache segment. * ntoskrnl/cc/view.c (CcRosFlushDirtyPages): New function to flush some dirty pages from the cache. * ntoskrnl/cc/view.c (CcRosMarkDirtyCacheSegment): New function to mark a cache segment modified while mapped into memory as dirty. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/pin.c (CcMapData, CcUnpinData, CcSetDirtyPinnedData): Store the dirty status in the BCB; don't write back dirty data immediately. 2002-08-14 David Welch <welch@computer2.darkstar.org> * include/ntos/mm.h: Added SEC_XXXX defines from 'Windows NT/2000 Native API Reference' 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/ea.c (VfatSetExtendedAttributes): Empty placeholder for extended attribute functions. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/finfo.c (VfatSetAllocationSizeInformation): Added function to set allocation size. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/fcb.c (vfatFCBInitializeCache): Renamed to vfatFCBInitializeCacheFromVolume. * drivers/fs/vfat/fcb.c (vfatMakeFCBFromDirEntry): Don't initialise the cache with a file object representing the volume unless the FCB is for a directory. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/create.c (VfatPagingFileCreate): Added a new function for handling paging file only code. * drivers/fs/vfat/create.c (VfatSupersedeFile): Added a new function for doing a file supersede. * drivers/fs/vfat/create.c (VfatCreateFile): Reformatted and adjusted control flow. Set allocation size and extended attributes on create. * drivers/fs/vfat/create.c (VfatCreate): Removed goto. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/cleanup.c (VfatCleanupFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/close.c (VfatCloseFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (updEntry): Renamed to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (addEntry): Renamed to VfatAddEntry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * apps/tests/sectest/sectest.c (main): Fixed formatting. svn path=/trunk/; revision=3331
2002-08-15 04:58:39 +08:00
{
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
NTSTATUS Status;
Status = CcWriteVirtualAddress(Vacb);
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
if (NT_SUCCESS(Status))
2002-08-14 David Welch <welch@computer2.darkstar.org> * subsys/smss/init.c (SmPagingFilesQueryRoutine): If possible take the size of the paging file from the registry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/section.c (MmCreateDataFileSection): Extend the section if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/pagefile.c (NtCreatePagingFile): Set the file size using the FileAllocationInformation class. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/anonmem.c (MmWritePageVirtualMemory): Implemented function to write anonymous memory pages to the swap file. * ntoskrnl/mm/anonmem.c (MmFreeVirtualMemoryPage): Free any swap page associated with the page. * ntoskrnl/mm/mpw.c (MmWriteDirtyPages): New function to find pages to write to disk. * ntoskrnl/mm/mpw.c (MmMpwThreadMain): Implemented MPW functionality. * ntoskrnl/mm/rmap.c (MmWritePagePhysicalAddress): New function to write a single page back to disk. * ntoskrnl/mm/rmap.c (MmSetCleanAllRmaps, MmSetDirtyAllRmaps, MmIsDirtyPageRmap): New rmap function to support the MPW thread. * ntoskrnl/mm/section.c (MmWritePageSectionView): Implemented function to write back section pages. * ntoskrnl/mm/section.c (MmFreeSectionPage): Free any swap entry associated with the page; mark pages shared with the cache as dirty if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/ldr/loader.c (LdrPEProcessModule): Set name of the module into the module text structure. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/io/rw.c (NtReadFile, NtWriteFile): Use the correct test for whether to wait for the completion of i/o. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cm/ntfunc.c (NtFlushKey): Request synchronous i/o from NtOpenFile. * ntoskrnl/cm/regfile (CmiInitPermanentRegistryHive): Request synchronous i/o from NtCreateFile. * ntoskrnl/dbg/kdb_stabs.c (LdrpLoadModuleSymbols): Request synchronous i/o from NtOpenFile. * ntoskrnl/ldr/sysdll.c (LdrpMapSystemDll): Request synchronous i/o from NtOpenFile. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosSuggestFreeCacheSegment): Maintain the correct reference count. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosFlushCacheSegment): New function to write back a modified cache segment. * ntoskrnl/cc/view.c (CcRosFlushDirtyPages): New function to flush some dirty pages from the cache. * ntoskrnl/cc/view.c (CcRosMarkDirtyCacheSegment): New function to mark a cache segment modified while mapped into memory as dirty. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/pin.c (CcMapData, CcUnpinData, CcSetDirtyPinnedData): Store the dirty status in the BCB; don't write back dirty data immediately. 2002-08-14 David Welch <welch@computer2.darkstar.org> * include/ntos/mm.h: Added SEC_XXXX defines from 'Windows NT/2000 Native API Reference' 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/ea.c (VfatSetExtendedAttributes): Empty placeholder for extended attribute functions. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/finfo.c (VfatSetAllocationSizeInformation): Added function to set allocation size. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/fcb.c (vfatFCBInitializeCache): Renamed to vfatFCBInitializeCacheFromVolume. * drivers/fs/vfat/fcb.c (vfatMakeFCBFromDirEntry): Don't initialise the cache with a file object representing the volume unless the FCB is for a directory. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/create.c (VfatPagingFileCreate): Added a new function for handling paging file only code. * drivers/fs/vfat/create.c (VfatSupersedeFile): Added a new function for doing a file supersede. * drivers/fs/vfat/create.c (VfatCreateFile): Reformatted and adjusted control flow. Set allocation size and extended attributes on create. * drivers/fs/vfat/create.c (VfatCreate): Removed goto. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/cleanup.c (VfatCleanupFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/close.c (VfatCloseFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (updEntry): Renamed to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (addEntry): Renamed to VfatAddEntry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * apps/tests/sectest/sectest.c (main): Fixed formatting. svn path=/trunk/; revision=3331
2002-08-15 04:58:39 +08:00
{
CcRosUnmarkDirtyVacb(Vacb, TRUE);
2002-08-14 David Welch <welch@computer2.darkstar.org> * subsys/smss/init.c (SmPagingFilesQueryRoutine): If possible take the size of the paging file from the registry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/section.c (MmCreateDataFileSection): Extend the section if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/pagefile.c (NtCreatePagingFile): Set the file size using the FileAllocationInformation class. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/anonmem.c (MmWritePageVirtualMemory): Implemented function to write anonymous memory pages to the swap file. * ntoskrnl/mm/anonmem.c (MmFreeVirtualMemoryPage): Free any swap page associated with the page. * ntoskrnl/mm/mpw.c (MmWriteDirtyPages): New function to find pages to write to disk. * ntoskrnl/mm/mpw.c (MmMpwThreadMain): Implemented MPW functionality. * ntoskrnl/mm/rmap.c (MmWritePagePhysicalAddress): New function to write a single page back to disk. * ntoskrnl/mm/rmap.c (MmSetCleanAllRmaps, MmSetDirtyAllRmaps, MmIsDirtyPageRmap): New rmap function to support the MPW thread. * ntoskrnl/mm/section.c (MmWritePageSectionView): Implemented function to write back section pages. * ntoskrnl/mm/section.c (MmFreeSectionPage): Free any swap entry associated with the page; mark pages shared with the cache as dirty if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/ldr/loader.c (LdrPEProcessModule): Set name of the module into the module text structure. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/io/rw.c (NtReadFile, NtWriteFile): Use the correct test for whether to wait for the completion of i/o. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cm/ntfunc.c (NtFlushKey): Request synchronous i/o from NtOpenFile. * ntoskrnl/cm/regfile (CmiInitPermanentRegistryHive): Request synchronous i/o from NtCreateFile. * ntoskrnl/dbg/kdb_stabs.c (LdrpLoadModuleSymbols): Request synchronous i/o from NtOpenFile. * ntoskrnl/ldr/sysdll.c (LdrpMapSystemDll): Request synchronous i/o from NtOpenFile. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosSuggestFreeCacheSegment): Maintain the correct reference count. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosFlushCacheSegment): New function to write back a modified cache segment. * ntoskrnl/cc/view.c (CcRosFlushDirtyPages): New function to flush some dirty pages from the cache. * ntoskrnl/cc/view.c (CcRosMarkDirtyCacheSegment): New function to mark a cache segment modified while mapped into memory as dirty. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/pin.c (CcMapData, CcUnpinData, CcSetDirtyPinnedData): Store the dirty status in the BCB; don't write back dirty data immediately. 2002-08-14 David Welch <welch@computer2.darkstar.org> * include/ntos/mm.h: Added SEC_XXXX defines from 'Windows NT/2000 Native API Reference' 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/ea.c (VfatSetExtendedAttributes): Empty placeholder for extended attribute functions. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/finfo.c (VfatSetAllocationSizeInformation): Added function to set allocation size. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/fcb.c (vfatFCBInitializeCache): Renamed to vfatFCBInitializeCacheFromVolume. * drivers/fs/vfat/fcb.c (vfatMakeFCBFromDirEntry): Don't initialise the cache with a file object representing the volume unless the FCB is for a directory. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/create.c (VfatPagingFileCreate): Added a new function for handling paging file only code. * drivers/fs/vfat/create.c (VfatSupersedeFile): Added a new function for doing a file supersede. * drivers/fs/vfat/create.c (VfatCreateFile): Reformatted and adjusted control flow. Set allocation size and extended attributes on create. * drivers/fs/vfat/create.c (VfatCreate): Removed goto. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/cleanup.c (VfatCleanupFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/close.c (VfatCloseFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (updEntry): Renamed to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (addEntry): Renamed to VfatAddEntry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * apps/tests/sectest/sectest.c (main): Fixed formatting. svn path=/trunk/; revision=3331
2002-08-15 04:58:39 +08:00
}
return Status;
2002-08-14 David Welch <welch@computer2.darkstar.org> * subsys/smss/init.c (SmPagingFilesQueryRoutine): If possible take the size of the paging file from the registry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/section.c (MmCreateDataFileSection): Extend the section if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/pagefile.c (NtCreatePagingFile): Set the file size using the FileAllocationInformation class. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/anonmem.c (MmWritePageVirtualMemory): Implemented function to write anonymous memory pages to the swap file. * ntoskrnl/mm/anonmem.c (MmFreeVirtualMemoryPage): Free any swap page associated with the page. * ntoskrnl/mm/mpw.c (MmWriteDirtyPages): New function to find pages to write to disk. * ntoskrnl/mm/mpw.c (MmMpwThreadMain): Implemented MPW functionality. * ntoskrnl/mm/rmap.c (MmWritePagePhysicalAddress): New function to write a single page back to disk. * ntoskrnl/mm/rmap.c (MmSetCleanAllRmaps, MmSetDirtyAllRmaps, MmIsDirtyPageRmap): New rmap function to support the MPW thread. * ntoskrnl/mm/section.c (MmWritePageSectionView): Implemented function to write back section pages. * ntoskrnl/mm/section.c (MmFreeSectionPage): Free any swap entry associated with the page; mark pages shared with the cache as dirty if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/ldr/loader.c (LdrPEProcessModule): Set name of the module into the module text structure. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/io/rw.c (NtReadFile, NtWriteFile): Use the correct test for whether to wait for the completion of i/o. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cm/ntfunc.c (NtFlushKey): Request synchronous i/o from NtOpenFile. * ntoskrnl/cm/regfile (CmiInitPermanentRegistryHive): Request synchronous i/o from NtCreateFile. * ntoskrnl/dbg/kdb_stabs.c (LdrpLoadModuleSymbols): Request synchronous i/o from NtOpenFile. * ntoskrnl/ldr/sysdll.c (LdrpMapSystemDll): Request synchronous i/o from NtOpenFile. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosSuggestFreeCacheSegment): Maintain the correct reference count. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosFlushCacheSegment): New function to write back a modified cache segment. * ntoskrnl/cc/view.c (CcRosFlushDirtyPages): New function to flush some dirty pages from the cache. * ntoskrnl/cc/view.c (CcRosMarkDirtyCacheSegment): New function to mark a cache segment modified while mapped into memory as dirty. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/pin.c (CcMapData, CcUnpinData, CcSetDirtyPinnedData): Store the dirty status in the BCB; don't write back dirty data immediately. 2002-08-14 David Welch <welch@computer2.darkstar.org> * include/ntos/mm.h: Added SEC_XXXX defines from 'Windows NT/2000 Native API Reference' 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/ea.c (VfatSetExtendedAttributes): Empty placeholder for extended attribute functions. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/finfo.c (VfatSetAllocationSizeInformation): Added function to set allocation size. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/fcb.c (vfatFCBInitializeCache): Renamed to vfatFCBInitializeCacheFromVolume. * drivers/fs/vfat/fcb.c (vfatMakeFCBFromDirEntry): Don't initialise the cache with a file object representing the volume unless the FCB is for a directory. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/create.c (VfatPagingFileCreate): Added a new function for handling paging file only code. * drivers/fs/vfat/create.c (VfatSupersedeFile): Added a new function for doing a file supersede. * drivers/fs/vfat/create.c (VfatCreateFile): Reformatted and adjusted control flow. Set allocation size and extended attributes on create. * drivers/fs/vfat/create.c (VfatCreate): Removed goto. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/cleanup.c (VfatCleanupFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/close.c (VfatCloseFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (updEntry): Renamed to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (addEntry): Renamed to VfatAddEntry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * apps/tests/sectest/sectest.c (main): Fixed formatting. svn path=/trunk/; revision=3331
2002-08-15 04:58:39 +08:00
}
NTSTATUS
NTAPI
CcRosFlushDirtyPages (
ULONG Target,
PULONG Count,
BOOLEAN Wait,
BOOLEAN CalledFromLazy)
2002-08-14 David Welch <welch@computer2.darkstar.org> * subsys/smss/init.c (SmPagingFilesQueryRoutine): If possible take the size of the paging file from the registry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/section.c (MmCreateDataFileSection): Extend the section if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/pagefile.c (NtCreatePagingFile): Set the file size using the FileAllocationInformation class. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/anonmem.c (MmWritePageVirtualMemory): Implemented function to write anonymous memory pages to the swap file. * ntoskrnl/mm/anonmem.c (MmFreeVirtualMemoryPage): Free any swap page associated with the page. * ntoskrnl/mm/mpw.c (MmWriteDirtyPages): New function to find pages to write to disk. * ntoskrnl/mm/mpw.c (MmMpwThreadMain): Implemented MPW functionality. * ntoskrnl/mm/rmap.c (MmWritePagePhysicalAddress): New function to write a single page back to disk. * ntoskrnl/mm/rmap.c (MmSetCleanAllRmaps, MmSetDirtyAllRmaps, MmIsDirtyPageRmap): New rmap function to support the MPW thread. * ntoskrnl/mm/section.c (MmWritePageSectionView): Implemented function to write back section pages. * ntoskrnl/mm/section.c (MmFreeSectionPage): Free any swap entry associated with the page; mark pages shared with the cache as dirty if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/ldr/loader.c (LdrPEProcessModule): Set name of the module into the module text structure. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/io/rw.c (NtReadFile, NtWriteFile): Use the correct test for whether to wait for the completion of i/o. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cm/ntfunc.c (NtFlushKey): Request synchronous i/o from NtOpenFile. * ntoskrnl/cm/regfile (CmiInitPermanentRegistryHive): Request synchronous i/o from NtCreateFile. * ntoskrnl/dbg/kdb_stabs.c (LdrpLoadModuleSymbols): Request synchronous i/o from NtOpenFile. * ntoskrnl/ldr/sysdll.c (LdrpMapSystemDll): Request synchronous i/o from NtOpenFile. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosSuggestFreeCacheSegment): Maintain the correct reference count. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosFlushCacheSegment): New function to write back a modified cache segment. * ntoskrnl/cc/view.c (CcRosFlushDirtyPages): New function to flush some dirty pages from the cache. * ntoskrnl/cc/view.c (CcRosMarkDirtyCacheSegment): New function to mark a cache segment modified while mapped into memory as dirty. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/pin.c (CcMapData, CcUnpinData, CcSetDirtyPinnedData): Store the dirty status in the BCB; don't write back dirty data immediately. 2002-08-14 David Welch <welch@computer2.darkstar.org> * include/ntos/mm.h: Added SEC_XXXX defines from 'Windows NT/2000 Native API Reference' 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/ea.c (VfatSetExtendedAttributes): Empty placeholder for extended attribute functions. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/finfo.c (VfatSetAllocationSizeInformation): Added function to set allocation size. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/fcb.c (vfatFCBInitializeCache): Renamed to vfatFCBInitializeCacheFromVolume. * drivers/fs/vfat/fcb.c (vfatMakeFCBFromDirEntry): Don't initialise the cache with a file object representing the volume unless the FCB is for a directory. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/create.c (VfatPagingFileCreate): Added a new function for handling paging file only code. * drivers/fs/vfat/create.c (VfatSupersedeFile): Added a new function for doing a file supersede. * drivers/fs/vfat/create.c (VfatCreateFile): Reformatted and adjusted control flow. Set allocation size and extended attributes on create. * drivers/fs/vfat/create.c (VfatCreate): Removed goto. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/cleanup.c (VfatCleanupFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/close.c (VfatCloseFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (updEntry): Renamed to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (addEntry): Renamed to VfatAddEntry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * apps/tests/sectest/sectest.c (main): Fixed formatting. svn path=/trunk/; revision=3331
2002-08-15 04:58:39 +08:00
{
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
PLIST_ENTRY current_entry;
PROS_VACB current;
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
BOOLEAN Locked;
NTSTATUS Status;
2016-05-26 20:09:05 +08:00
LARGE_INTEGER ZeroTimeout;
DPRINT("CcRosFlushDirtyPages(Target %lu)\n", Target);
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
(*Count) = 0;
2016-05-26 20:09:05 +08:00
ZeroTimeout.QuadPart = 0;
KeEnterCriticalRegion();
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
KeAcquireGuardedMutex(&ViewLock);
current_entry = DirtyVacbListHead.Flink;
if (current_entry == &DirtyVacbListHead)
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
{
DPRINT("No Dirty pages\n");
}
while ((current_entry != &DirtyVacbListHead) && (Target > 0))
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
{
current = CONTAINING_RECORD(current_entry,
ROS_VACB,
DirtyVacbListEntry);
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
current_entry = current_entry->Flink;
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);
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
if (!Locked)
{
CcRosVacbDecRefCount(current);
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
continue;
}
Status = CcRosAcquireVacbLock(current,
Wait ? NULL : &ZeroTimeout);
2016-05-26 20:09:05 +08:00
if (Status != STATUS_SUCCESS)
{
current->SharedCacheMap->Callbacks->ReleaseFromLazyWrite(
current->SharedCacheMap->LazyWriteContext);
CcRosVacbDecRefCount(current);
continue;
}
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
ASSERT(current->Dirty);
/* One reference is added above */
if (current->ReferenceCount > 2)
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
{
CcRosReleaseVacbLock(current);
current->SharedCacheMap->Callbacks->ReleaseFromLazyWrite(
current->SharedCacheMap->LazyWriteContext);
CcRosVacbDecRefCount(current);
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
continue;
}
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
KeReleaseGuardedMutex(&ViewLock);
Status = CcRosFlushVacb(current);
CcRosReleaseVacbLock(current);
current->SharedCacheMap->Callbacks->ReleaseFromLazyWrite(
current->SharedCacheMap->LazyWriteContext);
KeAcquireGuardedMutex(&ViewLock);
CcRosVacbDecRefCount(current);
if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE) &&
(Status != STATUS_MEDIA_WRITE_PROTECTED))
{
DPRINT1("CC: Failed to flush VACB.\n");
}
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
else
{
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;
}
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
}
current_entry = DirtyVacbListHead.Flink;
2002-08-14 David Welch <welch@computer2.darkstar.org> * subsys/smss/init.c (SmPagingFilesQueryRoutine): If possible take the size of the paging file from the registry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/section.c (MmCreateDataFileSection): Extend the section if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/pagefile.c (NtCreatePagingFile): Set the file size using the FileAllocationInformation class. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/anonmem.c (MmWritePageVirtualMemory): Implemented function to write anonymous memory pages to the swap file. * ntoskrnl/mm/anonmem.c (MmFreeVirtualMemoryPage): Free any swap page associated with the page. * ntoskrnl/mm/mpw.c (MmWriteDirtyPages): New function to find pages to write to disk. * ntoskrnl/mm/mpw.c (MmMpwThreadMain): Implemented MPW functionality. * ntoskrnl/mm/rmap.c (MmWritePagePhysicalAddress): New function to write a single page back to disk. * ntoskrnl/mm/rmap.c (MmSetCleanAllRmaps, MmSetDirtyAllRmaps, MmIsDirtyPageRmap): New rmap function to support the MPW thread. * ntoskrnl/mm/section.c (MmWritePageSectionView): Implemented function to write back section pages. * ntoskrnl/mm/section.c (MmFreeSectionPage): Free any swap entry associated with the page; mark pages shared with the cache as dirty if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/ldr/loader.c (LdrPEProcessModule): Set name of the module into the module text structure. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/io/rw.c (NtReadFile, NtWriteFile): Use the correct test for whether to wait for the completion of i/o. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cm/ntfunc.c (NtFlushKey): Request synchronous i/o from NtOpenFile. * ntoskrnl/cm/regfile (CmiInitPermanentRegistryHive): Request synchronous i/o from NtCreateFile. * ntoskrnl/dbg/kdb_stabs.c (LdrpLoadModuleSymbols): Request synchronous i/o from NtOpenFile. * ntoskrnl/ldr/sysdll.c (LdrpMapSystemDll): Request synchronous i/o from NtOpenFile. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosSuggestFreeCacheSegment): Maintain the correct reference count. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosFlushCacheSegment): New function to write back a modified cache segment. * ntoskrnl/cc/view.c (CcRosFlushDirtyPages): New function to flush some dirty pages from the cache. * ntoskrnl/cc/view.c (CcRosMarkDirtyCacheSegment): New function to mark a cache segment modified while mapped into memory as dirty. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/pin.c (CcMapData, CcUnpinData, CcSetDirtyPinnedData): Store the dirty status in the BCB; don't write back dirty data immediately. 2002-08-14 David Welch <welch@computer2.darkstar.org> * include/ntos/mm.h: Added SEC_XXXX defines from 'Windows NT/2000 Native API Reference' 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/ea.c (VfatSetExtendedAttributes): Empty placeholder for extended attribute functions. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/finfo.c (VfatSetAllocationSizeInformation): Added function to set allocation size. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/fcb.c (vfatFCBInitializeCache): Renamed to vfatFCBInitializeCacheFromVolume. * drivers/fs/vfat/fcb.c (vfatMakeFCBFromDirEntry): Don't initialise the cache with a file object representing the volume unless the FCB is for a directory. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/create.c (VfatPagingFileCreate): Added a new function for handling paging file only code. * drivers/fs/vfat/create.c (VfatSupersedeFile): Added a new function for doing a file supersede. * drivers/fs/vfat/create.c (VfatCreateFile): Reformatted and adjusted control flow. Set allocation size and extended attributes on create. * drivers/fs/vfat/create.c (VfatCreate): Removed goto. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/cleanup.c (VfatCleanupFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/close.c (VfatCloseFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (updEntry): Renamed to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (addEntry): Renamed to VfatAddEntry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * apps/tests/sectest/sectest.c (main): Fixed formatting. svn path=/trunk/; revision=3331
2002-08-15 04:58:39 +08:00
}
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
KeReleaseGuardedMutex(&ViewLock);
KeLeaveCriticalRegion();
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
DPRINT("CcRosFlushDirtyPages() finished\n");
return STATUS_SUCCESS;
2002-08-14 David Welch <welch@computer2.darkstar.org> * subsys/smss/init.c (SmPagingFilesQueryRoutine): If possible take the size of the paging file from the registry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/section.c (MmCreateDataFileSection): Extend the section if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/pagefile.c (NtCreatePagingFile): Set the file size using the FileAllocationInformation class. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/anonmem.c (MmWritePageVirtualMemory): Implemented function to write anonymous memory pages to the swap file. * ntoskrnl/mm/anonmem.c (MmFreeVirtualMemoryPage): Free any swap page associated with the page. * ntoskrnl/mm/mpw.c (MmWriteDirtyPages): New function to find pages to write to disk. * ntoskrnl/mm/mpw.c (MmMpwThreadMain): Implemented MPW functionality. * ntoskrnl/mm/rmap.c (MmWritePagePhysicalAddress): New function to write a single page back to disk. * ntoskrnl/mm/rmap.c (MmSetCleanAllRmaps, MmSetDirtyAllRmaps, MmIsDirtyPageRmap): New rmap function to support the MPW thread. * ntoskrnl/mm/section.c (MmWritePageSectionView): Implemented function to write back section pages. * ntoskrnl/mm/section.c (MmFreeSectionPage): Free any swap entry associated with the page; mark pages shared with the cache as dirty if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/ldr/loader.c (LdrPEProcessModule): Set name of the module into the module text structure. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/io/rw.c (NtReadFile, NtWriteFile): Use the correct test for whether to wait for the completion of i/o. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cm/ntfunc.c (NtFlushKey): Request synchronous i/o from NtOpenFile. * ntoskrnl/cm/regfile (CmiInitPermanentRegistryHive): Request synchronous i/o from NtCreateFile. * ntoskrnl/dbg/kdb_stabs.c (LdrpLoadModuleSymbols): Request synchronous i/o from NtOpenFile. * ntoskrnl/ldr/sysdll.c (LdrpMapSystemDll): Request synchronous i/o from NtOpenFile. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosSuggestFreeCacheSegment): Maintain the correct reference count. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosFlushCacheSegment): New function to write back a modified cache segment. * ntoskrnl/cc/view.c (CcRosFlushDirtyPages): New function to flush some dirty pages from the cache. * ntoskrnl/cc/view.c (CcRosMarkDirtyCacheSegment): New function to mark a cache segment modified while mapped into memory as dirty. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/pin.c (CcMapData, CcUnpinData, CcSetDirtyPinnedData): Store the dirty status in the BCB; don't write back dirty data immediately. 2002-08-14 David Welch <welch@computer2.darkstar.org> * include/ntos/mm.h: Added SEC_XXXX defines from 'Windows NT/2000 Native API Reference' 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/ea.c (VfatSetExtendedAttributes): Empty placeholder for extended attribute functions. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/finfo.c (VfatSetAllocationSizeInformation): Added function to set allocation size. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/fcb.c (vfatFCBInitializeCache): Renamed to vfatFCBInitializeCacheFromVolume. * drivers/fs/vfat/fcb.c (vfatMakeFCBFromDirEntry): Don't initialise the cache with a file object representing the volume unless the FCB is for a directory. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/create.c (VfatPagingFileCreate): Added a new function for handling paging file only code. * drivers/fs/vfat/create.c (VfatSupersedeFile): Added a new function for doing a file supersede. * drivers/fs/vfat/create.c (VfatCreateFile): Reformatted and adjusted control flow. Set allocation size and extended attributes on create. * drivers/fs/vfat/create.c (VfatCreate): Removed goto. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/cleanup.c (VfatCleanupFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/close.c (VfatCloseFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (updEntry): Renamed to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (addEntry): Renamed to VfatAddEntry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * apps/tests/sectest/sectest.c (main): Fixed formatting. svn path=/trunk/; revision=3331
2002-08-15 04:58:39 +08:00
}
NTSTATUS
CcRosTrimCache (
ULONG Target,
ULONG Priority,
PULONG NrFreed)
/*
* FUNCTION: Try to free some memory from the file cache.
* ARGUMENTS:
* Target - The number of pages to be freed.
* Priority - The priority of free (currently unused).
* NrFreed - Points to a variable where the number of pages
* actually freed is returned.
*/
{
PLIST_ENTRY current_entry;
PROS_VACB current;
ULONG PagesFreed;
KIRQL oldIrql;
LIST_ENTRY FreeList;
PFN_NUMBER Page;
ULONG i;
BOOLEAN FlushedPages = FALSE;
DPRINT("CcRosTrimCache(Target %lu)\n", Target);
InitializeListHead(&FreeList);
*NrFreed = 0;
retry:
KeAcquireGuardedMutex(&ViewLock);
current_entry = VacbLruListHead.Flink;
while (current_entry != &VacbLruListHead)
{
current = CONTAINING_RECORD(current_entry,
ROS_VACB,
VacbLruListEntry);
current_entry = current_entry->Flink;
KeAcquireSpinLock(&current->SharedCacheMap->CacheMapLock, &oldIrql);
/* Reference the VACB */
CcRosVacbIncRefCount(current);
/* Check if it's mapped and not dirty */
if (current->MappedCount > 0 && !current->Dirty)
{
/* We have to break these locks because Cc sucks */
KeReleaseSpinLock(&current->SharedCacheMap->CacheMapLock, oldIrql);
KeReleaseGuardedMutex(&ViewLock);
/* Page out the VACB */
for (i = 0; i < VACB_MAPPING_GRANULARITY / PAGE_SIZE; i++)
{
Page = (PFN_NUMBER)(MmGetPhysicalAddress((PUCHAR)current->BaseAddress + (i * PAGE_SIZE)).QuadPart >> PAGE_SHIFT);
MmPageOutPhysicalAddress(Page);
}
/* Reacquire the locks */
KeAcquireGuardedMutex(&ViewLock);
KeAcquireSpinLock(&current->SharedCacheMap->CacheMapLock, &oldIrql);
}
/* Dereference the VACB */
CcRosVacbDecRefCount(current);
/* Check if we can free this entry now */
if (current->ReferenceCount == 0)
{
ASSERT(!current->Dirty);
ASSERT(!current->MappedCount);
RemoveEntryList(&current->CacheMapVacbListEntry);
RemoveEntryList(&current->VacbLruListEntry);
InsertHeadList(&FreeList, &current->CacheMapVacbListEntry);
/* Calculate how many pages we freed for Mm */
PagesFreed = min(VACB_MAPPING_GRANULARITY / PAGE_SIZE, Target);
Target -= PagesFreed;
(*NrFreed) += PagesFreed;
}
KeReleaseSpinLock(&current->SharedCacheMap->CacheMapLock, oldIrql);
}
KeReleaseGuardedMutex(&ViewLock);
/* Try flushing pages if we haven't met our target */
if ((Target > 0) && !FlushedPages)
{
/* Flush dirty pages to disk */
CcRosFlushDirtyPages(Target, &PagesFreed, FALSE, FALSE);
FlushedPages = TRUE;
/* We can only swap as many pages as we flushed */
if (PagesFreed < Target) Target = PagesFreed;
/* Check if we flushed anything */
if (PagesFreed != 0)
{
/* Try again after flushing dirty pages */
DPRINT("Flushed %lu dirty cache pages to disk\n", PagesFreed);
goto retry;
}
}
while (!IsListEmpty(&FreeList))
{
current_entry = RemoveHeadList(&FreeList);
current = CONTAINING_RECORD(current_entry,
ROS_VACB,
CacheMapVacbListEntry);
CcRosInternalFreeVacb(current);
}
DPRINT("Evicted %lu cache pages\n", (*NrFreed));
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
CcRosReleaseVacb (
PROS_SHARED_CACHE_MAP SharedCacheMap,
PROS_VACB Vacb,
BOOLEAN Valid,
BOOLEAN Dirty,
BOOLEAN Mapped)
{
ASSERT(SharedCacheMap);
DPRINT("CcRosReleaseVacb(SharedCacheMap 0x%p, Vacb 0x%p, Valid %u)\n",
SharedCacheMap, Vacb, Valid);
Vacb->Valid = Valid;
if (Dirty && !Vacb->Dirty)
{
CcRosMarkDirtyVacb(Vacb);
}
if (Mapped)
{
Vacb->MappedCount++;
}
CcRosVacbDecRefCount(Vacb);
if (Mapped && (Vacb->MappedCount == 1))
{
CcRosVacbIncRefCount(Vacb);
}
CcRosReleaseVacbLock(Vacb);
return STATUS_SUCCESS;
}
/* Returns with VACB Lock Held! */
PROS_VACB
NTAPI
CcRosLookupVacb (
PROS_SHARED_CACHE_MAP SharedCacheMap,
LONGLONG FileOffset)
{
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
PLIST_ENTRY current_entry;
PROS_VACB current;
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
KIRQL oldIrql;
ASSERT(SharedCacheMap);
DPRINT("CcRosLookupVacb(SharedCacheMap 0x%p, FileOffset %I64u)\n",
SharedCacheMap, FileOffset);
KeAcquireGuardedMutex(&ViewLock);
KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql);
current_entry = SharedCacheMap->CacheMapVacbListHead.Flink;
while (current_entry != &SharedCacheMap->CacheMapVacbListHead)
{
current = CONTAINING_RECORD(current_entry,
ROS_VACB,
CacheMapVacbListEntry);
if (IsPointInRange(current->FileOffset.QuadPart,
VACB_MAPPING_GRANULARITY,
FileOffset))
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
{
CcRosVacbIncRefCount(current);
KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
KeReleaseGuardedMutex(&ViewLock);
CcRosAcquireVacbLock(current, NULL);
return current;
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
}
if (current->FileOffset.QuadPart > FileOffset)
break;
- Okay so...listen up. First off: When you acquire a lock such as a fast mutex, you should never acquire it recursively. For example, when you handle a page fault in a section, then page fault while handling that page fault (which is perfectly okay), you shouldn't be trying to re-acquire the address space lock that you're already holding. After this fix, this scenario works and countless others. Apps like QTInfo now work and load, and PictureViewer doesn't BSOD the system anymore. I've fixed this by changing the lock to a pushlock. It not only increases speed inside the memory manager significantly (such as during page fault handling), but does allow recursive acquisition without any problems. - Now if that wasn't bad enough, here's a couple more tips. Fast Mutexes actually require APC_LEVEL to be effective. If you're going to be using a Fast Mutex and calling it with the "Unsafe" version, then don't expect anything to work. Also, using functions like "CcTryToAcquireBrokenMutex" where correct code is duplicated then hacked to work isn't a big help either. And that's not all. Fast Mutex disables kernel APCs by setting the KernelApcDisable flag on, and it's expected that the count inside the fast mutex will match the count inside the thread. In other words, LOCK ACQUISITION AND RELEASE MUST BE ORDERED. You can't acquire LOCK A and B, and then release lock A and B, because that leads to deadlocks and other issues. So of course, the Cache Manager acquired a view lock, then acquired a segment lock, then released the view lock, then released the segment lock, then re-acquired the view lock. Uh, no, that won't work. You know what else doesn't work so well? Disabling APCs about 6-9 times to acquire a single lock, and using spinlocks in the same code path as well. Just how paranoid are you about thread safety, but still manage to get it wrong? Okay, so we've got recursion, out-of-order lock acquision and release, made-up "broken" acquire functions, and using a lock that depends on APC_LEVEL at PASSIVE_LEVEL. The best part is when Cc builds an array of cache segments, and locks each of them... then during release, the list gets parsed head-first, so the first acquired locks get released first. So locks a, b, c, d get acquired, then a, b, c, d get released. Great! Sounds about right for ReactOS's Cache Manager design. I've changed the view lock to a guarded mutex -- which actually properly disables APCs and works at PASSIVE_LEVEL, and changed the segment locks to be push locks. First it'll be 10 times faster then acquiring a bazillion fast mutexes, especially since APCs have already been disabled at this point, and it also allows you to do most of the stupid things the Cache Manager does. Out-of-order release is still not going to work well, so eventually on a multi-processor machine the code will completely die -- but at least it'll work on UP for now. In the end, this makes things like the Inkscape installer and Quicktime Installer to work, and probably countless other things that generated ASSERTS in the fast mutex code. -- Alex Ionescu svn path=/trunk/; revision=30401
2007-11-13 03:00:26 +08:00
current_entry = current_entry->Flink;
}
KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
KeReleaseGuardedMutex(&ViewLock);
return NULL;
}
VOID
NTAPI
CcRosMarkDirtyVacb (
PROS_VACB Vacb)
2002-08-14 David Welch <welch@computer2.darkstar.org> * subsys/smss/init.c (SmPagingFilesQueryRoutine): If possible take the size of the paging file from the registry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/section.c (MmCreateDataFileSection): Extend the section if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/pagefile.c (NtCreatePagingFile): Set the file size using the FileAllocationInformation class. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/anonmem.c (MmWritePageVirtualMemory): Implemented function to write anonymous memory pages to the swap file. * ntoskrnl/mm/anonmem.c (MmFreeVirtualMemoryPage): Free any swap page associated with the page. * ntoskrnl/mm/mpw.c (MmWriteDirtyPages): New function to find pages to write to disk. * ntoskrnl/mm/mpw.c (MmMpwThreadMain): Implemented MPW functionality. * ntoskrnl/mm/rmap.c (MmWritePagePhysicalAddress): New function to write a single page back to disk. * ntoskrnl/mm/rmap.c (MmSetCleanAllRmaps, MmSetDirtyAllRmaps, MmIsDirtyPageRmap): New rmap function to support the MPW thread. * ntoskrnl/mm/section.c (MmWritePageSectionView): Implemented function to write back section pages. * ntoskrnl/mm/section.c (MmFreeSectionPage): Free any swap entry associated with the page; mark pages shared with the cache as dirty if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/ldr/loader.c (LdrPEProcessModule): Set name of the module into the module text structure. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/io/rw.c (NtReadFile, NtWriteFile): Use the correct test for whether to wait for the completion of i/o. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cm/ntfunc.c (NtFlushKey): Request synchronous i/o from NtOpenFile. * ntoskrnl/cm/regfile (CmiInitPermanentRegistryHive): Request synchronous i/o from NtCreateFile. * ntoskrnl/dbg/kdb_stabs.c (LdrpLoadModuleSymbols): Request synchronous i/o from NtOpenFile. * ntoskrnl/ldr/sysdll.c (LdrpMapSystemDll): Request synchronous i/o from NtOpenFile. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosSuggestFreeCacheSegment): Maintain the correct reference count. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosFlushCacheSegment): New function to write back a modified cache segment. * ntoskrnl/cc/view.c (CcRosFlushDirtyPages): New function to flush some dirty pages from the cache. * ntoskrnl/cc/view.c (CcRosMarkDirtyCacheSegment): New function to mark a cache segment modified while mapped into memory as dirty. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/pin.c (CcMapData, CcUnpinData, CcSetDirtyPinnedData): Store the dirty status in the BCB; don't write back dirty data immediately. 2002-08-14 David Welch <welch@computer2.darkstar.org> * include/ntos/mm.h: Added SEC_XXXX defines from 'Windows NT/2000 Native API Reference' 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/ea.c (VfatSetExtendedAttributes): Empty placeholder for extended attribute functions. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/finfo.c (VfatSetAllocationSizeInformation): Added function to set allocation size. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/fcb.c (vfatFCBInitializeCache): Renamed to vfatFCBInitializeCacheFromVolume. * drivers/fs/vfat/fcb.c (vfatMakeFCBFromDirEntry): Don't initialise the cache with a file object representing the volume unless the FCB is for a directory. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/create.c (VfatPagingFileCreate): Added a new function for handling paging file only code. * drivers/fs/vfat/create.c (VfatSupersedeFile): Added a new function for doing a file supersede. * drivers/fs/vfat/create.c (VfatCreateFile): Reformatted and adjusted control flow. Set allocation size and extended attributes on create. * drivers/fs/vfat/create.c (VfatCreate): Removed goto. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/cleanup.c (VfatCleanupFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/close.c (VfatCloseFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (updEntry): Renamed to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (addEntry): Renamed to VfatAddEntry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * apps/tests/sectest/sectest.c (main): Fixed formatting. svn path=/trunk/; revision=3331
2002-08-15 04:58:39 +08:00
{
KIRQL oldIrql;
PROS_SHARED_CACHE_MAP SharedCacheMap;
SharedCacheMap = Vacb->SharedCacheMap;
KeAcquireGuardedMutex(&ViewLock);
KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql);
ASSERT(!Vacb->Dirty);
InsertTailList(&DirtyVacbListHead, &Vacb->DirtyVacbListEntry);
CcTotalDirtyPages += VACB_MAPPING_GRANULARITY / PAGE_SIZE;
Vacb->SharedCacheMap->DirtyPages += VACB_MAPPING_GRANULARITY / PAGE_SIZE;
CcRosVacbIncRefCount(Vacb);
2002-08-14 David Welch <welch@computer2.darkstar.org> * subsys/smss/init.c (SmPagingFilesQueryRoutine): If possible take the size of the paging file from the registry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/section.c (MmCreateDataFileSection): Extend the section if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/pagefile.c (NtCreatePagingFile): Set the file size using the FileAllocationInformation class. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/anonmem.c (MmWritePageVirtualMemory): Implemented function to write anonymous memory pages to the swap file. * ntoskrnl/mm/anonmem.c (MmFreeVirtualMemoryPage): Free any swap page associated with the page. * ntoskrnl/mm/mpw.c (MmWriteDirtyPages): New function to find pages to write to disk. * ntoskrnl/mm/mpw.c (MmMpwThreadMain): Implemented MPW functionality. * ntoskrnl/mm/rmap.c (MmWritePagePhysicalAddress): New function to write a single page back to disk. * ntoskrnl/mm/rmap.c (MmSetCleanAllRmaps, MmSetDirtyAllRmaps, MmIsDirtyPageRmap): New rmap function to support the MPW thread. * ntoskrnl/mm/section.c (MmWritePageSectionView): Implemented function to write back section pages. * ntoskrnl/mm/section.c (MmFreeSectionPage): Free any swap entry associated with the page; mark pages shared with the cache as dirty if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/ldr/loader.c (LdrPEProcessModule): Set name of the module into the module text structure. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/io/rw.c (NtReadFile, NtWriteFile): Use the correct test for whether to wait for the completion of i/o. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cm/ntfunc.c (NtFlushKey): Request synchronous i/o from NtOpenFile. * ntoskrnl/cm/regfile (CmiInitPermanentRegistryHive): Request synchronous i/o from NtCreateFile. * ntoskrnl/dbg/kdb_stabs.c (LdrpLoadModuleSymbols): Request synchronous i/o from NtOpenFile. * ntoskrnl/ldr/sysdll.c (LdrpMapSystemDll): Request synchronous i/o from NtOpenFile. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosSuggestFreeCacheSegment): Maintain the correct reference count. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosFlushCacheSegment): New function to write back a modified cache segment. * ntoskrnl/cc/view.c (CcRosFlushDirtyPages): New function to flush some dirty pages from the cache. * ntoskrnl/cc/view.c (CcRosMarkDirtyCacheSegment): New function to mark a cache segment modified while mapped into memory as dirty. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/pin.c (CcMapData, CcUnpinData, CcSetDirtyPinnedData): Store the dirty status in the BCB; don't write back dirty data immediately. 2002-08-14 David Welch <welch@computer2.darkstar.org> * include/ntos/mm.h: Added SEC_XXXX defines from 'Windows NT/2000 Native API Reference' 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/ea.c (VfatSetExtendedAttributes): Empty placeholder for extended attribute functions. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/finfo.c (VfatSetAllocationSizeInformation): Added function to set allocation size. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/fcb.c (vfatFCBInitializeCache): Renamed to vfatFCBInitializeCacheFromVolume. * drivers/fs/vfat/fcb.c (vfatMakeFCBFromDirEntry): Don't initialise the cache with a file object representing the volume unless the FCB is for a directory. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/create.c (VfatPagingFileCreate): Added a new function for handling paging file only code. * drivers/fs/vfat/create.c (VfatSupersedeFile): Added a new function for doing a file supersede. * drivers/fs/vfat/create.c (VfatCreateFile): Reformatted and adjusted control flow. Set allocation size and extended attributes on create. * drivers/fs/vfat/create.c (VfatCreate): Removed goto. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/cleanup.c (VfatCleanupFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/close.c (VfatCloseFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (updEntry): Renamed to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (addEntry): Renamed to VfatAddEntry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * apps/tests/sectest/sectest.c (main): Fixed formatting. svn path=/trunk/; revision=3331
2002-08-15 04:58:39 +08:00
/* Move to the tail of the LRU list */
RemoveEntryList(&Vacb->VacbLruListEntry);
InsertTailList(&VacbLruListHead, &Vacb->VacbLruListEntry);
Vacb->Dirty = TRUE;
KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
KeReleaseGuardedMutex(&ViewLock);
/* Schedule a lazy writer run to now that we have dirty VACB */
oldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
if (!LazyWriter.ScanActive)
{
CcScheduleLazyWriteScan(FALSE);
}
KeReleaseQueuedSpinLock(LockQueueMasterLock, oldIrql);
}
VOID
NTAPI
CcRosUnmarkDirtyVacb (
PROS_VACB Vacb,
BOOLEAN LockViews)
{
KIRQL oldIrql;
PROS_SHARED_CACHE_MAP SharedCacheMap;
SharedCacheMap = Vacb->SharedCacheMap;
if (LockViews)
{
KeAcquireGuardedMutex(&ViewLock);
KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql);
}
ASSERT(Vacb->Dirty);
Vacb->Dirty = FALSE;
RemoveEntryList(&Vacb->DirtyVacbListEntry);
CcTotalDirtyPages -= VACB_MAPPING_GRANULARITY / PAGE_SIZE;
Vacb->SharedCacheMap->DirtyPages -= VACB_MAPPING_GRANULARITY / PAGE_SIZE;
CcRosVacbDecRefCount(Vacb);
if (LockViews)
{
KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
KeReleaseGuardedMutex(&ViewLock);
}
}
NTSTATUS
NTAPI
CcRosMarkDirtyFile (
PROS_SHARED_CACHE_MAP SharedCacheMap,
LONGLONG FileOffset)
{
PROS_VACB Vacb;
ASSERT(SharedCacheMap);
DPRINT("CcRosMarkDirtyVacb(SharedCacheMap 0x%p, FileOffset %I64u)\n",
SharedCacheMap, FileOffset);
Vacb = CcRosLookupVacb(SharedCacheMap, FileOffset);
if (Vacb == NULL)
{
KeBugCheck(CACHE_MANAGER);
}
if (!Vacb->Dirty)
{
CcRosMarkDirtyVacb(Vacb);
}
CcRosReleaseVacbLock(Vacb);
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
CcRosUnmapVacb (
PROS_SHARED_CACHE_MAP SharedCacheMap,
LONGLONG FileOffset,
BOOLEAN NowDirty)
{
PROS_VACB Vacb;
ASSERT(SharedCacheMap);
DPRINT("CcRosUnmapVacb(SharedCacheMap 0x%p, FileOffset %I64u, NowDirty %u)\n",
SharedCacheMap, FileOffset, NowDirty);
Vacb = CcRosLookupVacb(SharedCacheMap, FileOffset);
if (Vacb == NULL)
{
return STATUS_UNSUCCESSFUL;
}
if (NowDirty && !Vacb->Dirty)
{
CcRosMarkDirtyVacb(Vacb);
}
ASSERT(Vacb->MappedCount != 0);
Vacb->MappedCount--;
CcRosVacbDecRefCount(Vacb);
if (Vacb->MappedCount == 0)
{
CcRosVacbDecRefCount(Vacb);
}
CcRosReleaseVacbLock(Vacb);
return STATUS_SUCCESS;
}
static
NTSTATUS
CcRosMapVacb(
PROS_VACB Vacb)
{
ULONG i;
NTSTATUS Status;
ULONG_PTR NumberOfPages;
/* Create a memory area. */
MmLockAddressSpace(MmGetKernelAddressSpace());
Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
0, // nothing checks for VACB mareas, so set to 0
&Vacb->BaseAddress,
VACB_MAPPING_GRANULARITY,
PAGE_READWRITE,
(PMEMORY_AREA*)&Vacb->MemoryArea,
0,
PAGE_SIZE);
MmUnlockAddressSpace(MmGetKernelAddressSpace());
if (!NT_SUCCESS(Status))
{
DPRINT1("MmCreateMemoryArea failed with %lx for VACB %p\n", Status, Vacb);
return Status;
}
ASSERT(((ULONG_PTR)Vacb->BaseAddress % PAGE_SIZE) == 0);
ASSERT((ULONG_PTR)Vacb->BaseAddress > (ULONG_PTR)MmSystemRangeStart);
/* Create a virtual mapping for this memory area */
NumberOfPages = BYTES_TO_PAGES(VACB_MAPPING_GRANULARITY);
for (i = 0; i < NumberOfPages; i++)
{
PFN_NUMBER PageFrameNumber;
MI_SET_USAGE(MI_USAGE_CACHE);
Status = MmRequestPageMemoryConsumer(MC_CACHE, TRUE, &PageFrameNumber);
if (PageFrameNumber == 0)
{
DPRINT1("Unable to allocate page\n");
KeBugCheck(MEMORY_MANAGEMENT);
}
Status = MmCreateVirtualMapping(NULL,
(PVOID)((ULONG_PTR)Vacb->BaseAddress + (i * PAGE_SIZE)),
PAGE_READWRITE,
&PageFrameNumber,
1);
if (!NT_SUCCESS(Status))
{
DPRINT1("Unable to create virtual mapping\n");
KeBugCheck(MEMORY_MANAGEMENT);
}
}
return STATUS_SUCCESS;
}
static
NTSTATUS
CcRosCreateVacb (
PROS_SHARED_CACHE_MAP SharedCacheMap,
LONGLONG FileOffset,
PROS_VACB *Vacb)
{
PROS_VACB current;
PROS_VACB previous;
PLIST_ENTRY current_entry;
NTSTATUS Status;
KIRQL oldIrql;
ASSERT(SharedCacheMap);
DPRINT("CcRosCreateVacb()\n");
if (FileOffset >= SharedCacheMap->SectionSize.QuadPart)
{
*Vacb = NULL;
return STATUS_INVALID_PARAMETER;
}
current = ExAllocateFromNPagedLookasideList(&VacbLookasideList);
current->BaseAddress = NULL;
current->Valid = FALSE;
current->Dirty = FALSE;
current->PageOut = FALSE;
current->FileOffset.QuadPart = ROUND_DOWN(FileOffset, VACB_MAPPING_GRANULARITY);
current->SharedCacheMap = SharedCacheMap;
#if DBG
if (SharedCacheMap->Trace)
{
DPRINT1("CacheMap 0x%p: new VACB: 0x%p\n", SharedCacheMap, current);
}
#endif
current->MappedCount = 0;
current->DirtyVacbListEntry.Flink = NULL;
current->DirtyVacbListEntry.Blink = NULL;
current->ReferenceCount = 1;
2016-05-26 20:09:05 +08:00
current->PinCount = 0;
KeInitializeMutex(&current->Mutex, 0);
CcRosAcquireVacbLock(current, NULL);
KeAcquireGuardedMutex(&ViewLock);
*Vacb = current;
/* There is window between the call to CcRosLookupVacb
* and CcRosCreateVacb. We must check if a VACB for the
* file offset exist. If there is a VACB, we release
* our newly created VACB and return the existing one.
*/
KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql);
current_entry = SharedCacheMap->CacheMapVacbListHead.Flink;
previous = NULL;
while (current_entry != &SharedCacheMap->CacheMapVacbListHead)
{
current = CONTAINING_RECORD(current_entry,
ROS_VACB,
CacheMapVacbListEntry);
if (IsPointInRange(current->FileOffset.QuadPart,
VACB_MAPPING_GRANULARITY,
FileOffset))
{
CcRosVacbIncRefCount(current);
KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
#if DBG
if (SharedCacheMap->Trace)
{
DPRINT1("CacheMap 0x%p: deleting newly created VACB 0x%p ( found existing one 0x%p )\n",
SharedCacheMap,
(*Vacb),
current);
}
#endif
CcRosReleaseVacbLock(*Vacb);
KeReleaseGuardedMutex(&ViewLock);
ExFreeToNPagedLookasideList(&VacbLookasideList, *Vacb);
*Vacb = current;
CcRosAcquireVacbLock(current, NULL);
return STATUS_SUCCESS;
}
if (current->FileOffset.QuadPart < FileOffset)
{
ASSERT(previous == NULL ||
previous->FileOffset.QuadPart < current->FileOffset.QuadPart);
previous = current;
}
if (current->FileOffset.QuadPart > FileOffset)
break;
current_entry = current_entry->Flink;
}
/* There was no existing VACB. */
current = *Vacb;
if (previous)
{
InsertHeadList(&previous->CacheMapVacbListEntry, &current->CacheMapVacbListEntry);
}
else
{
InsertHeadList(&SharedCacheMap->CacheMapVacbListHead, &current->CacheMapVacbListEntry);
}
KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
InsertTailList(&VacbLruListHead, &current->VacbLruListEntry);
KeReleaseGuardedMutex(&ViewLock);
MI_SET_USAGE(MI_USAGE_CACHE);
#if MI_TRACE_PFNS
if ((SharedCacheMap->FileObject) && (SharedCacheMap->FileObject->FileName.Buffer))
{
PWCHAR pos;
ULONG len = 0;
pos = wcsrchr(SharedCacheMap->FileObject->FileName.Buffer, '\\');
if (pos)
{
len = wcslen(pos) * sizeof(WCHAR);
snprintf(MI_PFN_CURRENT_PROCESS_NAME, min(16, len), "%S", pos);
}
else
{
snprintf(MI_PFN_CURRENT_PROCESS_NAME, min(16, len), "%wZ", &SharedCacheMap->FileObject->FileName);
}
}
#endif
Status = CcRosMapVacb(current);
if (!NT_SUCCESS(Status))
{
RemoveEntryList(&current->CacheMapVacbListEntry);
RemoveEntryList(&current->VacbLruListEntry);
CcRosReleaseVacbLock(current);
ExFreeToNPagedLookasideList(&VacbLookasideList, current);
}
return Status;
}
NTSTATUS
NTAPI
CcRosGetVacb (
PROS_SHARED_CACHE_MAP SharedCacheMap,
LONGLONG FileOffset,
PLONGLONG BaseOffset,
PVOID* BaseAddress,
PBOOLEAN UptoDate,
PROS_VACB *Vacb)
{
PROS_VACB current;
NTSTATUS Status;
ASSERT(SharedCacheMap);
DPRINT("CcRosGetVacb()\n");
/*
* Look for a VACB already mapping the same data.
*/
current = CcRosLookupVacb(SharedCacheMap, FileOffset);
if (current == NULL)
{
/*
* Otherwise create a new VACB.
*/
Status = CcRosCreateVacb(SharedCacheMap, FileOffset, &current);
if (!NT_SUCCESS(Status))
{
return Status;
}
}
KeAcquireGuardedMutex(&ViewLock);
/* Move to the tail of the LRU list */
RemoveEntryList(&current->VacbLruListEntry);
InsertTailList(&VacbLruListHead, &current->VacbLruListEntry);
KeReleaseGuardedMutex(&ViewLock);
/*
* Return information about the VACB to the caller.
*/
*UptoDate = current->Valid;
*BaseAddress = current->BaseAddress;
DPRINT("*BaseAddress %p\n", *BaseAddress);
*Vacb = current;
*BaseOffset = current->FileOffset.QuadPart;
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
CcRosRequestVacb (
PROS_SHARED_CACHE_MAP SharedCacheMap,
LONGLONG FileOffset,
PVOID* BaseAddress,
PBOOLEAN UptoDate,
PROS_VACB *Vacb)
/*
* FUNCTION: Request a page mapping for a shared cache map
*/
{
LONGLONG BaseOffset;
ASSERT(SharedCacheMap);
if (FileOffset % VACB_MAPPING_GRANULARITY != 0)
{
DPRINT1("Bad fileoffset %I64x should be multiple of %x",
FileOffset, VACB_MAPPING_GRANULARITY);
KeBugCheck(CACHE_MANAGER);
}
return CcRosGetVacb(SharedCacheMap,
FileOffset,
&BaseOffset,
BaseAddress,
UptoDate,
Vacb);
}
static
VOID
CcFreeCachePage (
PVOID Context,
MEMORY_AREA* MemoryArea,
PVOID Address,
PFN_NUMBER Page,
SWAPENTRY SwapEntry,
BOOLEAN Dirty)
{
ASSERT(SwapEntry == 0);
if (Page != 0)
{
ASSERT(MmGetReferenceCountPage(Page) == 1);
MmReleasePageMemoryConsumer(MC_CACHE, Page);
}
}
NTSTATUS
CcRosInternalFreeVacb (
PROS_VACB Vacb)
/*
* FUNCTION: Releases a VACB associated with a shared cache map
*/
{
DPRINT("Freeing VACB 0x%p\n", Vacb);
#if DBG
if (Vacb->SharedCacheMap->Trace)
{
DPRINT1("CacheMap 0x%p: deleting VACB: 0x%p\n", Vacb->SharedCacheMap, Vacb);
}
#endif
MmLockAddressSpace(MmGetKernelAddressSpace());
MmFreeMemoryArea(MmGetKernelAddressSpace(),
Vacb->MemoryArea,
CcFreeCachePage,
NULL);
MmUnlockAddressSpace(MmGetKernelAddressSpace());
ExFreeToNPagedLookasideList(&VacbLookasideList, Vacb);
return STATUS_SUCCESS;
}
/*
* @implemented
*/
VOID
NTAPI
CcFlushCache (
IN PSECTION_OBJECT_POINTERS SectionObjectPointers,
IN PLARGE_INTEGER FileOffset OPTIONAL,
IN ULONG Length,
OUT PIO_STATUS_BLOCK IoStatus)
{
PROS_SHARED_CACHE_MAP SharedCacheMap;
LARGE_INTEGER Offset;
LONGLONG RemainingLength;
PROS_VACB current;
NTSTATUS Status;
KIRQL oldIrql;
CCTRACE(CC_API_DEBUG, "SectionObjectPointers=%p FileOffset=%p Length=%lu\n",
SectionObjectPointers, FileOffset, Length);
DPRINT("CcFlushCache(SectionObjectPointers 0x%p, FileOffset 0x%p, Length %lu, IoStatus 0x%p)\n",
SectionObjectPointers, FileOffset, Length, IoStatus);
if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap)
{
SharedCacheMap = SectionObjectPointers->SharedCacheMap;
ASSERT(SharedCacheMap);
if (FileOffset)
{
Offset = *FileOffset;
RemainingLength = Length;
}
else
{
Offset.QuadPart = 0;
RemainingLength = SharedCacheMap->FileSize.QuadPart;
}
if (IoStatus)
{
IoStatus->Status = STATUS_SUCCESS;
IoStatus->Information = 0;
}
while (RemainingLength > 0)
{
current = CcRosLookupVacb(SharedCacheMap, Offset.QuadPart);
if (current != NULL)
{
if (current->Dirty)
{
Status = CcRosFlushVacb(current);
if (!NT_SUCCESS(Status) && IoStatus != NULL)
{
IoStatus->Status = Status;
}
}
2016-05-26 20:09:05 +08:00
CcRosReleaseVacbLock(current);
KeAcquireGuardedMutex(&ViewLock);
KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql);
CcRosVacbDecRefCount(current);
KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
KeReleaseGuardedMutex(&ViewLock);
}
Offset.QuadPart += VACB_MAPPING_GRANULARITY;
RemainingLength -= min(RemainingLength, VACB_MAPPING_GRANULARITY);
}
}
else
{
if (IoStatus)
{
IoStatus->Status = STATUS_INVALID_PARAMETER;
}
}
}
NTSTATUS
NTAPI
CcRosDeleteFileCache (
PFILE_OBJECT FileObject,
PROS_SHARED_CACHE_MAP SharedCacheMap)
/*
* FUNCTION: Releases the shared cache map associated with a file object
*/
{
PLIST_ENTRY current_entry;
PROS_VACB current;
LIST_ENTRY FreeList;
KIRQL oldIrql;
ASSERT(SharedCacheMap);
SharedCacheMap->OpenCount++;
KeReleaseGuardedMutex(&ViewLock);
CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, NULL);
KeAcquireGuardedMutex(&ViewLock);
SharedCacheMap->OpenCount--;
if (SharedCacheMap->OpenCount == 0)
{
KIRQL OldIrql;
FileObject->SectionObjectPointer->SharedCacheMap = NULL;
/*
* Release all VACBs
*/
InitializeListHead(&FreeList);
KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql);
while (!IsListEmpty(&SharedCacheMap->CacheMapVacbListHead))
{
current_entry = RemoveTailList(&SharedCacheMap->CacheMapVacbListHead);
KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
current = CONTAINING_RECORD(current_entry, ROS_VACB, CacheMapVacbListEntry);
CcRosAcquireVacbLock(current, NULL);
RemoveEntryList(&current->VacbLruListEntry);
if (current->Dirty)
{
KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql);
CcRosUnmarkDirtyVacb(current, FALSE);
KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
DPRINT1("Freeing dirty VACB\n");
}
InsertHeadList(&FreeList, &current->CacheMapVacbListEntry);
CcRosReleaseVacbLock(current);
KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql);
}
#if DBG
SharedCacheMap->Trace = FALSE;
#endif
KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
KeReleaseGuardedMutex(&ViewLock);
ObDereferenceObject(SharedCacheMap->FileObject);
while (!IsListEmpty(&FreeList))
{
current_entry = RemoveTailList(&FreeList);
current = CONTAINING_RECORD(current_entry, ROS_VACB, CacheMapVacbListEntry);
CcRosInternalFreeVacb(current);
}
OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
RemoveEntryList(&SharedCacheMap->SharedCacheMapLinks);
KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
ExFreeToNPagedLookasideList(&SharedCacheMapLookasideList, SharedCacheMap);
KeAcquireGuardedMutex(&ViewLock);
}
return STATUS_SUCCESS;
}
VOID
NTAPI
CcRosReferenceCache (
PFILE_OBJECT FileObject)
{
PROS_SHARED_CACHE_MAP SharedCacheMap;
KeAcquireGuardedMutex(&ViewLock);
SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
ASSERT(SharedCacheMap);
ASSERT(SharedCacheMap->OpenCount != 0);
SharedCacheMap->OpenCount++;
KeReleaseGuardedMutex(&ViewLock);
}
VOID
NTAPI
CcRosRemoveIfClosed (
PSECTION_OBJECT_POINTERS SectionObjectPointer)
{
PROS_SHARED_CACHE_MAP SharedCacheMap;
DPRINT("CcRosRemoveIfClosed()\n");
KeAcquireGuardedMutex(&ViewLock);
SharedCacheMap = SectionObjectPointer->SharedCacheMap;
if (SharedCacheMap && SharedCacheMap->OpenCount == 0)
{
CcRosDeleteFileCache(SharedCacheMap->FileObject, SharedCacheMap);
}
KeReleaseGuardedMutex(&ViewLock);
}
VOID
NTAPI
CcRosDereferenceCache (
PFILE_OBJECT FileObject)
{
PROS_SHARED_CACHE_MAP SharedCacheMap;
KeAcquireGuardedMutex(&ViewLock);
SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
ASSERT(SharedCacheMap);
if (SharedCacheMap->OpenCount > 0)
{
SharedCacheMap->OpenCount--;
if (SharedCacheMap->OpenCount == 0)
{
MmFreeSectionSegments(SharedCacheMap->FileObject);
CcRosDeleteFileCache(FileObject, SharedCacheMap);
}
}
KeReleaseGuardedMutex(&ViewLock);
}
NTSTATUS
NTAPI
CcRosReleaseFileCache (
PFILE_OBJECT FileObject)
2002-08-08 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/section (NtQuerySection): Return the right result length. 2002-08-08 David Welch <welch@computer2.darkstar.org> * ntoskrnl/ke/usertrap.c (print_user_address): Check for a NULL LDR structure in the PEB; copy the LDR pointer in safely. 2002-08-08 David Welch <welch@computer2.darkstar.org> * ntoskrnl/ke/apc.c (KiDeliverUserApc): Deliver all present APCs; release the APC spinlock while acccessing user memory. 2002-08-08 David Welch <welch@computer2.darkstar.org> * include/internal/ps.h: Adjusted offsets into the ETHREAD structure. * include/internal/ps.h: Removed redundant members from the KTHREAD structure. * ntoskrnl/ke/kthread.c (KeInitializeThread): Removed redundant members from the KTHREAD structure. 2002-08-08 David Welch <welch@computer2.darkstar.org> * ntoskrnl/dbg/kdb.c (KdbEnterDebuggerException): New function to enter the debugger on an exception. * ntoskrnl/kd/kdebug.c (KdInitSystem): Initialize the local kernel debugger if enabled. * ntoskrnl/ke/catch.c (KiDispatchException): Enter the local kernel debugger on an exception. 2002-08-08 David Welch <welch@computer2.darkstar.org> * include/ntdll/ldr.h: Added definition for a DLL entrypoint. * lib/kernel32/process/create.c (KlCreateFirstThread): Put the argument to the NtProcessStartup function on the stack. * lib/kernel32/process/create.c (KlInitPeb): Read the base address of the new image from the PEB. * lib/kernel32/process/create.c (CreateProcessW): Start the first thread at the entrypoint of the new image. * lib/ntdll/ldr/startup.c (LdrInitializeThunk): If the function is called after the initial startup then just call the entrypoints for the loaded DLLs with DLL_THREAD_ATTACH. Don't call the entrypoint of the image. * lib/ntdll/rtl/process.c (RtlpCreateFirstThread): Put the argument to the NtProcessStartup function on the stack. * lib/ntdll/rtl/process.c (KlInitPeb): Read the base address of the new image from the PEB. * lib/ntdll/rtl/process.c (RtlCreateUserProcess): Start the first thread at the entrypoint of the new image. * ntoskrnl/ke/i386/bthread.S (PsBeginThreadWithContextInternal): Use the system call path to begin a usermode thread. * ntoskrnl/ke/i386/thread.c (Ke386InitThreadWithContext): Convert the supplied context into a trap frame. * ntoskrnl/ldr/init.c (LdrLoadInitialProcess): Put the PEB argument to the NtProcessStartup function on the new stack; start the first thread at the entrypoint of the image. * ntoskrnl/ps/create.c (NtCreateThread): Create an APC to call LdrInitializeThunk in the context of a new thread before its entrypoint. 2002-08-08 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/cleanup.c (VfatCleanupFile): Uninitialise the cache on file cleanup. * drivers/fs/vfat/fcb.c (vfatReleaseFcb): Don't uninitialise the cache on file close. * ntoskrnl/cc/copy.c: Renamed zero page global variable. * ntoskrnl/cc/view.c: Added cache delete function. svn path=/trunk/; revision=3323
2002-08-09 01:54:16 +08:00
/*
* FUNCTION: Called by the file system when a handle to a file object
* has been closed.
*/
{
KIRQL OldIrql;
PPRIVATE_CACHE_MAP PrivateMap;
PROS_SHARED_CACHE_MAP SharedCacheMap;
KeAcquireGuardedMutex(&ViewLock);
if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
{
SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
/* Closing the handle, so kill the private cache map
* Before you event try to remove it from FO, always
* lock the master lock, to be sure not to race
* with a potential read ahead ongoing!
*/
OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
PrivateMap = FileObject->PrivateCacheMap;
FileObject->PrivateCacheMap = NULL;
KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
if (PrivateMap != NULL)
{
/* Remove it from the file */
KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql);
RemoveEntryList(&PrivateMap->PrivateLinks);
KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
/* And free it. */
ExFreePoolWithTag(PrivateMap, TAG_PRIVATE_CACHE_MAP);
if (SharedCacheMap->OpenCount > 0)
{
SharedCacheMap->OpenCount--;
if (SharedCacheMap->OpenCount == 0)
{
MmFreeSectionSegments(SharedCacheMap->FileObject);
CcRosDeleteFileCache(FileObject, SharedCacheMap);
}
}
}
}
KeReleaseGuardedMutex(&ViewLock);
return STATUS_SUCCESS;
2002-08-08 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/section (NtQuerySection): Return the right result length. 2002-08-08 David Welch <welch@computer2.darkstar.org> * ntoskrnl/ke/usertrap.c (print_user_address): Check for a NULL LDR structure in the PEB; copy the LDR pointer in safely. 2002-08-08 David Welch <welch@computer2.darkstar.org> * ntoskrnl/ke/apc.c (KiDeliverUserApc): Deliver all present APCs; release the APC spinlock while acccessing user memory. 2002-08-08 David Welch <welch@computer2.darkstar.org> * include/internal/ps.h: Adjusted offsets into the ETHREAD structure. * include/internal/ps.h: Removed redundant members from the KTHREAD structure. * ntoskrnl/ke/kthread.c (KeInitializeThread): Removed redundant members from the KTHREAD structure. 2002-08-08 David Welch <welch@computer2.darkstar.org> * ntoskrnl/dbg/kdb.c (KdbEnterDebuggerException): New function to enter the debugger on an exception. * ntoskrnl/kd/kdebug.c (KdInitSystem): Initialize the local kernel debugger if enabled. * ntoskrnl/ke/catch.c (KiDispatchException): Enter the local kernel debugger on an exception. 2002-08-08 David Welch <welch@computer2.darkstar.org> * include/ntdll/ldr.h: Added definition for a DLL entrypoint. * lib/kernel32/process/create.c (KlCreateFirstThread): Put the argument to the NtProcessStartup function on the stack. * lib/kernel32/process/create.c (KlInitPeb): Read the base address of the new image from the PEB. * lib/kernel32/process/create.c (CreateProcessW): Start the first thread at the entrypoint of the new image. * lib/ntdll/ldr/startup.c (LdrInitializeThunk): If the function is called after the initial startup then just call the entrypoints for the loaded DLLs with DLL_THREAD_ATTACH. Don't call the entrypoint of the image. * lib/ntdll/rtl/process.c (RtlpCreateFirstThread): Put the argument to the NtProcessStartup function on the stack. * lib/ntdll/rtl/process.c (KlInitPeb): Read the base address of the new image from the PEB. * lib/ntdll/rtl/process.c (RtlCreateUserProcess): Start the first thread at the entrypoint of the new image. * ntoskrnl/ke/i386/bthread.S (PsBeginThreadWithContextInternal): Use the system call path to begin a usermode thread. * ntoskrnl/ke/i386/thread.c (Ke386InitThreadWithContext): Convert the supplied context into a trap frame. * ntoskrnl/ldr/init.c (LdrLoadInitialProcess): Put the PEB argument to the NtProcessStartup function on the new stack; start the first thread at the entrypoint of the image. * ntoskrnl/ps/create.c (NtCreateThread): Create an APC to call LdrInitializeThunk in the context of a new thread before its entrypoint. 2002-08-08 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/cleanup.c (VfatCleanupFile): Uninitialise the cache on file cleanup. * drivers/fs/vfat/fcb.c (vfatReleaseFcb): Don't uninitialise the cache on file close. * ntoskrnl/cc/copy.c: Renamed zero page global variable. * ntoskrnl/cc/view.c: Added cache delete function. svn path=/trunk/; revision=3323
2002-08-09 01:54:16 +08:00
}
NTSTATUS
NTAPI
CcRosInitializeFileCache (
PFILE_OBJECT FileObject,
PCC_FILE_SIZES FileSizes,
BOOLEAN PinAccess,
PCACHE_MANAGER_CALLBACKS CallBacks,
PVOID LazyWriterContext)
/*
* FUNCTION: Initializes a shared cache map for a file object
*/
{
KIRQL OldIrql;
BOOLEAN Allocated;
PROS_SHARED_CACHE_MAP SharedCacheMap;
SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
DPRINT("CcRosInitializeFileCache(FileObject 0x%p, SharedCacheMap 0x%p)\n",
FileObject, SharedCacheMap);
Allocated = FALSE;
KeAcquireGuardedMutex(&ViewLock);
if (SharedCacheMap == NULL)
{
Allocated = TRUE;
SharedCacheMap = ExAllocateFromNPagedLookasideList(&SharedCacheMapLookasideList);
if (SharedCacheMap == NULL)
{
KeReleaseGuardedMutex(&ViewLock);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(SharedCacheMap, sizeof(*SharedCacheMap));
ObReferenceObjectByPointer(FileObject,
FILE_ALL_ACCESS,
NULL,
KernelMode);
2018-02-08 18:02:07 +08:00
SharedCacheMap->NodeTypeCode = NODE_TYPE_SHARED_MAP;
SharedCacheMap->NodeByteSize = sizeof(*SharedCacheMap);
SharedCacheMap->FileObject = FileObject;
SharedCacheMap->Callbacks = CallBacks;
SharedCacheMap->LazyWriteContext = LazyWriterContext;
SharedCacheMap->SectionSize = FileSizes->AllocationSize;
SharedCacheMap->FileSize = FileSizes->FileSize;
SharedCacheMap->PinAccess = PinAccess;
SharedCacheMap->DirtyPageThreshold = 0;
SharedCacheMap->DirtyPages = 0;
InitializeListHead(&SharedCacheMap->PrivateList);
KeInitializeSpinLock(&SharedCacheMap->CacheMapLock);
InitializeListHead(&SharedCacheMap->CacheMapVacbListHead);
FileObject->SectionObjectPointer->SharedCacheMap = SharedCacheMap;
OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
InsertTailList(&CcCleanSharedCacheMapList, &SharedCacheMap->SharedCacheMapLinks);
KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
}
if (FileObject->PrivateCacheMap == NULL)
{
PPRIVATE_CACHE_MAP PrivateMap;
/* Allocate the private cache map for this handle */
2018-02-08 18:02:07 +08:00
PrivateMap = ExAllocatePoolWithTag(NonPagedPool, sizeof(PRIVATE_CACHE_MAP), TAG_PRIVATE_CACHE_MAP);
if (PrivateMap == NULL)
{
/* If we also allocated the shared cache map for this file, kill it */
if (Allocated)
{
OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
RemoveEntryList(&SharedCacheMap->SharedCacheMapLinks);
KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
FileObject->SectionObjectPointer->SharedCacheMap = NULL;
ObDereferenceObject(FileObject);
ExFreeToNPagedLookasideList(&SharedCacheMapLookasideList, SharedCacheMap);
}
KeReleaseGuardedMutex(&ViewLock);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Initialize it */
RtlZeroMemory(PrivateMap, sizeof(PRIVATE_CACHE_MAP));
PrivateMap->NodeTypeCode = NODE_TYPE_PRIVATE_MAP;
2018-02-08 16:46:08 +08:00
PrivateMap->ReadAheadMask = PAGE_SIZE - 1;
PrivateMap->FileObject = FileObject;
KeInitializeSpinLock(&PrivateMap->ReadAheadSpinLock);
/* Link it to the file */
KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql);
InsertTailList(&SharedCacheMap->PrivateList, &PrivateMap->PrivateLinks);
KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
FileObject->PrivateCacheMap = PrivateMap;
SharedCacheMap->OpenCount++;
}
KeReleaseGuardedMutex(&ViewLock);
return STATUS_SUCCESS;
}
/*
* @implemented
*/
PFILE_OBJECT
NTAPI
CcGetFileObjectFromSectionPtrs (
IN PSECTION_OBJECT_POINTERS SectionObjectPointers)
{
PROS_SHARED_CACHE_MAP SharedCacheMap;
CCTRACE(CC_API_DEBUG, "SectionObjectPointers=%p\n", SectionObjectPointers);
if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap)
{
SharedCacheMap = SectionObjectPointers->SharedCacheMap;
ASSERT(SharedCacheMap);
return SharedCacheMap->FileObject;
}
return NULL;
}
VOID
INIT_FUNCTION
NTAPI
CcInitView (
VOID)
{
DPRINT("CcInitView()\n");
InitializeListHead(&DirtyVacbListHead);
InitializeListHead(&VacbLruListHead);
InitializeListHead(&CcDeferredWrites);
InitializeListHead(&CcCleanSharedCacheMapList);
KeInitializeSpinLock(&CcDeferredWriteSpinLock);
KeInitializeGuardedMutex(&ViewLock);
ExInitializeNPagedLookasideList(&iBcbLookasideList,
NULL,
NULL,
0,
sizeof(INTERNAL_BCB),
TAG_BCB,
20);
ExInitializeNPagedLookasideList(&SharedCacheMapLookasideList,
NULL,
NULL,
0,
sizeof(ROS_SHARED_CACHE_MAP),
TAG_SHARED_CACHE_MAP,
20);
ExInitializeNPagedLookasideList(&VacbLookasideList,
NULL,
NULL,
0,
sizeof(ROS_VACB),
TAG_VACB,
20);
MmInitializeMemoryConsumer(MC_CACHE, CcRosTrimCache);
CcInitCacheZeroPage();
}
2018-01-25 05:03:23 +08:00
#if DBG && defined(KDBG)
BOOLEAN
ExpKdbgExtFileCache(ULONG Argc, PCHAR Argv[])
{
PLIST_ENTRY ListEntry;
UNICODE_STRING NoName = RTL_CONSTANT_STRING(L"No name for File");
KdbpPrint(" Usage Summary (in kb)\n");
KdbpPrint("Shared\t\tValid\tDirty\tName\n");
/* No need to lock the spin lock here, we're in DBG */
for (ListEntry = CcCleanSharedCacheMapList.Flink;
ListEntry != &CcCleanSharedCacheMapList;
ListEntry = ListEntry->Flink)
{
PLIST_ENTRY Vacbs;
ULONG Valid = 0, Dirty = 0;
PROS_SHARED_CACHE_MAP SharedCacheMap;
PUNICODE_STRING FileName;
SharedCacheMap = CONTAINING_RECORD(ListEntry, ROS_SHARED_CACHE_MAP, SharedCacheMapLinks);
/* Dirty size */
Dirty = (SharedCacheMap->DirtyPages * PAGE_SIZE) / 1024;
/* First, count for all the associated VACB */
for (Vacbs = SharedCacheMap->CacheMapVacbListHead.Flink;
Vacbs != &SharedCacheMap->CacheMapVacbListHead;
Vacbs = Vacbs->Flink)
{
PROS_VACB Vacb;
Vacb = CONTAINING_RECORD(Vacbs, ROS_VACB, CacheMapVacbListEntry);
if (Vacb->Valid)
{
Valid += VACB_MAPPING_GRANULARITY / 1024;
}
}
/* Setup name */
if (SharedCacheMap->FileObject != NULL &&
SharedCacheMap->FileObject->FileName.Length != 0)
{
FileName = &SharedCacheMap->FileObject->FileName;
}
else
{
FileName = &NoName;
}
/* And print */
KdbpPrint("%p\t%d\t%d\t%wZ\n", SharedCacheMap, Valid, Dirty, FileName);
}
return TRUE;
}
BOOLEAN
ExpKdbgExtDefWrites(ULONG Argc, PCHAR Argv[])
{
KdbpPrint("CcTotalDirtyPages:\t%lu (%lu Kb)\n", CcTotalDirtyPages,
(CcTotalDirtyPages * PAGE_SIZE) / 1024);
KdbpPrint("CcDirtyPageThreshold:\t%lu (%lu Kb)\n", CcDirtyPageThreshold,
(CcDirtyPageThreshold * PAGE_SIZE) / 1024);
KdbpPrint("MmAvailablePages:\t%lu (%lu Kb)\n", MmAvailablePages,
(MmAvailablePages * PAGE_SIZE) / 1024);
KdbpPrint("MmThrottleTop:\t\t%lu (%lu Kb)\n", MmThrottleTop,
(MmThrottleTop * PAGE_SIZE) / 1024);
KdbpPrint("MmThrottleBottom:\t%lu (%lu Kb)\n", MmThrottleBottom,
(MmThrottleBottom * PAGE_SIZE) / 1024);
KdbpPrint("MmModifiedPageListHead.Total:\t%lu (%lu Kb)\n", MmModifiedPageListHead.Total,
(MmModifiedPageListHead.Total * PAGE_SIZE) / 1024);
if (CcTotalDirtyPages >= CcDirtyPageThreshold)
{
KdbpPrint("CcTotalDirtyPages above the threshold, writes should be throttled\n");
}
else if (CcTotalDirtyPages + 64 >= CcDirtyPageThreshold)
{
KdbpPrint("CcTotalDirtyPages within 64 (max charge) pages of the threshold, writes may be throttled\n");
}
else
{
KdbpPrint("CcTotalDirtyPages below the threshold, writes should not be throttled\n");
}
return TRUE;
}
2018-01-25 05:03:23 +08:00
#endif
/* EOF */