[NTOSKRNL] Use interlocked operations for VACB reference counting.

CORE-14480
CORE-14285
This commit is contained in:
Pierre Schweitzer 2018-03-24 19:15:16 +01:00
parent dea9c291ab
commit 14b05e65ff
No known key found for this signature in database
GPG key ID: 7545556C3D585B0B
3 changed files with 60 additions and 23 deletions

View file

@ -207,6 +207,8 @@ CcPurgeCacheSection (
ListEntry = SharedCacheMap->CacheMapVacbListHead.Flink; ListEntry = SharedCacheMap->CacheMapVacbListHead.Flink;
while (ListEntry != &SharedCacheMap->CacheMapVacbListHead) while (ListEntry != &SharedCacheMap->CacheMapVacbListHead)
{ {
ULONG Refs;
Vacb = CONTAINING_RECORD(ListEntry, ROS_VACB, CacheMapVacbListEntry); Vacb = CONTAINING_RECORD(ListEntry, ROS_VACB, CacheMapVacbListEntry);
ListEntry = ListEntry->Flink; ListEntry = ListEntry->Flink;
@ -225,15 +227,16 @@ CcPurgeCacheSection (
/* Still in use, it cannot be purged, fail /* Still in use, it cannot be purged, fail
* Allow one ref: VACB is supposed to be always 1-referenced * Allow one ref: VACB is supposed to be always 1-referenced
*/ */
if ((Vacb->ReferenceCount > 1 && !Vacb->Dirty) || Refs = CcRosVacbGetRefCount(Vacb);
(Vacb->ReferenceCount > 2 && Vacb->Dirty)) if ((Refs > 1 && !Vacb->Dirty) ||
(Refs > 2 && Vacb->Dirty))
{ {
Success = FALSE; Success = FALSE;
break; break;
} }
/* This VACB is in range, so unlink it and mark for free */ /* This VACB is in range, so unlink it and mark for free */
ASSERT(Vacb->ReferenceCount == 1 || Vacb->Dirty); ASSERT(Refs == 1 || Vacb->Dirty);
RemoveEntryList(&Vacb->VacbLruListEntry); RemoveEntryList(&Vacb->VacbLruListEntry);
if (Vacb->Dirty) if (Vacb->Dirty)
{ {

View file

@ -65,25 +65,45 @@ KSPIN_LOCK CcDeferredWriteSpinLock;
LIST_ENTRY CcCleanSharedCacheMapList; LIST_ENTRY CcCleanSharedCacheMapList;
#if DBG #if DBG
VOID CcRosVacbIncRefCount_(PROS_VACB vacb, PCSTR file, INT line) ULONG CcRosVacbIncRefCount_(PROS_VACB vacb, PCSTR file, INT line)
{ {
++vacb->ReferenceCount; ULONG Refs;
Refs = InterlockedIncrement((PLONG)&vacb->ReferenceCount);
if (vacb->SharedCacheMap->Trace) if (vacb->SharedCacheMap->Trace)
{ {
DbgPrint("(%s:%i) VACB %p ++RefCount=%lu, Dirty %u, PageOut %lu\n", DbgPrint("(%s:%i) VACB %p ++RefCount=%lu, Dirty %u, PageOut %lu\n",
file, line, vacb, vacb->ReferenceCount, vacb->Dirty, vacb->PageOut); file, line, vacb, Refs, vacb->Dirty, vacb->PageOut);
} }
return Refs;
} }
VOID CcRosVacbDecRefCount_(PROS_VACB vacb, PCSTR file, INT line) ULONG CcRosVacbDecRefCount_(PROS_VACB vacb, PCSTR file, INT line)
{ {
ASSERT(vacb->ReferenceCount != 0); ULONG Refs;
--vacb->ReferenceCount;
ASSERT(!(vacb->ReferenceCount == 0 && vacb->Dirty)); Refs = InterlockedDecrement((PLONG)&vacb->ReferenceCount);
ASSERT(!(Refs == 0 && vacb->Dirty));
if (vacb->SharedCacheMap->Trace) if (vacb->SharedCacheMap->Trace)
{ {
DbgPrint("(%s:%i) VACB %p --RefCount=%lu, Dirty %u, PageOut %lu\n", DbgPrint("(%s:%i) VACB %p --RefCount=%lu, Dirty %u, PageOut %lu\n",
file, line, vacb, vacb->ReferenceCount, vacb->Dirty, vacb->PageOut); file, line, vacb, Refs, vacb->Dirty, vacb->PageOut);
} }
return Refs;
}
ULONG CcRosVacbGetRefCount_(PROS_VACB vacb, PCSTR file, INT line)
{
ULONG Refs;
Refs = InterlockedCompareExchange((PLONG)&vacb->ReferenceCount, 0, 0);
if (vacb->SharedCacheMap->Trace)
{
DbgPrint("(%s:%i) VACB %p ==RefCount=%lu, Dirty %u, PageOut %lu\n",
file, line, vacb, Refs, vacb->Dirty, vacb->PageOut);
}
return Refs;
} }
#endif #endif
@ -221,7 +241,7 @@ CcRosFlushDirtyPages (
ASSERT(current->Dirty); ASSERT(current->Dirty);
/* One reference is added above */ /* One reference is added above */
if (current->ReferenceCount > 2) if (CcRosVacbGetRefCount(current) > 2)
{ {
CcRosReleaseVacbLock(current); CcRosReleaseVacbLock(current);
current->SharedCacheMap->Callbacks->ReleaseFromLazyWrite( current->SharedCacheMap->Callbacks->ReleaseFromLazyWrite(
@ -311,6 +331,8 @@ retry:
current_entry = VacbLruListHead.Flink; current_entry = VacbLruListHead.Flink;
while (current_entry != &VacbLruListHead) while (current_entry != &VacbLruListHead)
{ {
ULONG Refs;
current = CONTAINING_RECORD(current_entry, current = CONTAINING_RECORD(current_entry,
ROS_VACB, ROS_VACB,
VacbLruListEntry); VacbLruListEntry);
@ -342,14 +364,14 @@ retry:
} }
/* Dereference the VACB */ /* Dereference the VACB */
CcRosVacbDecRefCount(current); Refs = CcRosVacbDecRefCount(current);
/* Check if we can free this entry now */ /* Check if we can free this entry now */
if (current->ReferenceCount < 2) if (Refs < 2)
{ {
ASSERT(!current->Dirty); ASSERT(!current->Dirty);
ASSERT(!current->MappedCount); ASSERT(!current->MappedCount);
ASSERT(current->ReferenceCount == 1); ASSERT(Refs == 1);
RemoveEntryList(&current->CacheMapVacbListEntry); RemoveEntryList(&current->CacheMapVacbListEntry);
RemoveEntryList(&current->VacbLruListEntry); RemoveEntryList(&current->VacbLruListEntry);
@ -409,6 +431,7 @@ CcRosReleaseVacb (
BOOLEAN Dirty, BOOLEAN Dirty,
BOOLEAN Mapped) BOOLEAN Mapped)
{ {
ULONG Refs;
ASSERT(SharedCacheMap); ASSERT(SharedCacheMap);
DPRINT("CcRosReleaseVacb(SharedCacheMap 0x%p, Vacb 0x%p, Valid %u)\n", DPRINT("CcRosReleaseVacb(SharedCacheMap 0x%p, Vacb 0x%p, Valid %u)\n",
@ -425,13 +448,13 @@ CcRosReleaseVacb (
{ {
Vacb->MappedCount++; Vacb->MappedCount++;
} }
CcRosVacbDecRefCount(Vacb); Refs = CcRosVacbDecRefCount(Vacb);
if (Mapped && (Vacb->MappedCount == 1)) if (Mapped && (Vacb->MappedCount == 1))
{ {
CcRosVacbIncRefCount(Vacb); CcRosVacbIncRefCount(Vacb);
} }
ASSERT(Vacb->ReferenceCount > 0); ASSERT(Refs > 0);
CcRosReleaseVacbLock(Vacb); CcRosReleaseVacbLock(Vacb);
@ -835,6 +858,7 @@ CcRosGetVacb (
{ {
PROS_VACB current; PROS_VACB current;
NTSTATUS Status; NTSTATUS Status;
ULONG Refs;
ASSERT(SharedCacheMap); ASSERT(SharedCacheMap);
@ -856,6 +880,8 @@ CcRosGetVacb (
} }
} }
Refs = CcRosVacbGetRefCount(current);
KeAcquireGuardedMutex(&ViewLock); KeAcquireGuardedMutex(&ViewLock);
/* Move to the tail of the LRU list */ /* Move to the tail of the LRU list */
@ -873,7 +899,7 @@ CcRosGetVacb (
*Vacb = current; *Vacb = current;
*BaseOffset = current->FileOffset.QuadPart; *BaseOffset = current->FileOffset.QuadPart;
ASSERT(current->ReferenceCount > 1); ASSERT(Refs > 1);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }

View file

@ -220,7 +220,7 @@ typedef struct _ROS_VACB
/* Mutex */ /* Mutex */
KMUTEX Mutex; KMUTEX Mutex;
/* Number of references. */ /* Number of references. */
ULONG ReferenceCount; volatile ULONG ReferenceCount;
/* How many times was it pinned? */ /* How many times was it pinned? */
_Guarded_by_(Mutex) _Guarded_by_(Mutex)
LONG PinCount; LONG PinCount;
@ -523,20 +523,28 @@ IsPointInRange(
#if DBG #if DBG
#define CcRosVacbIncRefCount(vacb) CcRosVacbIncRefCount_(vacb,__FILE__,__LINE__) #define CcRosVacbIncRefCount(vacb) CcRosVacbIncRefCount_(vacb,__FILE__,__LINE__)
#define CcRosVacbDecRefCount(vacb) CcRosVacbDecRefCount_(vacb,__FILE__,__LINE__) #define CcRosVacbDecRefCount(vacb) CcRosVacbDecRefCount_(vacb,__FILE__,__LINE__)
#define CcRosVacbGetRefCount(vacb) CcRosVacbGetRefCount_(vacb,__FILE__,__LINE__)
VOID ULONG
CcRosVacbIncRefCount_( CcRosVacbIncRefCount_(
PROS_VACB vacb, PROS_VACB vacb,
PCSTR file, PCSTR file,
INT line); INT line);
VOID ULONG
CcRosVacbDecRefCount_( CcRosVacbDecRefCount_(
PROS_VACB vacb, PROS_VACB vacb,
PCSTR file, PCSTR file,
INT line); INT line);
ULONG
CcRosVacbGetRefCount_(
PROS_VACB vacb,
PCSTR file,
INT line);
#else #else
#define CcRosVacbIncRefCount(vacb) (++((vacb)->ReferenceCount)) #define CcRosVacbIncRefCount(vacb) InterlockedIncrement((PLONG)&(vacb)->ReferenceCount)
#define CcRosVacbDecRefCount(vacb) (--((vacb)->ReferenceCount)) #define CcRosVacbDecRefCount(vacb) InterlockedDecrement((PLONG)&(vacb)->ReferenceCount)
#define CcRosVacbGetRefCount(vacb) InterlockedCompareExchange((PLONG)&(vacb)->ReferenceCount, 0, 0)
#endif #endif