2008-03-09 14:11:42 +00:00
|
|
|
/*
|
2005-01-26 13:58:37 +00:00
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
1998-12-21 15:48:21 +00:00
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* FILE: ntoskrnl/cc/view.c
|
|
|
|
* PURPOSE: Cache manager
|
2005-01-26 13:58:37 +00:00
|
|
|
*
|
|
|
|
* PROGRAMMERS: David Welch (welch@mcmail.com)
|
1998-12-21 15:48:21 +00:00
|
|
|
*/
|
|
|
|
|
2000-12-10 23:42:01 +00:00
|
|
|
/* NOTES **********************************************************************
|
|
|
|
*
|
2005-05-09 01:38:29 +00:00
|
|
|
* This is not the NT implementation of a file cache nor anything much like
|
|
|
|
* it.
|
2002-05-05 14:57:45 +00:00
|
|
|
*
|
2005-05-09 01:38:29 +00:00
|
|
|
* The general procedure for a filesystem to implement a read or write
|
2000-12-10 23:42:01 +00:00
|
|
|
* dispatch routine is as follows
|
2005-05-09 01:38:29 +00:00
|
|
|
*
|
2000-12-10 23:42:01 +00:00
|
|
|
* (1) If caching for the FCB hasn't been initiated then so do by calling
|
|
|
|
* CcInitializeFileCache.
|
2005-05-09 01:38:29 +00:00
|
|
|
*
|
2000-12-10 23:42:01 +00:00
|
|
|
* (2) For each 4k region which is being read or written obtain a cache page
|
2005-05-09 01:38:29 +00:00
|
|
|
* by calling CcRequestCachePage.
|
2000-12-10 23:42:01 +00:00
|
|
|
*
|
2005-05-09 01:38:29 +00:00
|
|
|
* (3) If either the page is being read or not completely written, and it is
|
2000-12-10 23:42:01 +00:00
|
|
|
* not up to date then read its data from the underlying medium. If the read
|
2005-05-09 01:38:29 +00:00
|
|
|
* fails then call CcReleaseCachePage with VALID as FALSE and return a error.
|
|
|
|
*
|
2000-12-10 23:42:01 +00:00
|
|
|
* (4) Copy the data into or out of the page as necessary.
|
2005-05-09 01:38:29 +00:00
|
|
|
*
|
2000-12-10 23:42:01 +00:00
|
|
|
* (5) Release the cache page
|
|
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
1998-12-21 15:48:21 +00:00
|
|
|
|
2004-08-15 16:39:12 +00:00
|
|
|
#include <ntoskrnl.h>
|
1999-05-29 00:15:17 +00:00
|
|
|
#define NDEBUG
|
2008-08-30 16:31:06 +00:00
|
|
|
#include <debug.h>
|
1998-12-21 15:48:21 +00:00
|
|
|
|
2005-11-28 23:25:31 +00:00
|
|
|
#if defined (ALLOC_PRAGMA)
|
|
|
|
#pragma alloc_text(INIT, CcInitView)
|
|
|
|
#endif
|
|
|
|
|
2001-01-01 04:42:12 +00:00
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
|
2003-01-11 15:24:38 +00:00
|
|
|
/*
|
2005-05-09 01:38:29 +00:00
|
|
|
* If CACHE_BITMAP is defined, the cache manager uses one large memory region
|
|
|
|
* within the kernel address space and allocate/deallocate space from this block
|
|
|
|
* over a bitmap. If CACHE_BITMAP is used, the size of the mdl mapping region
|
2003-01-11 15:24:38 +00:00
|
|
|
* must be reduced (ntoskrnl\mm\mdl.c, MI_MDLMAPPING_REGION_SIZE).
|
|
|
|
*/
|
2008-05-23 14:40:50 +00:00
|
|
|
//#define CACHE_BITMAP
|
2003-01-11 15:24:38 +00:00
|
|
|
|
2001-12-27 23:56:42 +00:00
|
|
|
static LIST_ENTRY DirtySegmentListHead;
|
|
|
|
static LIST_ENTRY CacheSegmentListHead;
|
2001-12-29 14:32:22 +00:00
|
|
|
static LIST_ENTRY CacheSegmentLRUListHead;
|
2003-01-11 15:24:38 +00:00
|
|
|
static LIST_ENTRY ClosedListHead;
|
2003-02-13 22:24:19 +00:00
|
|
|
ULONG DirtyPageCount=0;
|
2001-04-09 02:45:04 +00: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-12 19:00:26 +00:00
|
|
|
KGUARDED_MUTEX ViewLock;
|
1999-01-16 21:03:00 +00:00
|
|
|
|
2003-01-11 15:24:38 +00:00
|
|
|
#ifdef CACHE_BITMAP
|
2008-05-23 14:40:50 +00:00
|
|
|
#define CI_CACHESEG_MAPPING_REGION_SIZE (128*1024*1024)
|
2003-01-11 15:24:38 +00:00
|
|
|
|
|
|
|
static PVOID CiCacheSegMappingRegionBase = NULL;
|
|
|
|
static RTL_BITMAP CiCacheSegMappingRegionAllocMap;
|
|
|
|
static ULONG CiCacheSegMappingRegionHint;
|
|
|
|
static KSPIN_LOCK CiCacheSegMappingRegionLock;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
NPAGED_LOOKASIDE_LIST iBcbLookasideList;
|
|
|
|
static NPAGED_LOOKASIDE_LIST BcbLookasideList;
|
|
|
|
static NPAGED_LOOKASIDE_LIST CacheSegLookasideList;
|
|
|
|
|
2009-10-17 15:03:54 +00:00
|
|
|
#if DBG
|
2005-08-15 18:43:56 +00:00
|
|
|
static void CcRosCacheSegmentIncRefCount_ ( PCACHE_SEGMENT cs, const char* file, int line )
|
2005-08-13 13:16:16 +00:00
|
|
|
{
|
|
|
|
++cs->ReferenceCount;
|
|
|
|
if ( cs->Bcb->Trace )
|
|
|
|
{
|
2005-08-15 18:43:56 +00:00
|
|
|
DbgPrint("(%s:%i) CacheSegment %p ++RefCount=%d, Dirty %d, PageOut %d\n",
|
|
|
|
file, line, cs, cs->ReferenceCount, cs->Dirty, cs->PageOut );
|
2005-08-13 13:16:16 +00:00
|
|
|
}
|
|
|
|
}
|
2005-08-15 18:43:56 +00:00
|
|
|
static void CcRosCacheSegmentDecRefCount_ ( PCACHE_SEGMENT cs, const char* file, int line )
|
2005-08-13 13:16:16 +00:00
|
|
|
{
|
|
|
|
--cs->ReferenceCount;
|
|
|
|
if ( cs->Bcb->Trace )
|
|
|
|
{
|
2005-08-15 18:43:56 +00:00
|
|
|
DbgPrint("(%s:%i) CacheSegment %p --RefCount=%d, Dirty %d, PageOut %d\n",
|
|
|
|
file, line, cs, cs->ReferenceCount, cs->Dirty, cs->PageOut );
|
2005-08-13 13:16:16 +00:00
|
|
|
}
|
|
|
|
}
|
2005-08-15 18:43:56 +00:00
|
|
|
#define CcRosCacheSegmentIncRefCount(cs) CcRosCacheSegmentIncRefCount_(cs,__FILE__,__LINE__)
|
|
|
|
#define CcRosCacheSegmentDecRefCount(cs) CcRosCacheSegmentDecRefCount_(cs,__FILE__,__LINE__)
|
2005-08-13 13:16:16 +00:00
|
|
|
#else
|
|
|
|
#define CcRosCacheSegmentIncRefCount(cs) (++((cs)->ReferenceCount))
|
|
|
|
#define CcRosCacheSegmentDecRefCount(cs) (--((cs)->ReferenceCount))
|
|
|
|
#endif
|
2002-09-30 20:55:33 +00:00
|
|
|
|
2003-01-11 15:24:38 +00:00
|
|
|
NTSTATUS
|
2002-10-02 19:20:51 +00:00
|
|
|
CcRosInternalFreeCacheSegment(PCACHE_SEGMENT CacheSeg);
|
2001-12-29 14:32:22 +00:00
|
|
|
|
2005-11-19 22:13:35 +00:00
|
|
|
|
2001-12-27 23:56:42 +00:00
|
|
|
/* FUNCTIONS *****************************************************************/
|
1998-12-21 15:48:21 +00:00
|
|
|
|
2005-08-13 13:16:16 +00:00
|
|
|
VOID
|
2008-11-29 20:47:48 +00:00
|
|
|
NTAPI
|
2005-08-13 13:16:16 +00:00
|
|
|
CcRosTraceCacheMap (
|
|
|
|
PBCB Bcb,
|
|
|
|
BOOLEAN Trace )
|
|
|
|
{
|
2009-10-17 15:03:54 +00:00
|
|
|
#if DBG
|
2005-08-13 13:16:16 +00:00
|
|
|
KIRQL oldirql;
|
|
|
|
PLIST_ENTRY current_entry;
|
|
|
|
PCACHE_SEGMENT current;
|
|
|
|
|
|
|
|
if ( !Bcb )
|
|
|
|
return;
|
|
|
|
|
|
|
|
Bcb->Trace = Trace;
|
|
|
|
|
|
|
|
if ( Trace )
|
|
|
|
{
|
|
|
|
DPRINT1("Enabling Tracing for CacheMap 0x%p:\n", Bcb );
|
|
|
|
|
- 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-12 19:00:26 +00:00
|
|
|
KeAcquireGuardedMutex(&ViewLock);
|
2005-08-13 13:16:16 +00:00
|
|
|
KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
|
|
|
|
|
|
|
|
current_entry = Bcb->BcbSegmentListHead.Flink;
|
|
|
|
while (current_entry != &Bcb->BcbSegmentListHead)
|
|
|
|
{
|
|
|
|
current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
|
|
|
|
current_entry = current_entry->Flink;
|
|
|
|
|
|
|
|
DPRINT1(" CacheSegment 0x%p enabled, RefCount %d, Dirty %d, PageOut %d\n",
|
|
|
|
current, current->ReferenceCount, current->Dirty, current->PageOut );
|
|
|
|
}
|
|
|
|
KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
|
- 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-12 19:00:26 +00:00
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
2005-08-13 13:16:16 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DPRINT1("Disabling Tracing for CacheMap 0x%p:\n", Bcb );
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
Bcb = Bcb;
|
|
|
|
Trace = Trace;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2004-08-25 15:08:29 +00:00
|
|
|
NTSTATUS
|
2005-09-14 01:44:19 +00:00
|
|
|
NTAPI
|
2002-09-08 10:23:54 +00:00
|
|
|
CcRosFlushCacheSegment(PCACHE_SEGMENT CacheSegment)
|
2002-08-14 20:58:39 +00: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-12 19:00:26 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
KIRQL oldIrql;
|
|
|
|
|
|
|
|
Status = WriteCacheSegment(CacheSegment);
|
|
|
|
if (NT_SUCCESS(Status))
|
2002-08-14 20:58:39 +00: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-12 19:00:26 +00:00
|
|
|
KeAcquireGuardedMutex(&ViewLock);
|
|
|
|
KeAcquireSpinLock(&CacheSegment->Bcb->BcbLock, &oldIrql);
|
|
|
|
|
|
|
|
CacheSegment->Dirty = FALSE;
|
|
|
|
RemoveEntryList(&CacheSegment->DirtySegmentListEntry);
|
|
|
|
DirtyPageCount -= CacheSegment->Bcb->CacheSegmentSize / PAGE_SIZE;
|
|
|
|
CcRosCacheSegmentDecRefCount ( CacheSegment );
|
|
|
|
|
|
|
|
KeReleaseSpinLock(&CacheSegment->Bcb->BcbLock, oldIrql);
|
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
2002-08-14 20:58:39 +00: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-12 19:00:26 +00:00
|
|
|
|
|
|
|
return(Status);
|
2002-08-14 20:58:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2005-09-14 01:44:19 +00:00
|
|
|
NTAPI
|
2002-08-14 20:58:39 +00:00
|
|
|
CcRosFlushDirtyPages(ULONG Target, PULONG Count)
|
|
|
|
{
|
- 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-12 19:00:26 +00:00
|
|
|
PLIST_ENTRY current_entry;
|
|
|
|
PCACHE_SEGMENT current;
|
|
|
|
ULONG PagesPerSegment;
|
|
|
|
BOOLEAN Locked;
|
|
|
|
NTSTATUS Status;
|
|
|
|
static ULONG WriteCount[4] = {0, 0, 0, 0};
|
|
|
|
ULONG NewTarget;
|
|
|
|
|
|
|
|
DPRINT("CcRosFlushDirtyPages(Target %d)\n", Target);
|
|
|
|
|
|
|
|
(*Count) = 0;
|
|
|
|
|
|
|
|
KeAcquireGuardedMutex(&ViewLock);
|
|
|
|
|
|
|
|
WriteCount[0] = WriteCount[1];
|
|
|
|
WriteCount[1] = WriteCount[2];
|
|
|
|
WriteCount[2] = WriteCount[3];
|
|
|
|
WriteCount[3] = 0;
|
|
|
|
|
|
|
|
NewTarget = WriteCount[0] + WriteCount[1] + WriteCount[2];
|
|
|
|
|
|
|
|
if (NewTarget < DirtyPageCount)
|
|
|
|
{
|
|
|
|
NewTarget = (DirtyPageCount - NewTarget + 3) / 4;
|
|
|
|
WriteCount[0] += NewTarget;
|
|
|
|
WriteCount[1] += NewTarget;
|
|
|
|
WriteCount[2] += NewTarget;
|
|
|
|
WriteCount[3] += NewTarget;
|
|
|
|
}
|
|
|
|
|
|
|
|
NewTarget = WriteCount[0];
|
|
|
|
|
|
|
|
Target = max(NewTarget, Target);
|
|
|
|
|
|
|
|
current_entry = DirtySegmentListHead.Flink;
|
|
|
|
if (current_entry == &DirtySegmentListHead)
|
|
|
|
{
|
|
|
|
DPRINT("No Dirty pages\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
while (current_entry != &DirtySegmentListHead && Target > 0)
|
|
|
|
{
|
|
|
|
current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
|
|
|
|
DirtySegmentListEntry);
|
|
|
|
current_entry = current_entry->Flink;
|
2007-11-18 23:11:20 +00:00
|
|
|
|
2008-03-08 16:47:41 +00:00
|
|
|
Locked = current->Bcb->Callbacks->AcquireForLazyWrite(
|
|
|
|
current->Bcb->LazyWriteContext, FALSE);
|
- 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-12 19:00:26 +00:00
|
|
|
if (!Locked)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Locked = ExTryToAcquirePushLockExclusive(¤t->Lock);
|
|
|
|
if (!Locked)
|
|
|
|
{
|
2008-03-08 16:47:41 +00:00
|
|
|
current->Bcb->Callbacks->ReleaseFromLazyWrite(
|
|
|
|
current->Bcb->LazyWriteContext);
|
|
|
|
|
- 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-12 19:00:26 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT(current->Dirty);
|
|
|
|
if (current->ReferenceCount > 1)
|
|
|
|
{
|
|
|
|
ExReleasePushLock(¤t->Lock);
|
2008-03-08 16:47:41 +00:00
|
|
|
current->Bcb->Callbacks->ReleaseFromLazyWrite(
|
|
|
|
current->Bcb->LazyWriteContext);
|
- 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-12 19:00:26 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
PagesPerSegment = current->Bcb->CacheSegmentSize / PAGE_SIZE;
|
2005-05-09 01:38:29 +00: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-12 19:00:26 +00:00
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
2008-03-08 16:47:41 +00: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-12 19:00:26 +00:00
|
|
|
Status = CcRosFlushCacheSegment(current);
|
2003-01-30 18:30:53 +00: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-12 19:00:26 +00:00
|
|
|
ExReleasePushLock(¤t->Lock);
|
2008-03-08 16:47:41 +00:00
|
|
|
current->Bcb->Callbacks->ReleaseFromLazyWrite(
|
|
|
|
current->Bcb->LazyWriteContext);
|
2007-10-19 23:21:45 +00: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-12 19:00:26 +00:00
|
|
|
if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
|
2005-11-27 15:59:32 +00: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-12 19:00:26 +00:00
|
|
|
DPRINT1("CC: Failed to flush cache segment.\n");
|
2005-11-27 15:59:32 +00: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-12 19:00:26 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
(*Count) += PagesPerSegment;
|
|
|
|
Target -= PagesPerSegment;
|
|
|
|
}
|
|
|
|
|
|
|
|
KeAcquireGuardedMutex(&ViewLock);
|
|
|
|
current_entry = DirtySegmentListHead.Flink;
|
2002-08-14 20:58:39 +00: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-12 19:00:26 +00:00
|
|
|
|
|
|
|
if (*Count < NewTarget)
|
|
|
|
{
|
|
|
|
WriteCount[1] += (NewTarget - *Count);
|
|
|
|
}
|
|
|
|
|
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
|
|
|
|
|
|
|
DPRINT("CcRosFlushDirtyPages() finished\n");
|
|
|
|
return(STATUS_SUCCESS);
|
2002-08-14 20:58:39 +00:00
|
|
|
}
|
|
|
|
|
2001-12-29 14:32:22 +00:00
|
|
|
NTSTATUS
|
2001-12-31 01:53:46 +00:00
|
|
|
CcRosTrimCache(ULONG Target, ULONG Priority, PULONG NrFreed)
|
2002-05-19 14:09:35 +00:00
|
|
|
/*
|
|
|
|
* 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).
|
2005-05-09 01:38:29 +00:00
|
|
|
* NrFreed - Points to a variable where the number of pages
|
2002-05-19 14:09:35 +00:00
|
|
|
* actually freed is returned.
|
|
|
|
*/
|
2001-12-29 14:32:22 +00:00
|
|
|
{
|
2009-02-18 16:56:42 +00:00
|
|
|
PLIST_ENTRY current_entry;
|
|
|
|
PCACHE_SEGMENT current;
|
|
|
|
ULONG PagesPerSegment;
|
|
|
|
ULONG PagesFreed;
|
|
|
|
KIRQL oldIrql;
|
|
|
|
LIST_ENTRY FreeList;
|
|
|
|
|
|
|
|
DPRINT("CcRosTrimCache(Target %d)\n", Target);
|
|
|
|
|
|
|
|
*NrFreed = 0;
|
|
|
|
|
|
|
|
InitializeListHead(&FreeList);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2009-02-18 16:56:42 +00:00
|
|
|
KeAcquireGuardedMutex(&ViewLock);
|
|
|
|
current_entry = CacheSegmentLRUListHead.Flink;
|
|
|
|
while (current_entry != &CacheSegmentLRUListHead && Target > 0)
|
2001-12-29 14:32:22 +00:00
|
|
|
{
|
2009-02-18 16:56:42 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
|
|
|
|
CacheSegmentLRUListEntry);
|
|
|
|
current_entry = current_entry->Flink;
|
|
|
|
|
|
|
|
KeAcquireSpinLock(¤t->Bcb->BcbLock, &oldIrql);
|
2002-10-02 19:20:51 +00:00
|
|
|
|
2009-02-18 16:56:42 +00:00
|
|
|
if (current->MappedCount > 0 && !current->Dirty && !current->PageOut)
|
|
|
|
{
|
|
|
|
ULONG i;
|
|
|
|
|
|
|
|
CcRosCacheSegmentIncRefCount(current);
|
|
|
|
current->PageOut = TRUE;
|
|
|
|
KeReleaseSpinLock(¤t->Bcb->BcbLock, oldIrql);
|
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
|
|
|
for (i = 0; i < current->Bcb->CacheSegmentSize / PAGE_SIZE; i++)
|
|
|
|
{
|
|
|
|
PFN_TYPE Page;
|
|
|
|
Page = (PFN_TYPE)(MmGetPhysicalAddress((char*)current->BaseAddress + i * PAGE_SIZE).QuadPart >> PAGE_SHIFT);
|
|
|
|
Status = MmPageOutPhysicalAddress(Page);
|
|
|
|
}
|
|
|
|
KeAcquireGuardedMutex(&ViewLock);
|
|
|
|
KeAcquireSpinLock(¤t->Bcb->BcbLock, &oldIrql);
|
|
|
|
CcRosCacheSegmentDecRefCount(current);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (current->ReferenceCount == 0)
|
|
|
|
{
|
|
|
|
PagesPerSegment = current->Bcb->CacheSegmentSize / PAGE_SIZE;
|
|
|
|
// PagesFreed = PagesPerSegment;
|
|
|
|
PagesFreed = min(PagesPerSegment, Target);
|
|
|
|
Target -= PagesFreed;
|
|
|
|
(*NrFreed) += PagesFreed;
|
|
|
|
}
|
|
|
|
|
|
|
|
KeReleaseSpinLock(¤t->Bcb->BcbLock, oldIrql);
|
|
|
|
}
|
|
|
|
|
|
|
|
current_entry = CacheSegmentLRUListHead.Flink;
|
|
|
|
while (current_entry != &CacheSegmentLRUListHead)
|
|
|
|
{
|
|
|
|
current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
|
|
|
|
CacheSegmentLRUListEntry);
|
|
|
|
current->PageOut = FALSE;
|
|
|
|
current_entry = current_entry->Flink;
|
|
|
|
|
|
|
|
KeAcquireSpinLock(¤t->Bcb->BcbLock, &oldIrql);
|
|
|
|
if (current->ReferenceCount == 0)
|
|
|
|
{
|
|
|
|
RemoveEntryList(¤t->BcbSegmentListEntry);
|
|
|
|
KeReleaseSpinLock(¤t->Bcb->BcbLock, oldIrql);
|
|
|
|
RemoveEntryList(¤t->CacheSegmentListEntry);
|
|
|
|
RemoveEntryList(¤t->CacheSegmentLRUListEntry);
|
|
|
|
InsertHeadList(&FreeList, ¤t->BcbSegmentListEntry);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
KeReleaseSpinLock(¤t->Bcb->BcbLock, oldIrql);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
|
|
|
|
|
|
|
while (!IsListEmpty(&FreeList))
|
|
|
|
{
|
|
|
|
current_entry = RemoveHeadList(&FreeList);
|
|
|
|
current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
|
|
|
|
BcbSegmentListEntry);
|
|
|
|
CcRosInternalFreeCacheSegment(current);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
2001-12-29 14:32:22 +00:00
|
|
|
}
|
|
|
|
|
2005-05-09 01:38:29 +00:00
|
|
|
NTSTATUS
|
2005-09-14 01:44:19 +00:00
|
|
|
NTAPI
|
2002-09-08 10:23:54 +00:00
|
|
|
CcRosReleaseCacheSegment(PBCB Bcb,
|
|
|
|
PCACHE_SEGMENT CacheSeg,
|
2001-12-29 14:32:22 +00:00
|
|
|
BOOLEAN Valid,
|
|
|
|
BOOLEAN Dirty,
|
|
|
|
BOOLEAN Mapped)
|
1999-05-29 00:15:17 +00:00
|
|
|
{
|
2002-07-17 21:04:57 +00:00
|
|
|
BOOLEAN WasDirty = CacheSeg->Dirty;
|
2002-10-02 19:20:51 +00:00
|
|
|
KIRQL oldIrql;
|
2001-12-29 14:32:22 +00:00
|
|
|
|
2004-10-22 20:19:58 +00:00
|
|
|
ASSERT(Bcb);
|
2002-12-15 Casper S. Hornstrup <chorns@users.sourceforge.net>
* drivers/fs/vfat/cleanup.c (VfatCleanupFile): Only uninitialize caching
when initialized.
* drivers/fs/vfat/fcb.c (vfatReleaseFCB): Ditto.
* lib/kernel32/mem/section.c (CreateFileMappingW): Pass NULL as
MaximumSize to NtCreateSection if dwMaximumSizeHigh and dwMaximumSizeLow
are both 0.
* ntoskrnl/cc/pin.c (CcMapData): Assert if Bcb is NULL.
* ntoskrnl/cc/view.c (CcRosReleaseCacheSegment, CcRosLookupCacheSegment,
CcRosMarkDirtyCacheSegment, CcRosUnmapCacheSegment,
CcRosCreateCacheSegment, CcRosGetCacheSegmentChain,
CcRosGetCacheSegment, CcRosRequestCacheSegment, CcFlushCache,
CcRosDeleteFileCache, CcRosReferenceCache, CcRosDereferenceCache,
CcRosReleaseFileCache, CcGetFileObjectFromSectionPtrs): Ditto.
* ntoskrnl/mm/section.c (MiReadPage): Assert if Fcb->Bcb is NULL.
(MmCreateDataFileSection): Make sure caching is initialized for the file
stream.
svn path=/trunk/; revision=3879
2002-12-15 17:01:52 +00:00
|
|
|
|
2005-07-04 22:11:00 +00:00
|
|
|
DPRINT("CcReleaseCacheSegment(Bcb 0x%p, CacheSeg 0x%p, Valid %d)\n",
|
2002-07-17 21:04:57 +00:00
|
|
|
Bcb, CacheSeg, Valid);
|
2002-10-02 19:20:51 +00:00
|
|
|
|
2002-07-17 21:04:57 +00:00
|
|
|
CacheSeg->Valid = Valid;
|
|
|
|
CacheSeg->Dirty = CacheSeg->Dirty || Dirty;
|
2002-10-02 19:20:51 +00: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-12 19:00:26 +00:00
|
|
|
KeAcquireGuardedMutex(&ViewLock);
|
2002-07-17 21:04:57 +00:00
|
|
|
if (!WasDirty && CacheSeg->Dirty)
|
|
|
|
{
|
|
|
|
InsertTailList(&DirtySegmentListHead, &CacheSeg->DirtySegmentListEntry);
|
2003-01-30 18:30:53 +00:00
|
|
|
DirtyPageCount += Bcb->CacheSegmentSize / PAGE_SIZE;
|
2002-07-17 21:04:57 +00:00
|
|
|
}
|
|
|
|
RemoveEntryList(&CacheSeg->CacheSegmentLRUListEntry);
|
2002-10-02 19:20:51 +00:00
|
|
|
InsertTailList(&CacheSegmentLRUListHead, &CacheSeg->CacheSegmentLRUListEntry);
|
|
|
|
|
|
|
|
if (Mapped)
|
|
|
|
{
|
|
|
|
CacheSeg->MappedCount++;
|
|
|
|
}
|
|
|
|
KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
|
2005-08-13 13:16:16 +00:00
|
|
|
CcRosCacheSegmentDecRefCount(CacheSeg);
|
2002-10-02 19:20:51 +00:00
|
|
|
if (Mapped && CacheSeg->MappedCount == 1)
|
|
|
|
{
|
2005-08-13 13:16:16 +00:00
|
|
|
CcRosCacheSegmentIncRefCount(CacheSeg);
|
2002-10-02 19:20:51 +00:00
|
|
|
}
|
|
|
|
if (!WasDirty && CacheSeg->Dirty)
|
|
|
|
{
|
2005-08-13 13:16:16 +00:00
|
|
|
CcRosCacheSegmentIncRefCount(CacheSeg);
|
2002-10-02 19:20:51 +00:00
|
|
|
}
|
|
|
|
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
|
- 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-12 19:00:26 +00:00
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
|
|
|
ExReleasePushLock(&CacheSeg->Lock);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2002-07-17 21:04:57 +00:00
|
|
|
return(STATUS_SUCCESS);
|
1999-05-29 00:15:17 +00:00
|
|
|
}
|
1998-12-21 15:48:21 +00: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-12 19:00:26 +00:00
|
|
|
/* Returns with Cache Segment Lock Held! */
|
2005-05-09 01:38:29 +00:00
|
|
|
PCACHE_SEGMENT
|
2005-09-14 01:44:19 +00:00
|
|
|
NTAPI
|
2003-01-11 15:24:38 +00:00
|
|
|
CcRosLookupCacheSegment(PBCB Bcb, ULONG FileOffset)
|
2001-12-31 01:53:46 +00: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-12 19:00:26 +00:00
|
|
|
PLIST_ENTRY current_entry;
|
|
|
|
PCACHE_SEGMENT current;
|
|
|
|
KIRQL oldIrql;
|
|
|
|
|
|
|
|
ASSERT(Bcb);
|
|
|
|
|
|
|
|
DPRINT("CcRosLookupCacheSegment(Bcb -x%p, FileOffset %d)\n", Bcb, FileOffset);
|
|
|
|
|
|
|
|
KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
|
|
|
|
current_entry = Bcb->BcbSegmentListHead.Flink;
|
|
|
|
while (current_entry != &Bcb->BcbSegmentListHead)
|
2001-12-31 01:53:46 +00: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-12 19:00:26 +00:00
|
|
|
current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
|
|
|
|
BcbSegmentListEntry);
|
|
|
|
if (current->FileOffset <= FileOffset &&
|
|
|
|
(current->FileOffset + Bcb->CacheSegmentSize) > FileOffset)
|
|
|
|
{
|
|
|
|
CcRosCacheSegmentIncRefCount(current);
|
|
|
|
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
|
|
|
|
ExAcquirePushLockExclusive(¤t->Lock);
|
|
|
|
return(current);
|
|
|
|
}
|
|
|
|
current_entry = current_entry->Flink;
|
2001-12-31 01:53:46 +00: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-12 19:00:26 +00:00
|
|
|
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
|
|
|
|
return(NULL);
|
2001-12-31 01:53:46 +00:00
|
|
|
}
|
|
|
|
|
2002-08-14 20:58:39 +00:00
|
|
|
NTSTATUS
|
2005-09-14 01:44:19 +00:00
|
|
|
NTAPI
|
2002-09-08 10:23:54 +00:00
|
|
|
CcRosMarkDirtyCacheSegment(PBCB Bcb, ULONG FileOffset)
|
2002-08-14 20:58:39 +00:00
|
|
|
{
|
2002-09-08 10:23:54 +00:00
|
|
|
PCACHE_SEGMENT CacheSeg;
|
2002-10-02 19:20:51 +00:00
|
|
|
KIRQL oldIrql;
|
|
|
|
|
2004-10-22 20:19:58 +00:00
|
|
|
ASSERT(Bcb);
|
2002-12-15 Casper S. Hornstrup <chorns@users.sourceforge.net>
* drivers/fs/vfat/cleanup.c (VfatCleanupFile): Only uninitialize caching
when initialized.
* drivers/fs/vfat/fcb.c (vfatReleaseFCB): Ditto.
* lib/kernel32/mem/section.c (CreateFileMappingW): Pass NULL as
MaximumSize to NtCreateSection if dwMaximumSizeHigh and dwMaximumSizeLow
are both 0.
* ntoskrnl/cc/pin.c (CcMapData): Assert if Bcb is NULL.
* ntoskrnl/cc/view.c (CcRosReleaseCacheSegment, CcRosLookupCacheSegment,
CcRosMarkDirtyCacheSegment, CcRosUnmapCacheSegment,
CcRosCreateCacheSegment, CcRosGetCacheSegmentChain,
CcRosGetCacheSegment, CcRosRequestCacheSegment, CcFlushCache,
CcRosDeleteFileCache, CcRosReferenceCache, CcRosDereferenceCache,
CcRosReleaseFileCache, CcGetFileObjectFromSectionPtrs): Ditto.
* ntoskrnl/mm/section.c (MiReadPage): Assert if Fcb->Bcb is NULL.
(MmCreateDataFileSection): Make sure caching is initialized for the file
stream.
svn path=/trunk/; revision=3879
2002-12-15 17:01:52 +00:00
|
|
|
|
2005-07-04 22:11:00 +00:00
|
|
|
DPRINT("CcRosMarkDirtyCacheSegment(Bcb 0x%p, FileOffset %d)\n", Bcb, FileOffset);
|
2002-08-14 20:58:39 +00:00
|
|
|
|
|
|
|
CacheSeg = CcRosLookupCacheSegment(Bcb, FileOffset);
|
|
|
|
if (CacheSeg == NULL)
|
|
|
|
{
|
2008-08-24 15:48:05 +00:00
|
|
|
KeBugCheck(CACHE_MANAGER);
|
2002-08-14 20:58:39 +00:00
|
|
|
}
|
|
|
|
if (!CacheSeg->Dirty)
|
|
|
|
{
|
- 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-12 19:00:26 +00:00
|
|
|
KeAcquireGuardedMutex(&ViewLock);
|
2002-08-14 20:58:39 +00:00
|
|
|
InsertTailList(&DirtySegmentListHead, &CacheSeg->DirtySegmentListEntry);
|
2003-01-30 18:30:53 +00:00
|
|
|
DirtyPageCount += Bcb->CacheSegmentSize / PAGE_SIZE;
|
- 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-12 19:00:26 +00:00
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
2002-08-14 20:58:39 +00:00
|
|
|
}
|
2002-10-02 19:20:51 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
|
2005-08-13 13:16:16 +00:00
|
|
|
CcRosCacheSegmentDecRefCount(CacheSeg);
|
2002-10-02 19:20:51 +00:00
|
|
|
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
|
|
|
|
}
|
2002-08-14 20:58:39 +00:00
|
|
|
|
2001-12-31 01:53:46 +00:00
|
|
|
|
2002-10-02 19:20:51 +00:00
|
|
|
CacheSeg->Dirty = TRUE;
|
- 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-12 19:00:26 +00:00
|
|
|
ExReleasePushLock(&CacheSeg->Lock);
|
2002-10-02 19:20:51 +00:00
|
|
|
|
2001-12-31 01:53:46 +00:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2005-09-14 01:44:19 +00:00
|
|
|
NTAPI
|
2002-09-08 10:23:54 +00:00
|
|
|
CcRosUnmapCacheSegment(PBCB Bcb, ULONG FileOffset, BOOLEAN NowDirty)
|
2001-12-31 01:53:46 +00:00
|
|
|
{
|
2002-09-08 10:23:54 +00:00
|
|
|
PCACHE_SEGMENT CacheSeg;
|
2002-10-02 19:20:51 +00:00
|
|
|
BOOLEAN WasDirty;
|
|
|
|
KIRQL oldIrql;
|
|
|
|
|
2004-10-22 20:19:58 +00:00
|
|
|
ASSERT(Bcb);
|
2002-12-15 Casper S. Hornstrup <chorns@users.sourceforge.net>
* drivers/fs/vfat/cleanup.c (VfatCleanupFile): Only uninitialize caching
when initialized.
* drivers/fs/vfat/fcb.c (vfatReleaseFCB): Ditto.
* lib/kernel32/mem/section.c (CreateFileMappingW): Pass NULL as
MaximumSize to NtCreateSection if dwMaximumSizeHigh and dwMaximumSizeLow
are both 0.
* ntoskrnl/cc/pin.c (CcMapData): Assert if Bcb is NULL.
* ntoskrnl/cc/view.c (CcRosReleaseCacheSegment, CcRosLookupCacheSegment,
CcRosMarkDirtyCacheSegment, CcRosUnmapCacheSegment,
CcRosCreateCacheSegment, CcRosGetCacheSegmentChain,
CcRosGetCacheSegment, CcRosRequestCacheSegment, CcFlushCache,
CcRosDeleteFileCache, CcRosReferenceCache, CcRosDereferenceCache,
CcRosReleaseFileCache, CcGetFileObjectFromSectionPtrs): Ditto.
* ntoskrnl/mm/section.c (MiReadPage): Assert if Fcb->Bcb is NULL.
(MmCreateDataFileSection): Make sure caching is initialized for the file
stream.
svn path=/trunk/; revision=3879
2002-12-15 17:01:52 +00:00
|
|
|
|
2005-07-04 22:11:00 +00:00
|
|
|
DPRINT("CcRosUnmapCacheSegment(Bcb 0x%p, FileOffset %d, NowDirty %d)\n",
|
2002-10-02 19:20:51 +00:00
|
|
|
Bcb, FileOffset, NowDirty);
|
2001-12-31 01:53:46 +00:00
|
|
|
|
|
|
|
CacheSeg = CcRosLookupCacheSegment(Bcb, FileOffset);
|
|
|
|
if (CacheSeg == NULL)
|
|
|
|
{
|
|
|
|
return(STATUS_UNSUCCESSFUL);
|
|
|
|
}
|
2002-10-02 19:20:51 +00:00
|
|
|
|
|
|
|
WasDirty = CacheSeg->Dirty;
|
2001-12-31 01:53:46 +00:00
|
|
|
CacheSeg->Dirty = CacheSeg->Dirty || NowDirty;
|
2002-10-02 19:20:51 +00:00
|
|
|
|
|
|
|
CacheSeg->MappedCount--;
|
|
|
|
|
|
|
|
if (!WasDirty && NowDirty)
|
|
|
|
{
|
- 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-12 19:00:26 +00:00
|
|
|
KeAcquireGuardedMutex(&ViewLock);
|
2002-10-02 19:20:51 +00:00
|
|
|
InsertTailList(&DirtySegmentListHead, &CacheSeg->DirtySegmentListEntry);
|
2003-01-30 18:30:53 +00:00
|
|
|
DirtyPageCount += Bcb->CacheSegmentSize / PAGE_SIZE;
|
- 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-12 19:00:26 +00:00
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
2002-10-02 19:20:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
|
2005-08-13 13:16:16 +00:00
|
|
|
CcRosCacheSegmentDecRefCount(CacheSeg);
|
2002-10-02 19:20:51 +00:00
|
|
|
if (!WasDirty && NowDirty)
|
|
|
|
{
|
2005-08-13 13:16:16 +00:00
|
|
|
CcRosCacheSegmentIncRefCount(CacheSeg);
|
2002-10-02 19:20:51 +00:00
|
|
|
}
|
|
|
|
if (CacheSeg->MappedCount == 0)
|
|
|
|
{
|
2005-08-13 13:16:16 +00:00
|
|
|
CcRosCacheSegmentDecRefCount(CacheSeg);
|
2002-10-02 19:20:51 +00:00
|
|
|
}
|
|
|
|
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
|
|
|
|
|
- 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-12 19:00:26 +00:00
|
|
|
ExReleasePushLock(&CacheSeg->Lock);
|
2001-12-31 01:53:46 +00:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2008-12-03 17:28:59 +00:00
|
|
|
static
|
|
|
|
NTSTATUS
|
2002-09-08 10:23:54 +00:00
|
|
|
CcRosCreateCacheSegment(PBCB Bcb,
|
2002-01-26 21:21:02 +00:00
|
|
|
ULONG FileOffset,
|
2003-07-15 19:30:33 +00:00
|
|
|
PCACHE_SEGMENT* CacheSeg)
|
2002-01-26 21:21:02 +00:00
|
|
|
{
|
2002-09-08 10:23:54 +00:00
|
|
|
PCACHE_SEGMENT current;
|
2003-05-25 21:49:04 +00:00
|
|
|
PCACHE_SEGMENT previous;
|
2002-10-02 19:20:51 +00:00
|
|
|
PLIST_ENTRY current_entry;
|
2008-05-23 14:40:50 +00:00
|
|
|
NTSTATUS Status;
|
2002-01-26 21:21:02 +00:00
|
|
|
KIRQL oldIrql;
|
2003-01-11 15:24:38 +00:00
|
|
|
#ifdef CACHE_BITMAP
|
|
|
|
ULONG StartingOffset;
|
|
|
|
#endif
|
2003-12-31 05:33:04 +00:00
|
|
|
PHYSICAL_ADDRESS BoundaryAddressMultiple;
|
2004-10-22 20:19:58 +00:00
|
|
|
|
|
|
|
ASSERT(Bcb);
|
2002-12-15 Casper S. Hornstrup <chorns@users.sourceforge.net>
* drivers/fs/vfat/cleanup.c (VfatCleanupFile): Only uninitialize caching
when initialized.
* drivers/fs/vfat/fcb.c (vfatReleaseFCB): Ditto.
* lib/kernel32/mem/section.c (CreateFileMappingW): Pass NULL as
MaximumSize to NtCreateSection if dwMaximumSizeHigh and dwMaximumSizeLow
are both 0.
* ntoskrnl/cc/pin.c (CcMapData): Assert if Bcb is NULL.
* ntoskrnl/cc/view.c (CcRosReleaseCacheSegment, CcRosLookupCacheSegment,
CcRosMarkDirtyCacheSegment, CcRosUnmapCacheSegment,
CcRosCreateCacheSegment, CcRosGetCacheSegmentChain,
CcRosGetCacheSegment, CcRosRequestCacheSegment, CcFlushCache,
CcRosDeleteFileCache, CcRosReferenceCache, CcRosDereferenceCache,
CcRosReleaseFileCache, CcGetFileObjectFromSectionPtrs): Ditto.
* ntoskrnl/mm/section.c (MiReadPage): Assert if Fcb->Bcb is NULL.
(MmCreateDataFileSection): Make sure caching is initialized for the file
stream.
svn path=/trunk/; revision=3879
2002-12-15 17:01:52 +00:00
|
|
|
|
2002-10-02 19:20:51 +00:00
|
|
|
DPRINT("CcRosCreateCacheSegment()\n");
|
2002-01-26 21:21:02 +00:00
|
|
|
|
2003-12-31 05:33:04 +00:00
|
|
|
BoundaryAddressMultiple.QuadPart = 0;
|
2003-06-06 21:02:42 +00:00
|
|
|
if (FileOffset >= Bcb->FileSize.u.LowPart)
|
|
|
|
{
|
|
|
|
CacheSeg = NULL;
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
2003-01-11 15:24:38 +00:00
|
|
|
current = ExAllocateFromNPagedLookasideList(&CacheSegLookasideList);
|
2002-01-26 21:21:02 +00:00
|
|
|
current->Valid = FALSE;
|
|
|
|
current->Dirty = FALSE;
|
2004-02-26 19:29:55 +00:00
|
|
|
current->PageOut = FALSE;
|
2002-01-26 21:21:02 +00:00
|
|
|
current->FileOffset = ROUND_DOWN(FileOffset, Bcb->CacheSegmentSize);
|
|
|
|
current->Bcb = Bcb;
|
2009-10-17 15:03:54 +00:00
|
|
|
#if DBG
|
2005-08-13 13:16:16 +00:00
|
|
|
if ( Bcb->Trace )
|
|
|
|
{
|
|
|
|
DPRINT1("CacheMap 0x%p: new Cache Segment: 0x%p\n", Bcb, current );
|
|
|
|
}
|
|
|
|
#endif
|
2002-01-26 21:21:02 +00:00
|
|
|
current->MappedCount = 0;
|
2002-10-02 19:20:51 +00:00
|
|
|
current->DirtySegmentListEntry.Flink = NULL;
|
|
|
|
current->DirtySegmentListEntry.Blink = NULL;
|
2002-01-26 21:21:02 +00:00
|
|
|
current->ReferenceCount = 1;
|
- 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-12 19:00:26 +00:00
|
|
|
ExInitializePushLock((PULONG_PTR)¤t->Lock);
|
|
|
|
ExAcquirePushLockExclusive(¤t->Lock);
|
|
|
|
KeAcquireGuardedMutex(&ViewLock);
|
2002-10-02 19:20:51 +00:00
|
|
|
|
|
|
|
*CacheSeg = current;
|
|
|
|
/* There is window between the call to CcRosLookupCacheSegment
|
|
|
|
* and CcRosCreateCacheSegment. We must check if a segment on
|
|
|
|
* the fileoffset exist. If there exist a segment, we release
|
2005-05-09 01:38:29 +00:00
|
|
|
* our new created segment and return the existing one.
|
2002-10-02 19:20:51 +00:00
|
|
|
*/
|
2002-01-26 21:21:02 +00:00
|
|
|
KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
|
2002-10-02 19:20:51 +00:00
|
|
|
current_entry = Bcb->BcbSegmentListHead.Flink;
|
2003-05-25 21:49:04 +00:00
|
|
|
previous = NULL;
|
2002-10-02 19:20:51 +00:00
|
|
|
while (current_entry != &Bcb->BcbSegmentListHead)
|
|
|
|
{
|
2005-05-09 01:38:29 +00:00
|
|
|
current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
|
2002-10-02 19:20:51 +00:00
|
|
|
BcbSegmentListEntry);
|
|
|
|
if (current->FileOffset <= FileOffset &&
|
|
|
|
(current->FileOffset + Bcb->CacheSegmentSize) > FileOffset)
|
|
|
|
{
|
2005-08-13 13:16:16 +00:00
|
|
|
CcRosCacheSegmentIncRefCount(current);
|
2002-10-02 19:20:51 +00:00
|
|
|
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
|
2009-10-17 15:03:54 +00:00
|
|
|
#if DBG
|
2005-08-13 13:16:16 +00:00
|
|
|
if ( Bcb->Trace )
|
|
|
|
{
|
|
|
|
DPRINT1("CacheMap 0x%p: deleting newly created Cache Segment 0x%p ( found existing one 0x%p )\n",
|
|
|
|
Bcb,
|
|
|
|
(*CacheSeg),
|
|
|
|
current );
|
|
|
|
}
|
|
|
|
#endif
|
- 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-12 19:00:26 +00:00
|
|
|
ExReleasePushLock(&(*CacheSeg)->Lock);
|
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
2003-01-11 15:24:38 +00:00
|
|
|
ExFreeToNPagedLookasideList(&CacheSegLookasideList, *CacheSeg);
|
2002-10-02 19:20:51 +00:00
|
|
|
*CacheSeg = 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-12 19:00:26 +00:00
|
|
|
ExAcquirePushLockExclusive(¤t->Lock);
|
2002-10-02 19:20:51 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
2003-05-25 21:49:04 +00:00
|
|
|
if (current->FileOffset < FileOffset)
|
|
|
|
{
|
|
|
|
if (previous == NULL)
|
|
|
|
{
|
|
|
|
previous = current;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (previous->FileOffset < current->FileOffset)
|
|
|
|
{
|
|
|
|
previous = current;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-10-02 19:20:51 +00:00
|
|
|
current_entry = current_entry->Flink;
|
|
|
|
}
|
|
|
|
/* There was no existing segment. */
|
|
|
|
current = *CacheSeg;
|
2003-05-25 21:49:04 +00:00
|
|
|
if (previous)
|
|
|
|
{
|
|
|
|
InsertHeadList(&previous->BcbSegmentListEntry, ¤t->BcbSegmentListEntry);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
InsertHeadList(&Bcb->BcbSegmentListHead, ¤t->BcbSegmentListEntry);
|
|
|
|
}
|
2002-01-26 21:21:02 +00:00
|
|
|
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
|
|
|
|
InsertTailList(&CacheSegmentListHead, ¤t->CacheSegmentListEntry);
|
2002-10-02 19:20:51 +00:00
|
|
|
InsertTailList(&CacheSegmentLRUListHead, ¤t->CacheSegmentLRUListEntry);
|
- 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-12 19:00:26 +00:00
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
2003-01-11 15:24:38 +00:00
|
|
|
#ifdef CACHE_BITMAP
|
|
|
|
KeAcquireSpinLock(&CiCacheSegMappingRegionLock, &oldIrql);
|
2002-10-02 19:20:51 +00:00
|
|
|
|
2003-01-11 15:24:38 +00:00
|
|
|
StartingOffset = RtlFindClearBitsAndSet(&CiCacheSegMappingRegionAllocMap, Bcb->CacheSegmentSize / PAGE_SIZE, CiCacheSegMappingRegionHint);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2003-01-11 15:24:38 +00:00
|
|
|
if (StartingOffset == 0xffffffff)
|
|
|
|
{
|
|
|
|
DPRINT1("Out of CacheSeg mapping space\n");
|
2008-08-24 15:48:05 +00:00
|
|
|
KeBugCheck(CACHE_MANAGER);
|
2003-01-11 15:24:38 +00:00
|
|
|
}
|
|
|
|
|
2008-05-23 14:40:50 +00:00
|
|
|
current->BaseAddress = CiCacheSegMappingRegionBase + StartingOffset * PAGE_SIZE;
|
2003-01-11 15:24:38 +00:00
|
|
|
|
|
|
|
if (CiCacheSegMappingRegionHint == StartingOffset)
|
|
|
|
{
|
2005-05-09 01:38:29 +00:00
|
|
|
CiCacheSegMappingRegionHint += Bcb->CacheSegmentSize / PAGE_SIZE;
|
2003-01-11 15:24:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
KeReleaseSpinLock(&CiCacheSegMappingRegionLock, oldIrql);
|
|
|
|
#else
|
2002-10-02 19:20:51 +00:00
|
|
|
MmLockAddressSpace(MmGetKernelAddressSpace());
|
|
|
|
current->BaseAddress = NULL;
|
2005-11-13 17:28:24 +00:00
|
|
|
Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
|
2002-10-02 19:20:51 +00:00
|
|
|
MEMORY_AREA_CACHE_SEGMENT,
|
|
|
|
¤t->BaseAddress,
|
|
|
|
Bcb->CacheSegmentSize,
|
|
|
|
PAGE_READWRITE,
|
|
|
|
(PMEMORY_AREA*)¤t->MemoryArea,
|
2003-05-17 15:29:50 +00:00
|
|
|
FALSE,
|
2005-11-13 17:28:24 +00:00
|
|
|
0,
|
2003-12-31 05:33:04 +00:00
|
|
|
BoundaryAddressMultiple);
|
2002-10-02 19:20:51 +00:00
|
|
|
MmUnlockAddressSpace(MmGetKernelAddressSpace());
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2008-08-24 15:48:05 +00:00
|
|
|
KeBugCheck(CACHE_MANAGER);
|
2002-10-02 19:20:51 +00:00
|
|
|
}
|
2003-01-11 15:24:38 +00:00
|
|
|
#endif
|
2008-03-13 13:17:57 +00:00
|
|
|
|
|
|
|
/* Create a virtual mapping for this memory area */
|
|
|
|
MmMapMemoryArea(current->BaseAddress, Bcb->CacheSegmentSize,
|
|
|
|
MC_CACHE, PAGE_READWRITE);
|
2008-03-08 16:47:41 +00:00
|
|
|
|
2002-01-26 21:21:02 +00:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2005-09-14 01:44:19 +00:00
|
|
|
NTAPI
|
2002-09-08 10:23:54 +00:00
|
|
|
CcRosGetCacheSegmentChain(PBCB Bcb,
|
2002-01-26 21:21:02 +00:00
|
|
|
ULONG FileOffset,
|
|
|
|
ULONG Length,
|
2002-09-08 10:23:54 +00:00
|
|
|
PCACHE_SEGMENT* CacheSeg)
|
2002-01-26 21:21:02 +00:00
|
|
|
{
|
2002-09-08 10:23:54 +00:00
|
|
|
PCACHE_SEGMENT current;
|
2002-01-26 21:21:02 +00:00
|
|
|
ULONG i;
|
2002-09-08 10:23:54 +00:00
|
|
|
PCACHE_SEGMENT* CacheSegList;
|
2002-09-15 10:45:05 +00:00
|
|
|
PCACHE_SEGMENT Previous = NULL;
|
2002-01-26 21:21:02 +00:00
|
|
|
|
2004-10-22 20:19:58 +00:00
|
|
|
ASSERT(Bcb);
|
2002-12-15 Casper S. Hornstrup <chorns@users.sourceforge.net>
* drivers/fs/vfat/cleanup.c (VfatCleanupFile): Only uninitialize caching
when initialized.
* drivers/fs/vfat/fcb.c (vfatReleaseFCB): Ditto.
* lib/kernel32/mem/section.c (CreateFileMappingW): Pass NULL as
MaximumSize to NtCreateSection if dwMaximumSizeHigh and dwMaximumSizeLow
are both 0.
* ntoskrnl/cc/pin.c (CcMapData): Assert if Bcb is NULL.
* ntoskrnl/cc/view.c (CcRosReleaseCacheSegment, CcRosLookupCacheSegment,
CcRosMarkDirtyCacheSegment, CcRosUnmapCacheSegment,
CcRosCreateCacheSegment, CcRosGetCacheSegmentChain,
CcRosGetCacheSegment, CcRosRequestCacheSegment, CcFlushCache,
CcRosDeleteFileCache, CcRosReferenceCache, CcRosDereferenceCache,
CcRosReleaseFileCache, CcGetFileObjectFromSectionPtrs): Ditto.
* ntoskrnl/mm/section.c (MiReadPage): Assert if Fcb->Bcb is NULL.
(MmCreateDataFileSection): Make sure caching is initialized for the file
stream.
svn path=/trunk/; revision=3879
2002-12-15 17:01:52 +00:00
|
|
|
|
2002-10-02 19:20:51 +00:00
|
|
|
DPRINT("CcRosGetCacheSegmentChain()\n");
|
|
|
|
|
2002-01-26 21:21:02 +00:00
|
|
|
Length = ROUND_UP(Length, Bcb->CacheSegmentSize);
|
|
|
|
|
2005-05-09 01:38:29 +00:00
|
|
|
CacheSegList = _alloca(sizeof(PCACHE_SEGMENT) *
|
2003-12-30 18:52:06 +00:00
|
|
|
(Length / Bcb->CacheSegmentSize));
|
2002-01-26 21:21:02 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Look for a cache segment already mapping the same data.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < (Length / Bcb->CacheSegmentSize); i++)
|
|
|
|
{
|
|
|
|
ULONG CurrentOffset = FileOffset + (i * Bcb->CacheSegmentSize);
|
|
|
|
current = CcRosLookupCacheSegment(Bcb, CurrentOffset);
|
|
|
|
if (current != NULL)
|
|
|
|
{
|
|
|
|
CacheSegList[i] = current;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-07-15 19:30:33 +00:00
|
|
|
CcRosCreateCacheSegment(Bcb, CurrentOffset, ¤t);
|
2002-01-26 21:21:02 +00:00
|
|
|
CacheSegList[i] = current;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < (Length / Bcb->CacheSegmentSize); i++)
|
|
|
|
{
|
|
|
|
if (i == 0)
|
|
|
|
{
|
|
|
|
*CacheSeg = CacheSegList[i];
|
|
|
|
Previous = CacheSegList[i];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Previous->NextInChain = CacheSegList[i];
|
|
|
|
Previous = CacheSegList[i];
|
|
|
|
}
|
|
|
|
}
|
2006-10-25 16:37:46 +00:00
|
|
|
ASSERT(Previous);
|
2002-01-26 21:21:02 +00:00
|
|
|
Previous->NextInChain = NULL;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2002-01-26 21:21:02 +00:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2001-04-03 17:25:50 +00:00
|
|
|
NTSTATUS
|
2005-09-14 01:44:19 +00:00
|
|
|
NTAPI
|
2002-09-08 10:23:54 +00:00
|
|
|
CcRosGetCacheSegment(PBCB Bcb,
|
2001-12-27 23:56:42 +00:00
|
|
|
ULONG FileOffset,
|
|
|
|
PULONG BaseOffset,
|
|
|
|
PVOID* BaseAddress,
|
|
|
|
PBOOLEAN UptoDate,
|
2002-09-08 10:23:54 +00:00
|
|
|
PCACHE_SEGMENT* CacheSeg)
|
1998-12-21 15:48:21 +00:00
|
|
|
{
|
2002-09-08 10:23:54 +00:00
|
|
|
PCACHE_SEGMENT current;
|
2001-08-03 09:36:19 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
|
2004-10-22 20:19:58 +00:00
|
|
|
ASSERT(Bcb);
|
2002-12-15 Casper S. Hornstrup <chorns@users.sourceforge.net>
* drivers/fs/vfat/cleanup.c (VfatCleanupFile): Only uninitialize caching
when initialized.
* drivers/fs/vfat/fcb.c (vfatReleaseFCB): Ditto.
* lib/kernel32/mem/section.c (CreateFileMappingW): Pass NULL as
MaximumSize to NtCreateSection if dwMaximumSizeHigh and dwMaximumSizeLow
are both 0.
* ntoskrnl/cc/pin.c (CcMapData): Assert if Bcb is NULL.
* ntoskrnl/cc/view.c (CcRosReleaseCacheSegment, CcRosLookupCacheSegment,
CcRosMarkDirtyCacheSegment, CcRosUnmapCacheSegment,
CcRosCreateCacheSegment, CcRosGetCacheSegmentChain,
CcRosGetCacheSegment, CcRosRequestCacheSegment, CcFlushCache,
CcRosDeleteFileCache, CcRosReferenceCache, CcRosDereferenceCache,
CcRosReleaseFileCache, CcGetFileObjectFromSectionPtrs): Ditto.
* ntoskrnl/mm/section.c (MiReadPage): Assert if Fcb->Bcb is NULL.
(MmCreateDataFileSection): Make sure caching is initialized for the file
stream.
svn path=/trunk/; revision=3879
2002-12-15 17:01:52 +00:00
|
|
|
|
2002-10-02 19:20:51 +00:00
|
|
|
DPRINT("CcRosGetCacheSegment()\n");
|
2001-12-27 23:56:42 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Look for a cache segment already mapping the same data.
|
|
|
|
*/
|
2001-12-31 01:53:46 +00:00
|
|
|
current = CcRosLookupCacheSegment(Bcb, FileOffset);
|
2003-07-15 19:30:33 +00:00
|
|
|
if (current == NULL)
|
2002-10-02 19:20:51 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Otherwise create a new segment.
|
|
|
|
*/
|
2003-07-15 19:30:33 +00:00
|
|
|
Status = CcRosCreateCacheSegment(Bcb, FileOffset, ¤t);
|
2003-05-25 21:49:04 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return Status;
|
|
|
|
}
|
2002-10-02 19:20:51 +00:00
|
|
|
}
|
2001-12-27 23:56:42 +00:00
|
|
|
/*
|
2002-10-02 19:20:51 +00:00
|
|
|
* Return information about the segment to the caller.
|
2001-12-27 23:56:42 +00:00
|
|
|
*/
|
1999-04-05 15:04:46 +00:00
|
|
|
*UptoDate = current->Valid;
|
|
|
|
*BaseAddress = current->BaseAddress;
|
2002-01-26 21:21:02 +00:00
|
|
|
DPRINT("*BaseAddress 0x%.8X\n", *BaseAddress);
|
1999-05-29 00:15:17 +00:00
|
|
|
*CacheSeg = current;
|
2001-04-03 17:25:50 +00:00
|
|
|
*BaseOffset = current->FileOffset;
|
1999-05-29 00:15:17 +00:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2008-11-29 20:47:48 +00:00
|
|
|
NTSTATUS NTAPI
|
2002-09-08 10:23:54 +00:00
|
|
|
CcRosRequestCacheSegment(PBCB Bcb,
|
2001-04-03 17:25:50 +00:00
|
|
|
ULONG FileOffset,
|
|
|
|
PVOID* BaseAddress,
|
|
|
|
PBOOLEAN UptoDate,
|
2002-09-08 10:23:54 +00:00
|
|
|
PCACHE_SEGMENT* CacheSeg)
|
2001-04-03 17:25:50 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Request a page mapping for a BCB
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
ULONG BaseOffset;
|
2002-10-02 19:20:51 +00:00
|
|
|
|
2004-10-22 20:19:58 +00:00
|
|
|
ASSERT(Bcb);
|
2002-12-15 Casper S. Hornstrup <chorns@users.sourceforge.net>
* drivers/fs/vfat/cleanup.c (VfatCleanupFile): Only uninitialize caching
when initialized.
* drivers/fs/vfat/fcb.c (vfatReleaseFCB): Ditto.
* lib/kernel32/mem/section.c (CreateFileMappingW): Pass NULL as
MaximumSize to NtCreateSection if dwMaximumSizeHigh and dwMaximumSizeLow
are both 0.
* ntoskrnl/cc/pin.c (CcMapData): Assert if Bcb is NULL.
* ntoskrnl/cc/view.c (CcRosReleaseCacheSegment, CcRosLookupCacheSegment,
CcRosMarkDirtyCacheSegment, CcRosUnmapCacheSegment,
CcRosCreateCacheSegment, CcRosGetCacheSegmentChain,
CcRosGetCacheSegment, CcRosRequestCacheSegment, CcFlushCache,
CcRosDeleteFileCache, CcRosReferenceCache, CcRosDereferenceCache,
CcRosReleaseFileCache, CcGetFileObjectFromSectionPtrs): Ditto.
* ntoskrnl/mm/section.c (MiReadPage): Assert if Fcb->Bcb is NULL.
(MmCreateDataFileSection): Make sure caching is initialized for the file
stream.
svn path=/trunk/; revision=3879
2002-12-15 17:01:52 +00:00
|
|
|
|
2001-04-03 17:25:50 +00:00
|
|
|
if ((FileOffset % Bcb->CacheSegmentSize) != 0)
|
|
|
|
{
|
2008-08-24 15:48:05 +00:00
|
|
|
DPRINT1("Bad fileoffset %x should be multiple of %x",
|
2001-05-01 23:08:21 +00:00
|
|
|
FileOffset, Bcb->CacheSegmentSize);
|
2008-08-24 15:48:05 +00:00
|
|
|
KeBugCheck(CACHE_MANAGER);
|
2001-04-03 17:25:50 +00:00
|
|
|
}
|
|
|
|
|
2001-05-04 01:21:45 +00:00
|
|
|
return(CcRosGetCacheSegment(Bcb,
|
2001-04-03 17:25:50 +00:00
|
|
|
FileOffset,
|
|
|
|
&BaseOffset,
|
|
|
|
BaseAddress,
|
|
|
|
UptoDate,
|
|
|
|
CacheSeg));
|
|
|
|
}
|
2003-01-11 15:24:38 +00:00
|
|
|
#ifdef CACHE_BITMAP
|
|
|
|
#else
|
2006-09-07 05:07:34 +00:00
|
|
|
static VOID
|
2005-05-09 01:38:29 +00:00
|
|
|
CcFreeCachePage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
|
2004-08-01 07:24:59 +00:00
|
|
|
PFN_TYPE Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
|
2001-02-10 22:51:11 +00:00
|
|
|
{
|
2004-10-22 20:19:58 +00:00
|
|
|
ASSERT(SwapEntry == 0);
|
2004-08-01 07:24:59 +00:00
|
|
|
if (Page != 0)
|
2001-02-10 22:51:11 +00:00
|
|
|
{
|
2004-08-01 07:24:59 +00:00
|
|
|
MmReleasePageMemoryConsumer(MC_CACHE, Page);
|
2001-02-10 22:51:11 +00:00
|
|
|
}
|
|
|
|
}
|
2003-01-11 15:24:38 +00:00
|
|
|
#endif
|
2005-05-09 01:38:29 +00:00
|
|
|
NTSTATUS
|
2002-10-02 19:20:51 +00:00
|
|
|
CcRosInternalFreeCacheSegment(PCACHE_SEGMENT CacheSeg)
|
2000-12-10 23:42:01 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Releases a cache segment associated with a BCB
|
|
|
|
*/
|
1999-05-29 00:15:17 +00:00
|
|
|
{
|
2003-01-11 15:24:38 +00:00
|
|
|
#ifdef CACHE_BITMAP
|
|
|
|
ULONG i;
|
|
|
|
ULONG RegionSize;
|
|
|
|
ULONG Base;
|
2004-08-01 07:24:59 +00:00
|
|
|
PFN_TYPE Page;
|
2003-01-11 15:24:38 +00:00
|
|
|
KIRQL oldIrql;
|
|
|
|
#endif
|
2005-07-04 22:11:00 +00:00
|
|
|
DPRINT("Freeing cache segment 0x%p\n", CacheSeg);
|
2009-10-17 15:03:54 +00:00
|
|
|
#if DBG
|
2005-08-13 13:16:16 +00:00
|
|
|
if ( CacheSeg->Bcb->Trace )
|
|
|
|
{
|
|
|
|
DPRINT1("CacheMap 0x%p: deleting Cache Segment: 0x%p\n", CacheSeg->Bcb, CacheSeg );
|
|
|
|
}
|
|
|
|
#endif
|
2003-01-11 15:24:38 +00:00
|
|
|
#ifdef CACHE_BITMAP
|
|
|
|
RegionSize = CacheSeg->Bcb->CacheSegmentSize / PAGE_SIZE;
|
|
|
|
|
|
|
|
/* Unmap all the pages. */
|
|
|
|
for (i = 0; i < RegionSize; i++)
|
|
|
|
{
|
2005-05-09 01:38:29 +00:00
|
|
|
MmDeleteVirtualMapping(NULL,
|
2008-05-23 14:40:50 +00:00
|
|
|
CacheSeg->BaseAddress + (i * PAGE_SIZE),
|
2003-01-11 15:24:38 +00:00
|
|
|
FALSE,
|
|
|
|
NULL,
|
2004-08-01 07:24:59 +00:00
|
|
|
&Page);
|
|
|
|
MmReleasePageMemoryConsumer(MC_CACHE, Page);
|
2003-01-11 15:24:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
KeAcquireSpinLock(&CiCacheSegMappingRegionLock, &oldIrql);
|
|
|
|
/* Deallocate all the pages used. */
|
2008-05-23 14:40:50 +00:00
|
|
|
Base = (ULONG)(CacheSeg->BaseAddress - CiCacheSegMappingRegionBase) / PAGE_SIZE;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2003-01-11 15:24:38 +00:00
|
|
|
RtlClearBits(&CiCacheSegMappingRegionAllocMap, Base, RegionSize);
|
2002-10-02 19:20:51 +00:00
|
|
|
|
2003-01-11 15:24:38 +00:00
|
|
|
CiCacheSegMappingRegionHint = min (CiCacheSegMappingRegionHint, Base);
|
|
|
|
|
|
|
|
KeReleaseSpinLock(&CiCacheSegMappingRegionLock, oldIrql);
|
|
|
|
#else
|
2001-12-29 14:32:22 +00:00
|
|
|
MmLockAddressSpace(MmGetKernelAddressSpace());
|
2001-03-09 14:40:28 +00:00
|
|
|
MmFreeMemoryArea(MmGetKernelAddressSpace(),
|
2005-01-02 17:55:06 +00:00
|
|
|
CacheSeg->MemoryArea,
|
2001-03-09 14:40:28 +00:00
|
|
|
CcFreeCachePage,
|
2001-12-31 01:53:46 +00:00
|
|
|
NULL);
|
2001-12-29 14:32:22 +00:00
|
|
|
MmUnlockAddressSpace(MmGetKernelAddressSpace());
|
2003-01-11 15:24:38 +00:00
|
|
|
#endif
|
|
|
|
ExFreeToNPagedLookasideList(&CacheSegLookasideList, CacheSeg);
|
2001-03-09 14:40:28 +00:00
|
|
|
return(STATUS_SUCCESS);
|
1999-05-29 00:15:17 +00:00
|
|
|
}
|
|
|
|
|
2003-01-11 15:24:38 +00:00
|
|
|
NTSTATUS
|
2005-09-14 01:44:19 +00:00
|
|
|
NTAPI
|
2002-09-08 10:23:54 +00:00
|
|
|
CcRosFreeCacheSegment(PBCB Bcb, PCACHE_SEGMENT CacheSeg)
|
2001-12-29 14:32:22 +00:00
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
2002-10-02 19:20:51 +00:00
|
|
|
KIRQL oldIrql;
|
|
|
|
|
2004-10-22 20:19:58 +00:00
|
|
|
ASSERT(Bcb);
|
2002-12-15 Casper S. Hornstrup <chorns@users.sourceforge.net>
* drivers/fs/vfat/cleanup.c (VfatCleanupFile): Only uninitialize caching
when initialized.
* drivers/fs/vfat/fcb.c (vfatReleaseFCB): Ditto.
* lib/kernel32/mem/section.c (CreateFileMappingW): Pass NULL as
MaximumSize to NtCreateSection if dwMaximumSizeHigh and dwMaximumSizeLow
are both 0.
* ntoskrnl/cc/pin.c (CcMapData): Assert if Bcb is NULL.
* ntoskrnl/cc/view.c (CcRosReleaseCacheSegment, CcRosLookupCacheSegment,
CcRosMarkDirtyCacheSegment, CcRosUnmapCacheSegment,
CcRosCreateCacheSegment, CcRosGetCacheSegmentChain,
CcRosGetCacheSegment, CcRosRequestCacheSegment, CcFlushCache,
CcRosDeleteFileCache, CcRosReferenceCache, CcRosDereferenceCache,
CcRosReleaseFileCache, CcGetFileObjectFromSectionPtrs): Ditto.
* ntoskrnl/mm/section.c (MiReadPage): Assert if Fcb->Bcb is NULL.
(MmCreateDataFileSection): Make sure caching is initialized for the file
stream.
svn path=/trunk/; revision=3879
2002-12-15 17:01:52 +00:00
|
|
|
|
2005-07-04 22:11:00 +00:00
|
|
|
DPRINT("CcRosFreeCacheSegment(Bcb 0x%p, CacheSeg 0x%p)\n",
|
2002-10-02 19:20:51 +00:00
|
|
|
Bcb, CacheSeg);
|
|
|
|
|
- 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-12 19:00:26 +00:00
|
|
|
KeAcquireGuardedMutex(&ViewLock);
|
2002-10-02 19:20:51 +00:00
|
|
|
KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
|
|
|
|
RemoveEntryList(&CacheSeg->BcbSegmentListEntry);
|
|
|
|
RemoveEntryList(&CacheSeg->CacheSegmentListEntry);
|
|
|
|
RemoveEntryList(&CacheSeg->CacheSegmentLRUListEntry);
|
|
|
|
if (CacheSeg->Dirty)
|
|
|
|
{
|
|
|
|
RemoveEntryList(&CacheSeg->DirtySegmentListEntry);
|
2003-01-30 18:30:53 +00:00
|
|
|
DirtyPageCount -= Bcb->CacheSegmentSize / PAGE_SIZE;
|
|
|
|
|
2002-10-02 19:20:51 +00:00
|
|
|
}
|
|
|
|
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
|
- 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-12 19:00:26 +00:00
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
2002-10-02 19:20:51 +00:00
|
|
|
|
|
|
|
Status = CcRosInternalFreeCacheSegment(CacheSeg);
|
2001-12-29 14:32:22 +00:00
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
2003-07-10 06:27:13 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2008-11-29 20:47:48 +00:00
|
|
|
VOID NTAPI
|
2002-10-02 19:20:51 +00:00
|
|
|
CcFlushCache(IN PSECTION_OBJECT_POINTERS SectionObjectPointers,
|
|
|
|
IN PLARGE_INTEGER FileOffset OPTIONAL,
|
|
|
|
IN ULONG Length,
|
|
|
|
OUT PIO_STATUS_BLOCK IoStatus)
|
|
|
|
{
|
|
|
|
PBCB Bcb;
|
|
|
|
LARGE_INTEGER Offset;
|
|
|
|
PCACHE_SEGMENT current;
|
|
|
|
NTSTATUS Status;
|
|
|
|
KIRQL oldIrql;
|
|
|
|
|
2005-07-04 22:11:00 +00:00
|
|
|
DPRINT("CcFlushCache(SectionObjectPointers 0x%p, FileOffset 0x%p, Length %d, IoStatus 0x%p)\n",
|
2002-10-02 19:20:51 +00:00
|
|
|
SectionObjectPointers, FileOffset, Length, IoStatus);
|
|
|
|
|
|
|
|
if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap)
|
|
|
|
{
|
|
|
|
Bcb = (PBCB)SectionObjectPointers->SharedCacheMap;
|
2004-10-22 20:19:58 +00:00
|
|
|
ASSERT(Bcb);
|
2002-10-02 19:20:51 +00:00
|
|
|
if (FileOffset)
|
|
|
|
{
|
|
|
|
Offset = *FileOffset;
|
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
else
|
2002-10-02 19:20:51 +00:00
|
|
|
{
|
2004-10-22 20:19:58 +00:00
|
|
|
Offset.QuadPart = (LONGLONG)0;
|
2002-10-02 19:20:51 +00:00
|
|
|
Length = Bcb->FileSize.u.LowPart;
|
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2002-10-02 19:20:51 +00:00
|
|
|
if (IoStatus)
|
|
|
|
{
|
|
|
|
IoStatus->Status = STATUS_SUCCESS;
|
|
|
|
IoStatus->Information = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (Length > 0)
|
|
|
|
{
|
|
|
|
current = CcRosLookupCacheSegment (Bcb, Offset.u.LowPart);
|
|
|
|
if (current != NULL)
|
|
|
|
{
|
|
|
|
if (current->Dirty)
|
|
|
|
{
|
|
|
|
Status = CcRosFlushCacheSegment(current);
|
|
|
|
if (!NT_SUCCESS(Status) && IoStatus != NULL)
|
|
|
|
{
|
|
|
|
IoStatus->Status = Status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
|
- 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-12 19:00:26 +00:00
|
|
|
ExReleasePushLock(¤t->Lock);
|
2005-08-13 13:16:16 +00:00
|
|
|
CcRosCacheSegmentDecRefCount(current);
|
2002-10-02 19:20:51 +00:00
|
|
|
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
|
|
|
|
}
|
|
|
|
|
|
|
|
Offset.QuadPart += Bcb->CacheSegmentSize;
|
|
|
|
if (Length > Bcb->CacheSegmentSize)
|
|
|
|
{
|
|
|
|
Length -= Bcb->CacheSegmentSize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Length = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (IoStatus)
|
|
|
|
{
|
|
|
|
IoStatus->Status = STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-05-09 01:38:29 +00:00
|
|
|
NTSTATUS
|
2005-09-14 01:44:19 +00:00
|
|
|
NTAPI
|
2002-09-08 10:23:54 +00:00
|
|
|
CcRosDeleteFileCache(PFILE_OBJECT FileObject, PBCB Bcb)
|
2000-12-10 23:42:01 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Releases the BCB associated with a file object
|
|
|
|
*/
|
1999-05-29 00:15:17 +00:00
|
|
|
{
|
|
|
|
PLIST_ENTRY current_entry;
|
2002-09-08 10:23:54 +00:00
|
|
|
PCACHE_SEGMENT current;
|
2002-07-17 21:04:57 +00:00
|
|
|
NTSTATUS Status;
|
2002-10-02 19:20:51 +00:00
|
|
|
LIST_ENTRY FreeList;
|
|
|
|
KIRQL oldIrql;
|
2001-03-09 14:40:28 +00:00
|
|
|
|
2004-10-22 20:19:58 +00:00
|
|
|
ASSERT(Bcb);
|
|
|
|
|
2003-01-11 15:24:38 +00:00
|
|
|
Bcb->RefCount++;
|
- 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-12 19:00:26 +00:00
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
2002-07-17 21:04:57 +00:00
|
|
|
|
2003-06-07 Casper S. Hornstrup <chorns@users.sourceforge.net>
Changes for compiling with w32api
* include/ddk/cctypes.h (PREACTOS_COMMON_FCB_HEADER): Remove.
(FSRTL_COMMON_FCB_HEADER): Add.
* include/ddk/iotypes.h (FILE_OBJECT): Rename field
SectionObjectPointers to SectionObjectPointer.
* ntoskrnl/cc/copy.c, ntoskrnl/cc/misc.c, ntoskrnl/cc/pin.c,
ntoskrnl/cc/view.c, ntoskrnl/io/rawfs.c, ntoskrnl/mm/section.c,
drivers/fs/cdfs/cleanup.c, drivers/fs/cdfs/fcb.c,
drivers/fs/cdfs/fsctl.c, drivers/fs/ntfs/fcb.c, drivers/fs/ntfs/fsctl.c,
drivers/fs/vfat/close.c, drivers/fs/vfat/create.c,
drivers/fs/vfat/finfo.c, drivers/fs/vfat/fcb.c, drivers/fs/vfat/fsctl.c:
Use new FILE_OBJECT structure.
* drivers/fs/cdfs/cdfs.h, drivers/fs/ntfs/ntfs.h, drivers/fs/vfat/vfat.h:
Use new FSRTL_COMMON_FCB_HEADER structure.
* drivers/net/afd/include/afd.h (FSRTL_COMMON_FCB_HEADER): Remove.
* include/ddk/ketypes.h (KQUEUE): Match w32api structure.
* ntoskrnl/ke/queue.c, ntoskrnl/ke/wait.c: Use new structure.
* ntoskrnl/ke/spinlock.c (KeAcquireSpinLockAtDpcLevel,
KeReleaseSpinLockFromDpcLevel): Undefine before declaring.
svn path=/trunk/; revision=4865
2003-06-07 11:34:36 +00:00
|
|
|
CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, NULL);
|
2002-10-02 19:20:51 +00: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-12 19:00:26 +00:00
|
|
|
KeAcquireGuardedMutex(&ViewLock);
|
2003-01-11 15:24:38 +00:00
|
|
|
Bcb->RefCount--;
|
2002-10-02 19:20:51 +00:00
|
|
|
if (Bcb->RefCount == 0)
|
|
|
|
{
|
2003-01-11 15:24:38 +00:00
|
|
|
if (Bcb->BcbRemoveListEntry.Flink != NULL)
|
|
|
|
{
|
|
|
|
RemoveEntryList(&Bcb->BcbRemoveListEntry);
|
|
|
|
Bcb->BcbRemoveListEntry.Flink = NULL;
|
|
|
|
}
|
|
|
|
|
2005-05-09 01:38:29 +00:00
|
|
|
FileObject->SectionObjectPointer->SharedCacheMap = NULL;
|
2002-10-02 19:20:51 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Release all cache segments.
|
|
|
|
*/
|
|
|
|
InitializeListHead(&FreeList);
|
|
|
|
KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
|
|
|
|
current_entry = Bcb->BcbSegmentListHead.Flink;
|
|
|
|
while (!IsListEmpty(&Bcb->BcbSegmentListHead))
|
|
|
|
{
|
|
|
|
current_entry = RemoveTailList(&Bcb->BcbSegmentListHead);
|
|
|
|
current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
|
|
|
|
RemoveEntryList(¤t->CacheSegmentListEntry);
|
|
|
|
RemoveEntryList(¤t->CacheSegmentLRUListEntry);
|
|
|
|
if (current->Dirty)
|
2002-07-17 21:04:57 +00:00
|
|
|
{
|
2002-10-02 19:20:51 +00:00
|
|
|
RemoveEntryList(¤t->DirtySegmentListEntry);
|
2003-01-30 18:30:53 +00:00
|
|
|
DirtyPageCount -= Bcb->CacheSegmentSize / PAGE_SIZE;
|
2003-01-11 15:24:38 +00:00
|
|
|
DPRINT1("Freeing dirty segment\n");
|
2002-07-17 21:04:57 +00:00
|
|
|
}
|
2002-10-02 19:20:51 +00:00
|
|
|
InsertHeadList(&FreeList, ¤t->BcbSegmentListEntry);
|
|
|
|
}
|
2009-10-17 15:03:54 +00:00
|
|
|
#if DBG
|
2005-08-13 13:16:16 +00:00
|
|
|
Bcb->Trace = FALSE;
|
|
|
|
#endif
|
2005-05-09 01:38:29 +00:00
|
|
|
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
|
2003-01-11 15:24:38 +00: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-12 19:00:26 +00:00
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
2003-01-11 15:24:38 +00:00
|
|
|
ObDereferenceObject (Bcb->FileObject);
|
|
|
|
|
2002-10-02 19:20:51 +00:00
|
|
|
while (!IsListEmpty(&FreeList))
|
|
|
|
{
|
|
|
|
current_entry = RemoveTailList(&FreeList);
|
|
|
|
current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
|
|
|
|
Status = CcRosInternalFreeCacheSegment(current);
|
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
ExFreeToNPagedLookasideList(&BcbLookasideList, Bcb);
|
- 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-12 19:00:26 +00:00
|
|
|
KeAcquireGuardedMutex(&ViewLock);
|
2002-10-02 19:20:51 +00:00
|
|
|
}
|
1999-04-05 15:04:46 +00:00
|
|
|
return(STATUS_SUCCESS);
|
1998-12-21 15:48:21 +00:00
|
|
|
}
|
|
|
|
|
2005-09-14 01:44:19 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
CcRosReferenceCache(PFILE_OBJECT FileObject)
|
2002-08-17 15:14:26 +00:00
|
|
|
{
|
2002-10-02 19:20:51 +00:00
|
|
|
PBCB Bcb;
|
- 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-12 19:00:26 +00:00
|
|
|
KeAcquireGuardedMutex(&ViewLock);
|
2003-06-07 Casper S. Hornstrup <chorns@users.sourceforge.net>
Changes for compiling with w32api
* include/ddk/cctypes.h (PREACTOS_COMMON_FCB_HEADER): Remove.
(FSRTL_COMMON_FCB_HEADER): Add.
* include/ddk/iotypes.h (FILE_OBJECT): Rename field
SectionObjectPointers to SectionObjectPointer.
* ntoskrnl/cc/copy.c, ntoskrnl/cc/misc.c, ntoskrnl/cc/pin.c,
ntoskrnl/cc/view.c, ntoskrnl/io/rawfs.c, ntoskrnl/mm/section.c,
drivers/fs/cdfs/cleanup.c, drivers/fs/cdfs/fcb.c,
drivers/fs/cdfs/fsctl.c, drivers/fs/ntfs/fcb.c, drivers/fs/ntfs/fsctl.c,
drivers/fs/vfat/close.c, drivers/fs/vfat/create.c,
drivers/fs/vfat/finfo.c, drivers/fs/vfat/fcb.c, drivers/fs/vfat/fsctl.c:
Use new FILE_OBJECT structure.
* drivers/fs/cdfs/cdfs.h, drivers/fs/ntfs/ntfs.h, drivers/fs/vfat/vfat.h:
Use new FSRTL_COMMON_FCB_HEADER structure.
* drivers/net/afd/include/afd.h (FSRTL_COMMON_FCB_HEADER): Remove.
* include/ddk/ketypes.h (KQUEUE): Match w32api structure.
* ntoskrnl/ke/queue.c, ntoskrnl/ke/wait.c: Use new structure.
* ntoskrnl/ke/spinlock.c (KeAcquireSpinLockAtDpcLevel,
KeReleaseSpinLockFromDpcLevel): Undefine before declaring.
svn path=/trunk/; revision=4865
2003-06-07 11:34:36 +00:00
|
|
|
Bcb = (PBCB)FileObject->SectionObjectPointer->SharedCacheMap;
|
2004-10-22 20:19:58 +00:00
|
|
|
ASSERT(Bcb);
|
2003-05-25 21:49:04 +00:00
|
|
|
if (Bcb->RefCount == 0)
|
|
|
|
{
|
2004-10-22 20:19:58 +00:00
|
|
|
ASSERT(Bcb->BcbRemoveListEntry.Flink != NULL);
|
2003-05-25 21:49:04 +00:00
|
|
|
RemoveEntryList(&Bcb->BcbRemoveListEntry);
|
|
|
|
Bcb->BcbRemoveListEntry.Flink = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-10-22 20:19:58 +00:00
|
|
|
ASSERT(Bcb->BcbRemoveListEntry.Flink == NULL);
|
2003-05-25 21:49:04 +00:00
|
|
|
}
|
2002-08-17 15:14:26 +00:00
|
|
|
Bcb->RefCount++;
|
- 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-12 19:00:26 +00:00
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
2002-08-17 15:14:26 +00:00
|
|
|
}
|
|
|
|
|
2005-09-14 01:44:19 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
CcRosSetRemoveOnClose(PSECTION_OBJECT_POINTERS SectionObjectPointer)
|
2003-01-11 15:24:38 +00:00
|
|
|
{
|
|
|
|
PBCB Bcb;
|
2003-07-15 19:30:33 +00:00
|
|
|
DPRINT("CcRosSetRemoveOnClose()\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-12 19:00:26 +00:00
|
|
|
KeAcquireGuardedMutex(&ViewLock);
|
2003-01-11 15:24:38 +00:00
|
|
|
Bcb = (PBCB)SectionObjectPointer->SharedCacheMap;
|
|
|
|
if (Bcb)
|
|
|
|
{
|
|
|
|
Bcb->RemoveOnClose = TRUE;
|
|
|
|
if (Bcb->RefCount == 0)
|
|
|
|
{
|
|
|
|
CcRosDeleteFileCache(Bcb->FileObject, Bcb);
|
|
|
|
}
|
|
|
|
}
|
- 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-12 19:00:26 +00:00
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
2003-01-11 15:24:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-14 01:44:19 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
CcRosDereferenceCache(PFILE_OBJECT FileObject)
|
2002-08-17 15:14:26 +00:00
|
|
|
{
|
2002-10-02 19:20:51 +00:00
|
|
|
PBCB Bcb;
|
- 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-12 19:00:26 +00:00
|
|
|
KeAcquireGuardedMutex(&ViewLock);
|
2003-06-07 Casper S. Hornstrup <chorns@users.sourceforge.net>
Changes for compiling with w32api
* include/ddk/cctypes.h (PREACTOS_COMMON_FCB_HEADER): Remove.
(FSRTL_COMMON_FCB_HEADER): Add.
* include/ddk/iotypes.h (FILE_OBJECT): Rename field
SectionObjectPointers to SectionObjectPointer.
* ntoskrnl/cc/copy.c, ntoskrnl/cc/misc.c, ntoskrnl/cc/pin.c,
ntoskrnl/cc/view.c, ntoskrnl/io/rawfs.c, ntoskrnl/mm/section.c,
drivers/fs/cdfs/cleanup.c, drivers/fs/cdfs/fcb.c,
drivers/fs/cdfs/fsctl.c, drivers/fs/ntfs/fcb.c, drivers/fs/ntfs/fsctl.c,
drivers/fs/vfat/close.c, drivers/fs/vfat/create.c,
drivers/fs/vfat/finfo.c, drivers/fs/vfat/fcb.c, drivers/fs/vfat/fsctl.c:
Use new FILE_OBJECT structure.
* drivers/fs/cdfs/cdfs.h, drivers/fs/ntfs/ntfs.h, drivers/fs/vfat/vfat.h:
Use new FSRTL_COMMON_FCB_HEADER structure.
* drivers/net/afd/include/afd.h (FSRTL_COMMON_FCB_HEADER): Remove.
* include/ddk/ketypes.h (KQUEUE): Match w32api structure.
* ntoskrnl/ke/queue.c, ntoskrnl/ke/wait.c: Use new structure.
* ntoskrnl/ke/spinlock.c (KeAcquireSpinLockAtDpcLevel,
KeReleaseSpinLockFromDpcLevel): Undefine before declaring.
svn path=/trunk/; revision=4865
2003-06-07 11:34:36 +00:00
|
|
|
Bcb = (PBCB)FileObject->SectionObjectPointer->SharedCacheMap;
|
2004-10-22 20:19:58 +00:00
|
|
|
ASSERT(Bcb);
|
2003-01-11 15:24:38 +00:00
|
|
|
if (Bcb->RefCount > 0)
|
2002-08-17 15:14:26 +00:00
|
|
|
{
|
2003-01-11 15:24:38 +00:00
|
|
|
Bcb->RefCount--;
|
|
|
|
if (Bcb->RefCount == 0)
|
|
|
|
{
|
|
|
|
MmFreeSectionSegments(Bcb->FileObject);
|
|
|
|
CcRosDeleteFileCache(FileObject, Bcb);
|
|
|
|
}
|
2002-08-17 15:14:26 +00: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-12 19:00:26 +00:00
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
2002-08-17 15:14:26 +00:00
|
|
|
}
|
|
|
|
|
2008-11-29 20:47:48 +00:00
|
|
|
NTSTATUS NTAPI
|
2003-02-13 22:24:19 +00:00
|
|
|
CcRosReleaseFileCache(PFILE_OBJECT FileObject)
|
2002-08-08 17:54:16 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Called by the file system when a handle to a file object
|
|
|
|
* has been closed.
|
|
|
|
*/
|
|
|
|
{
|
2003-02-13 22:24:19 +00:00
|
|
|
PBCB Bcb;
|
2002-12-15 Casper S. Hornstrup <chorns@users.sourceforge.net>
* drivers/fs/vfat/cleanup.c (VfatCleanupFile): Only uninitialize caching
when initialized.
* drivers/fs/vfat/fcb.c (vfatReleaseFCB): Ditto.
* lib/kernel32/mem/section.c (CreateFileMappingW): Pass NULL as
MaximumSize to NtCreateSection if dwMaximumSizeHigh and dwMaximumSizeLow
are both 0.
* ntoskrnl/cc/pin.c (CcMapData): Assert if Bcb is NULL.
* ntoskrnl/cc/view.c (CcRosReleaseCacheSegment, CcRosLookupCacheSegment,
CcRosMarkDirtyCacheSegment, CcRosUnmapCacheSegment,
CcRosCreateCacheSegment, CcRosGetCacheSegmentChain,
CcRosGetCacheSegment, CcRosRequestCacheSegment, CcFlushCache,
CcRosDeleteFileCache, CcRosReferenceCache, CcRosDereferenceCache,
CcRosReleaseFileCache, CcGetFileObjectFromSectionPtrs): Ditto.
* ntoskrnl/mm/section.c (MiReadPage): Assert if Fcb->Bcb is NULL.
(MmCreateDataFileSection): Make sure caching is initialized for the file
stream.
svn path=/trunk/; revision=3879
2002-12-15 17:01:52 +00: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-12 19:00:26 +00:00
|
|
|
KeAcquireGuardedMutex(&ViewLock);
|
2002-10-02 19:20:51 +00:00
|
|
|
|
2003-06-07 Casper S. Hornstrup <chorns@users.sourceforge.net>
Changes for compiling with w32api
* include/ddk/cctypes.h (PREACTOS_COMMON_FCB_HEADER): Remove.
(FSRTL_COMMON_FCB_HEADER): Add.
* include/ddk/iotypes.h (FILE_OBJECT): Rename field
SectionObjectPointers to SectionObjectPointer.
* ntoskrnl/cc/copy.c, ntoskrnl/cc/misc.c, ntoskrnl/cc/pin.c,
ntoskrnl/cc/view.c, ntoskrnl/io/rawfs.c, ntoskrnl/mm/section.c,
drivers/fs/cdfs/cleanup.c, drivers/fs/cdfs/fcb.c,
drivers/fs/cdfs/fsctl.c, drivers/fs/ntfs/fcb.c, drivers/fs/ntfs/fsctl.c,
drivers/fs/vfat/close.c, drivers/fs/vfat/create.c,
drivers/fs/vfat/finfo.c, drivers/fs/vfat/fcb.c, drivers/fs/vfat/fsctl.c:
Use new FILE_OBJECT structure.
* drivers/fs/cdfs/cdfs.h, drivers/fs/ntfs/ntfs.h, drivers/fs/vfat/vfat.h:
Use new FSRTL_COMMON_FCB_HEADER structure.
* drivers/net/afd/include/afd.h (FSRTL_COMMON_FCB_HEADER): Remove.
* include/ddk/ketypes.h (KQUEUE): Match w32api structure.
* ntoskrnl/ke/queue.c, ntoskrnl/ke/wait.c: Use new structure.
* ntoskrnl/ke/spinlock.c (KeAcquireSpinLockAtDpcLevel,
KeReleaseSpinLockFromDpcLevel): Undefine before declaring.
svn path=/trunk/; revision=4865
2003-06-07 11:34:36 +00:00
|
|
|
if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
|
2002-08-17 15:14:26 +00:00
|
|
|
{
|
2003-06-07 Casper S. Hornstrup <chorns@users.sourceforge.net>
Changes for compiling with w32api
* include/ddk/cctypes.h (PREACTOS_COMMON_FCB_HEADER): Remove.
(FSRTL_COMMON_FCB_HEADER): Add.
* include/ddk/iotypes.h (FILE_OBJECT): Rename field
SectionObjectPointers to SectionObjectPointer.
* ntoskrnl/cc/copy.c, ntoskrnl/cc/misc.c, ntoskrnl/cc/pin.c,
ntoskrnl/cc/view.c, ntoskrnl/io/rawfs.c, ntoskrnl/mm/section.c,
drivers/fs/cdfs/cleanup.c, drivers/fs/cdfs/fcb.c,
drivers/fs/cdfs/fsctl.c, drivers/fs/ntfs/fcb.c, drivers/fs/ntfs/fsctl.c,
drivers/fs/vfat/close.c, drivers/fs/vfat/create.c,
drivers/fs/vfat/finfo.c, drivers/fs/vfat/fcb.c, drivers/fs/vfat/fsctl.c:
Use new FILE_OBJECT structure.
* drivers/fs/cdfs/cdfs.h, drivers/fs/ntfs/ntfs.h, drivers/fs/vfat/vfat.h:
Use new FSRTL_COMMON_FCB_HEADER structure.
* drivers/net/afd/include/afd.h (FSRTL_COMMON_FCB_HEADER): Remove.
* include/ddk/ketypes.h (KQUEUE): Match w32api structure.
* ntoskrnl/ke/queue.c, ntoskrnl/ke/wait.c: Use new structure.
* ntoskrnl/ke/spinlock.c (KeAcquireSpinLockAtDpcLevel,
KeReleaseSpinLockFromDpcLevel): Undefine before declaring.
svn path=/trunk/; revision=4865
2003-06-07 11:34:36 +00:00
|
|
|
Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
|
2002-08-17 15:14:26 +00:00
|
|
|
if (FileObject->PrivateCacheMap != NULL)
|
|
|
|
{
|
|
|
|
FileObject->PrivateCacheMap = NULL;
|
2003-01-11 15:24:38 +00:00
|
|
|
if (Bcb->RefCount > 0)
|
|
|
|
{
|
|
|
|
Bcb->RefCount--;
|
|
|
|
if (Bcb->RefCount == 0)
|
|
|
|
{
|
2004-09-19 12:11:44 +00:00
|
|
|
MmFreeSectionSegments(Bcb->FileObject);
|
2003-01-11 15:24:38 +00:00
|
|
|
CcRosDeleteFileCache(FileObject, Bcb);
|
|
|
|
}
|
|
|
|
}
|
2002-08-17 15:14:26 +00: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-12 19:00:26 +00:00
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
2002-08-08 17:54:16 +00:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2005-05-09 01:38:29 +00:00
|
|
|
NTSTATUS
|
2005-09-14 01:44:19 +00:00
|
|
|
NTAPI
|
2003-06-27 21:28:30 +00:00
|
|
|
CcTryToInitializeFileCache(PFILE_OBJECT FileObject)
|
|
|
|
{
|
|
|
|
PBCB Bcb;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
- 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-12 19:00:26 +00:00
|
|
|
KeAcquireGuardedMutex(&ViewLock);
|
2003-06-27 21:28:30 +00:00
|
|
|
|
2008-07-20 04:40:27 +00:00
|
|
|
ASSERT(FileObject->SectionObjectPointer);
|
2003-06-27 21:28:30 +00:00
|
|
|
Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
|
|
|
|
if (Bcb == NULL)
|
|
|
|
{
|
|
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (FileObject->PrivateCacheMap == NULL)
|
|
|
|
{
|
|
|
|
FileObject->PrivateCacheMap = Bcb;
|
|
|
|
Bcb->RefCount++;
|
|
|
|
}
|
|
|
|
if (Bcb->BcbRemoveListEntry.Flink != NULL)
|
|
|
|
{
|
|
|
|
RemoveEntryList(&Bcb->BcbRemoveListEntry);
|
|
|
|
Bcb->BcbRemoveListEntry.Flink = NULL;
|
|
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
}
|
- 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-12 19:00:26 +00:00
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
2003-06-27 21:28:30 +00:00
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-08 16:47:41 +00:00
|
|
|
NTSTATUS NTAPI
|
2001-05-04 01:21:45 +00:00
|
|
|
CcRosInitializeFileCache(PFILE_OBJECT FileObject,
|
2008-03-08 16:47:41 +00:00
|
|
|
ULONG CacheSegmentSize,
|
|
|
|
PCACHE_MANAGER_CALLBACKS CallBacks,
|
|
|
|
PVOID LazyWriterContext)
|
2000-12-10 23:42:01 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Initializes a BCB for a file object
|
|
|
|
*/
|
2002-08-17 15:14:26 +00:00
|
|
|
{
|
2003-02-13 22:24:19 +00:00
|
|
|
PBCB Bcb;
|
2004-08-10 01:49:37 +00:00
|
|
|
|
|
|
|
Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
|
2005-07-04 22:11:00 +00:00
|
|
|
DPRINT("CcRosInitializeFileCache(FileObject 0x%p, Bcb 0x%p, CacheSegmentSize %d)\n",
|
2002-10-02 19:20:51 +00:00
|
|
|
FileObject, Bcb, CacheSegmentSize);
|
|
|
|
|
- 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-12 19:00:26 +00:00
|
|
|
KeAcquireGuardedMutex(&ViewLock);
|
2003-02-13 22:24:19 +00:00
|
|
|
if (Bcb == NULL)
|
2002-08-17 15:14:26 +00:00
|
|
|
{
|
2008-03-08 16:47:41 +00:00
|
|
|
Bcb = ExAllocateFromNPagedLookasideList(&BcbLookasideList);
|
|
|
|
if (Bcb == NULL)
|
|
|
|
{
|
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
|
|
|
return(STATUS_UNSUCCESSFUL);
|
|
|
|
}
|
|
|
|
memset(Bcb, 0, sizeof(BCB));
|
|
|
|
ObReferenceObjectByPointer(FileObject,
|
|
|
|
FILE_ALL_ACCESS,
|
|
|
|
NULL,
|
|
|
|
KernelMode);
|
|
|
|
Bcb->FileObject = FileObject;
|
|
|
|
Bcb->CacheSegmentSize = CacheSegmentSize;
|
|
|
|
Bcb->Callbacks = CallBacks;
|
|
|
|
Bcb->LazyWriteContext = LazyWriterContext;
|
|
|
|
if (FileObject->FsContext)
|
|
|
|
{
|
|
|
|
Bcb->AllocationSize =
|
|
|
|
((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->AllocationSize;
|
|
|
|
Bcb->FileSize =
|
|
|
|
((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize;
|
|
|
|
}
|
|
|
|
KeInitializeSpinLock(&Bcb->BcbLock);
|
|
|
|
InitializeListHead(&Bcb->BcbSegmentListHead);
|
|
|
|
FileObject->SectionObjectPointer->SharedCacheMap = Bcb;
|
2002-08-17 15:14:26 +00:00
|
|
|
}
|
|
|
|
if (FileObject->PrivateCacheMap == NULL)
|
|
|
|
{
|
2008-03-08 16:47:41 +00:00
|
|
|
FileObject->PrivateCacheMap = Bcb;
|
|
|
|
Bcb->RefCount++;
|
2002-08-17 15:14:26 +00:00
|
|
|
}
|
2003-02-13 22:24:19 +00:00
|
|
|
if (Bcb->BcbRemoveListEntry.Flink != NULL)
|
2003-01-11 15:24:38 +00:00
|
|
|
{
|
2008-03-08 16:47:41 +00:00
|
|
|
RemoveEntryList(&Bcb->BcbRemoveListEntry);
|
|
|
|
Bcb->BcbRemoveListEntry.Flink = NULL;
|
2003-01-11 15:24:38 +00: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-12 19:00:26 +00:00
|
|
|
KeReleaseGuardedMutex(&ViewLock);
|
2002-08-17 15:14:26 +00:00
|
|
|
|
1999-02-01 20:58:37 +00:00
|
|
|
return(STATUS_SUCCESS);
|
1998-12-21 15:48:21 +00:00
|
|
|
}
|
1999-02-01 20:58:37 +00:00
|
|
|
|
2003-07-10 06:27:13 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2008-11-29 20:47:48 +00:00
|
|
|
PFILE_OBJECT NTAPI
|
2002-10-02 19:20:51 +00:00
|
|
|
CcGetFileObjectFromSectionPtrs(IN PSECTION_OBJECT_POINTERS SectionObjectPointers)
|
|
|
|
{
|
|
|
|
PBCB Bcb;
|
|
|
|
if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap)
|
|
|
|
{
|
|
|
|
Bcb = (PBCB)SectionObjectPointers->SharedCacheMap;
|
2004-10-22 20:19:58 +00:00
|
|
|
ASSERT(Bcb);
|
2002-10-02 19:20:51 +00:00
|
|
|
return Bcb->FileObject;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-09-14 01:44:19 +00:00
|
|
|
VOID
|
|
|
|
INIT_FUNCTION
|
|
|
|
NTAPI
|
2001-04-09 02:45:04 +00:00
|
|
|
CcInitView(VOID)
|
|
|
|
{
|
2003-01-11 15:24:38 +00:00
|
|
|
#ifdef CACHE_BITMAP
|
|
|
|
PMEMORY_AREA marea;
|
|
|
|
PVOID Buffer;
|
2003-12-31 05:33:04 +00:00
|
|
|
PHYSICAL_ADDRESS BoundaryAddressMultiple;
|
2003-01-11 15:24:38 +00:00
|
|
|
#endif
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2002-02-08 02:57:10 +00:00
|
|
|
DPRINT("CcInitView()\n");
|
2003-01-11 15:24:38 +00:00
|
|
|
#ifdef CACHE_BITMAP
|
2003-12-31 05:33:04 +00:00
|
|
|
BoundaryAddressMultiple.QuadPart = 0;
|
2003-01-11 15:24:38 +00:00
|
|
|
CiCacheSegMappingRegionHint = 0;
|
|
|
|
CiCacheSegMappingRegionBase = NULL;
|
|
|
|
|
|
|
|
MmLockAddressSpace(MmGetKernelAddressSpace());
|
|
|
|
|
2005-11-13 17:28:24 +00:00
|
|
|
Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
|
2003-01-11 15:24:38 +00:00
|
|
|
MEMORY_AREA_CACHE_SEGMENT,
|
|
|
|
&CiCacheSegMappingRegionBase,
|
|
|
|
CI_CACHESEG_MAPPING_REGION_SIZE,
|
2005-11-13 17:28:24 +00:00
|
|
|
PAGE_READWRITE,
|
2003-01-11 15:24:38 +00:00
|
|
|
&marea,
|
2003-05-25 21:49:04 +00:00
|
|
|
FALSE,
|
2005-11-13 17:28:24 +00:00
|
|
|
0,
|
2003-12-31 05:33:04 +00:00
|
|
|
BoundaryAddressMultiple);
|
2003-01-11 15:24:38 +00:00
|
|
|
MmUnlockAddressSpace(MmGetKernelAddressSpace());
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2008-08-24 15:48:05 +00:00
|
|
|
KeBugCheck(CACHE_MANAGER);
|
2003-01-11 15:24:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Buffer = ExAllocatePool(NonPagedPool, CI_CACHESEG_MAPPING_REGION_SIZE / (PAGE_SIZE * 8));
|
2009-09-02 13:02:30 +00:00
|
|
|
if (!Buffer)
|
|
|
|
{
|
|
|
|
KeBugCheck(CACHE_MANAGER);
|
|
|
|
}
|
2003-01-11 15:24:38 +00:00
|
|
|
|
|
|
|
RtlInitializeBitMap(&CiCacheSegMappingRegionAllocMap, Buffer, CI_CACHESEG_MAPPING_REGION_SIZE / PAGE_SIZE);
|
|
|
|
RtlClearAllBits(&CiCacheSegMappingRegionAllocMap);
|
|
|
|
|
|
|
|
KeInitializeSpinLock(&CiCacheSegMappingRegionLock);
|
2005-05-09 01:38:29 +00:00
|
|
|
#endif
|
2001-12-27 23:56:42 +00:00
|
|
|
InitializeListHead(&CacheSegmentListHead);
|
|
|
|
InitializeListHead(&DirtySegmentListHead);
|
2001-12-29 14:32:22 +00:00
|
|
|
InitializeListHead(&CacheSegmentLRUListHead);
|
2003-01-11 15:24:38 +00:00
|
|
|
InitializeListHead(&ClosedListHead);
|
- 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-12 19:00:26 +00:00
|
|
|
KeInitializeGuardedMutex(&ViewLock);
|
2003-01-11 15:24:38 +00:00
|
|
|
ExInitializeNPagedLookasideList (&iBcbLookasideList,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
sizeof(INTERNAL_BCB),
|
|
|
|
TAG_IBCB,
|
|
|
|
20);
|
|
|
|
ExInitializeNPagedLookasideList (&BcbLookasideList,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
sizeof(BCB),
|
|
|
|
TAG_BCB,
|
|
|
|
20);
|
|
|
|
ExInitializeNPagedLookasideList (&CacheSegLookasideList,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
sizeof(CACHE_SEGMENT),
|
|
|
|
TAG_CSEG,
|
|
|
|
20);
|
|
|
|
|
2001-12-29 14:32:22 +00:00
|
|
|
MmInitializeMemoryConsumer(MC_CACHE, CcRosTrimCache);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2002-08-08 17:54:16 +00:00
|
|
|
CcInitCacheZeroPage();
|
2003-01-11 15:24:38 +00:00
|
|
|
|
2001-04-09 02:45:04 +00:00
|
|
|
}
|
2000-03-05 19:17:43 +00:00
|
|
|
|
2000-02-26 22:41:35 +00:00
|
|
|
/* EOF */
|
2001-12-27 23:56:42 +00: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-12 19:00:26 +00:00
|
|
|
|