Something went wrong. Try again.
Reactos
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/cc/view.c * PURPOSE: Cache manager * * PROGRAMMERS: David Welch (welch@mcmail.com) * Pierre Schweitzer (pierre@reactos.org) */
/* NOTES ********************************************************************** * * This is not the NT implementation of a file cache nor anything much like * it. * * The general procedure for a filesystem to implement a read or write * dispatch routine is as follows * * (1) If caching for the FCB hasn't been initiated then so do by calling * CcInitializeFileCache. * * (2) For each 4k region which is being read or written obtain a cache page * by calling CcRequestCachePage. * * (3) If either the page is being read or not completely written, and it is * not up to date then read its data from the underlying medium. If the read * fails then call CcReleaseCachePage with VALID as FALSE and return a error. * * (4) Copy the data into or out of the page as necessary. * * (5) Release the cache page *//* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG#include <debug.h>
/* GLOBALS *******************************************************************/
LIST_ENTRY DirtyVacbListHead;static LIST_ENTRY VacbLruListHead;
NPAGED_LOOKASIDE_LIST iBcbLookasideList;static NPAGED_LOOKASIDE_LIST SharedCacheMapLookasideList;static NPAGED_LOOKASIDE_LIST VacbLookasideList;
/* Internal vars (MS): * - Threshold above which lazy writer will start action * - Amount of dirty pages * - List for deferred writes * - Spinlock when dealing with the deferred list * - List for "clean" shared cache maps */ULONG CcDirtyPageThreshold = 0;ULONG CcTotalDirtyPages = 0;LIST_ENTRY CcDeferredWrites;KSPIN_LOCK CcDeferredWriteSpinLock;LIST_ENTRY CcCleanSharedCacheMapList;
#if DBGULONG CcRosVacbIncRefCount_(PROS_VACB vacb, PCSTR file, INT line){ ULONG Refs;
Refs = InterlockedIncrement((PLONG)&vacb->ReferenceCount); 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;}ULONG CcRosVacbDecRefCount_(PROS_VACB vacb, PCSTR file, INT line){ ULONG Refs; BOOLEAN VacbDirty = vacb->Dirty; BOOLEAN VacbTrace = vacb->SharedCacheMap->Trace; BOOLEAN VacbPageOut = vacb->PageOut;
Refs = InterlockedDecrement((PLONG)&vacb->ReferenceCount); ASSERT(!(Refs == 0 && VacbDirty)); if (VacbTrace) { DbgPrint("(%s:%i) VACB %p --RefCount=%lu, Dirty %u, PageOut %lu\n", file, line, vacb, Refs, VacbDirty, VacbPageOut); }
if (Refs == 0) { CcRosInternalFreeVacb(vacb); }
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
/* FUNCTIONS *****************************************************************/
VOIDCcRosTraceCacheMap ( PROS_SHARED_CACHE_MAP SharedCacheMap, BOOLEAN Trace ){#if DBG KIRQL oldirql; PLIST_ENTRY current_entry; PROS_VACB current;
if (!SharedCacheMap) return;
SharedCacheMap->Trace = Trace;
if (Trace) { DPRINT1("Enabling Tracing for CacheMap 0x%p:\n", SharedCacheMap);
oldirql = KeAcquireQueuedSpinLock(LockQueueMasterLock); KeAcquireSpinLockAtDpcLevel(&SharedCacheMap->CacheMapLock);
current_entry = SharedCacheMap->CacheMapVacbListHead.Flink; while (current_entry != &SharedCacheMap->CacheMapVacbListHead) { current = CONTAINING_RECORD(current_entry, ROS_VACB, CacheMapVacbListEntry); current_entry = current_entry->Flink;
DPRINT1(" VACB 0x%p enabled, RefCount %lu, Dirty %u, PageOut %lu, BaseAddress %p, FileOffset %I64d\n", current, current->ReferenceCount, current->Dirty, current->PageOut, current->BaseAddress, current->FileOffset.QuadPart); }
KeReleaseSpinLockFromDpcLevel(&SharedCacheMap->CacheMapLock); KeReleaseQueuedSpinLock(LockQueueMasterLock, oldirql); } else { DPRINT1("Disabling Tracing for CacheMap 0x%p:\n", SharedCacheMap); }
#else UNREFERENCED_PARAMETER(SharedCacheMap); UNREFERENCED_PARAMETER(Trace);#endif}
NTSTATUSCcRosFlushVacb ( _In_ PROS_VACB Vacb, _Out_opt_ PIO_STATUS_BLOCK Iosb){ NTSTATUS Status; BOOLEAN HaveLock = FALSE; PROS_SHARED_CACHE_MAP SharedCacheMap = Vacb->SharedCacheMap;
CcRosUnmarkDirtyVacb(Vacb, TRUE);
/* Lock for flush, if we are not already the top-level */ if (IoGetTopLevelIrp() != (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP) { Status = FsRtlAcquireFileForCcFlushEx(Vacb->SharedCacheMap->FileObject); if (!NT_SUCCESS(Status)) goto quit; HaveLock = TRUE; }
Status = MmFlushSegment(SharedCacheMap->FileObject->SectionObjectPointer, &Vacb->FileOffset, VACB_MAPPING_GRANULARITY, Iosb);
if (HaveLock) { FsRtlReleaseFileForCcFlush(Vacb->SharedCacheMap->FileObject); }
quit: if (!NT_SUCCESS(Status)) CcRosMarkDirtyVacb(Vacb); else { /* Update VDL */ if (SharedCacheMap->ValidDataLength.QuadPart < (Vacb->FileOffset.QuadPart + VACB_MAPPING_GRANULARITY)) { SharedCacheMap->ValidDataLength.QuadPart = Vacb->FileOffset.QuadPart + VACB_MAPPING_GRANULARITY; } }
return Status;}
staticNTSTATUSCcRosDeleteFileCache ( PFILE_OBJECT FileObject, PROS_SHARED_CACHE_MAP SharedCacheMap, PKIRQL OldIrql)/* * FUNCTION: Releases the shared cache map associated with a file object */{ PLIST_ENTRY current_entry;
ASSERT(SharedCacheMap); ASSERT(SharedCacheMap == FileObject->SectionObjectPointer->SharedCacheMap); ASSERT(SharedCacheMap->OpenCount == 0);
/* Remove all VACBs from the global lists */ KeAcquireSpinLockAtDpcLevel(&SharedCacheMap->CacheMapLock); current_entry = SharedCacheMap->CacheMapVacbListHead.Flink; while (current_entry != &SharedCacheMap->CacheMapVacbListHead) { PROS_VACB Vacb = CONTAINING_RECORD(current_entry, ROS_VACB, CacheMapVacbListEntry);
RemoveEntryList(&Vacb->VacbLruListEntry); InitializeListHead(&Vacb->VacbLruListEntry);
if (Vacb->Dirty) { CcRosUnmarkDirtyVacb(Vacb, FALSE); /* Mark it as dirty again so we know that we have to flush before freeing it */ Vacb->Dirty = TRUE; }
current_entry = current_entry->Flink; }
/* Make sure there is no trace anymore of this map */ FileObject->SectionObjectPointer->SharedCacheMap = NULL; RemoveEntryList(&SharedCacheMap->SharedCacheMapLinks);
KeReleaseSpinLockFromDpcLevel(&SharedCacheMap->CacheMapLock); KeReleaseQueuedSpinLock(LockQueueMasterLock, *OldIrql);
/* Now that we're out of the locks, free everything for real */ while (!IsListEmpty(&SharedCacheMap->CacheMapVacbListHead)) { PROS_VACB Vacb = CONTAINING_RECORD(RemoveHeadList(&SharedCacheMap->CacheMapVacbListHead), ROS_VACB, CacheMapVacbListEntry); ULONG RefCount;
InitializeListHead(&Vacb->CacheMapVacbListEntry);
/* Flush to disk, if needed */ if (Vacb->Dirty) { IO_STATUS_BLOCK Iosb; NTSTATUS Status;
Status = MmFlushSegment(FileObject->SectionObjectPointer, &Vacb->FileOffset, VACB_MAPPING_GRANULARITY, &Iosb); if (!NT_SUCCESS(Status)) { /* Complain. There's not much we can do */ DPRINT1("Failed to flush VACB to disk while deleting the cache entry. Status: 0x%08x\n", Status); } Vacb->Dirty = FALSE; }
RefCount = CcRosVacbDecRefCount(Vacb);#if DBG // CORE-14578 if (RefCount != 0) { DPRINT1("Leaking VACB %p attached to %p (%I64d)\n", Vacb, FileObject, Vacb->FileOffset.QuadPart); DPRINT1("There are: %d references left\n", RefCount); DPRINT1("Map: %d\n", Vacb->MappedCount); DPRINT1("Dirty: %d\n", Vacb->Dirty); if (FileObject->FileName.Length != 0) { DPRINT1("File was: %wZ\n", &FileObject->FileName); } else { DPRINT1("No name for the file\n"); } }#else (void)RefCount;#endif }
/* Release the references we own */ if(SharedCacheMap->Section) ObDereferenceObject(SharedCacheMap->Section); ObDereferenceObject(SharedCacheMap->FileObject);
ExFreeToNPagedLookasideList(&SharedCacheMapLookasideList, SharedCacheMap);
/* Acquire the lock again for our caller */ *OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
return STATUS_SUCCESS;}
NTSTATUSCcRosFlushDirtyPages ( ULONG Target, PULONG Count, BOOLEAN Wait, BOOLEAN CalledFromLazy){ PLIST_ENTRY current_entry; NTSTATUS Status; KIRQL OldIrql; BOOLEAN FlushAll = (Target == MAXULONG);
DPRINT("CcRosFlushDirtyPages(Target %lu)\n", Target);
(*Count) = 0;
KeEnterCriticalRegion(); OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
current_entry = DirtyVacbListHead.Flink; if (current_entry == &DirtyVacbListHead) { DPRINT("No Dirty pages\n"); }
while (((current_entry != &DirtyVacbListHead) && (Target > 0)) || FlushAll) { PROS_SHARED_CACHE_MAP SharedCacheMap; PROS_VACB current; BOOLEAN Locked;
if (current_entry == &DirtyVacbListHead) { ASSERT(FlushAll); if (IsListEmpty(&DirtyVacbListHead)) break; current_entry = DirtyVacbListHead.Flink; }
current = CONTAINING_RECORD(current_entry, ROS_VACB, DirtyVacbListEntry); current_entry = current_entry->Flink;
CcRosVacbIncRefCount(current);
SharedCacheMap = current->SharedCacheMap;
/* When performing lazy write, don't handle temporary files */ if (CalledFromLazy && BooleanFlagOn(SharedCacheMap->FileObject->Flags, FO_TEMPORARY_FILE)) { CcRosVacbDecRefCount(current); continue; }
/* Don't attempt to lazy write the files that asked not to */ if (CalledFromLazy && BooleanFlagOn(SharedCacheMap->Flags, WRITEBEHIND_DISABLED)) { CcRosVacbDecRefCount(current); continue; }
ASSERT(current->Dirty);
/* Do not lazy-write the same file concurrently. Fastfat ASSERTS on that */ if (SharedCacheMap->Flags & SHARED_CACHE_MAP_IN_LAZYWRITE) { CcRosVacbDecRefCount(current); continue; }
SharedCacheMap->Flags |= SHARED_CACHE_MAP_IN_LAZYWRITE;
/* Keep a ref on the shared cache map */ SharedCacheMap->OpenCount++;
KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
Locked = SharedCacheMap->Callbacks->AcquireForLazyWrite(SharedCacheMap->LazyWriteContext, Wait); if (!Locked) { DPRINT("Not locked\n"); ASSERT(!Wait); CcRosVacbDecRefCount(current); OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); SharedCacheMap->Flags &= ~SHARED_CACHE_MAP_IN_LAZYWRITE;
if (--SharedCacheMap->OpenCount == 0) CcRosDeleteFileCache(SharedCacheMap->FileObject, SharedCacheMap, &OldIrql);
continue; }
IO_STATUS_BLOCK Iosb; Status = CcRosFlushVacb(current, &Iosb);
SharedCacheMap->Callbacks->ReleaseFromLazyWrite(SharedCacheMap->LazyWriteContext);
/* We release the VACB before acquiring the lock again, because * CcRosVacbDecRefCount might free the VACB, as CcRosFlushVacb dropped a * Refcount. Freeing must be done outside of the lock. * The refcount is decremented atomically. So this is OK. */ CcRosVacbDecRefCount(current); OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
SharedCacheMap->Flags &= ~SHARED_CACHE_MAP_IN_LAZYWRITE;
if (--SharedCacheMap->OpenCount == 0) CcRosDeleteFileCache(SharedCacheMap->FileObject, SharedCacheMap, &OldIrql);
if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE) && (Status != STATUS_MEDIA_WRITE_PROTECTED)) { DPRINT1("CC: Failed to flush VACB.\n"); } else { ULONG PagesFreed;
/* How many pages did we free? */ PagesFreed = Iosb.Information / PAGE_SIZE; (*Count) += PagesFreed;
if (!Wait) { /* Make sure we don't overflow target! */ if (Target < PagesFreed) { /* If we would have, jump to zero directly */ Target = 0; } else { Target -= PagesFreed; } } }
current_entry = DirtyVacbListHead.Flink; }
KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); KeLeaveCriticalRegion();
DPRINT("CcRosFlushDirtyPages() finished\n"); return STATUS_SUCCESS;}
VOIDCcRosTrimCache( _In_ ULONG Target, _Out_ PULONG NrFreed)/* * FUNCTION: Try to free some memory from the file cache. * ARGUMENTS: * Target - The number of pages to be freed. * NrFreed - Points to a variable where the number of pages * actually freed is returned. */{ PLIST_ENTRY current_entry; PROS_VACB current; ULONG PagesFreed; KIRQL oldIrql; LIST_ENTRY FreeList; BOOLEAN FlushedPages = FALSE;
DPRINT("CcRosTrimCache(Target %lu)\n", Target);
InitializeListHead(&FreeList);
*NrFreed = 0;
retry: oldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
current_entry = VacbLruListHead.Flink; while (current_entry != &VacbLruListHead) { ULONG Refs;
current = CONTAINING_RECORD(current_entry, ROS_VACB, VacbLruListEntry);
KeAcquireSpinLockAtDpcLevel(¤t->SharedCacheMap->CacheMapLock);
/* Reference the VACB */ CcRosVacbIncRefCount(current);
/* Check if it's mapped and not dirty */ if (InterlockedCompareExchange((PLONG)¤t->MappedCount, 0, 0) > 0 && !current->Dirty) { /* This code is never executed. It is left for reference only. */#if 1 DPRINT1("MmPageOutPhysicalAddress unexpectedly called\n"); ASSERT(FALSE);#else ULONG i; PFN_NUMBER Page;
/* We have to break these locks to call MmPageOutPhysicalAddress */ KeReleaseSpinLockFromDpcLevel(¤t->SharedCacheMap->CacheMapLock); KeReleaseQueuedSpinLock(LockQueueMasterLock, oldIrql);
/* Page out the VACB */ for (i = 0; i < VACB_MAPPING_GRANULARITY / PAGE_SIZE; i++) { Page = (PFN_NUMBER)(MmGetPhysicalAddress((PUCHAR)current->BaseAddress + (i * PAGE_SIZE)).QuadPart >> PAGE_SHIFT);
MmPageOutPhysicalAddress(Page); }
/* Reacquire the locks */ oldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); KeAcquireSpinLockAtDpcLevel(¤t->SharedCacheMap->CacheMapLock);#endif }
/* Only keep iterating though the loop while the lock is held */ current_entry = current_entry->Flink;
/* Dereference the VACB */ Refs = CcRosVacbDecRefCount(current);
/* Check if we can free this entry now */ if (Refs < 2) { ASSERT(!current->Dirty); ASSERT(!current->MappedCount); ASSERT(Refs == 1);
RemoveEntryList(¤t->CacheMapVacbListEntry); RemoveEntryList(¤t->VacbLruListEntry); InitializeListHead(¤t->VacbLruListEntry); InsertHeadList(&FreeList, ¤t->CacheMapVacbListEntry);
/* Calculate how many pages we freed for Mm */ PagesFreed = min(VACB_MAPPING_GRANULARITY / PAGE_SIZE, Target); Target -= PagesFreed; (*NrFreed) += PagesFreed; }
KeReleaseSpinLockFromDpcLevel(¤t->SharedCacheMap->CacheMapLock); }
KeReleaseQueuedSpinLock(LockQueueMasterLock, oldIrql);
/* Try flushing pages if we haven't met our target */ if ((Target > 0) && !FlushedPages) { /* Flush dirty pages to disk */ CcRosFlushDirtyPages(Target, &PagesFreed, FALSE, FALSE); FlushedPages = TRUE;
/* We can only swap as many pages as we flushed */ if (PagesFreed < Target) Target = PagesFreed;
/* Check if we flushed anything */ if (PagesFreed != 0) { /* Try again after flushing dirty pages */ DPRINT("Flushed %lu dirty cache pages to disk\n", PagesFreed); goto retry; } }
while (!IsListEmpty(&FreeList)) { ULONG Refs;
current_entry = RemoveHeadList(&FreeList); current = CONTAINING_RECORD(current_entry, ROS_VACB, CacheMapVacbListEntry); InitializeListHead(¤t->CacheMapVacbListEntry); Refs = CcRosVacbDecRefCount(current); ASSERT(Refs == 0); }
DPRINT("Evicted %lu cache pages\n", (*NrFreed));}
NTSTATUSCcRosReleaseVacb ( PROS_SHARED_CACHE_MAP SharedCacheMap, PROS_VACB Vacb, BOOLEAN Dirty, BOOLEAN Mapped){ ULONG Refs; ASSERT(SharedCacheMap);
DPRINT("CcRosReleaseVacb(SharedCacheMap 0x%p, Vacb 0x%p)\n", SharedCacheMap, Vacb);
if (Dirty && !Vacb->Dirty) { CcRosMarkDirtyVacb(Vacb); }
if (Mapped) { if (InterlockedIncrement((PLONG)&Vacb->MappedCount) == 1) { CcRosVacbIncRefCount(Vacb); } }
Refs = CcRosVacbDecRefCount(Vacb); ASSERT(Refs > 0);
return STATUS_SUCCESS;}
/* Returns with VACB Lock Held! */PROS_VACBCcRosLookupVacb ( PROS_SHARED_CACHE_MAP SharedCacheMap, LONGLONG FileOffset){ PLIST_ENTRY current_entry; PROS_VACB current; KIRQL oldIrql;
ASSERT(SharedCacheMap);
DPRINT("CcRosLookupVacb(SharedCacheMap 0x%p, FileOffset %I64u)\n", SharedCacheMap, FileOffset);
oldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); KeAcquireSpinLockAtDpcLevel(&SharedCacheMap->CacheMapLock);
current_entry = SharedCacheMap->CacheMapVacbListHead.Flink; while (current_entry != &SharedCacheMap->CacheMapVacbListHead) { current = CONTAINING_RECORD(current_entry, ROS_VACB, CacheMapVacbListEntry); if (IsPointInRange(current->FileOffset.QuadPart, VACB_MAPPING_GRANULARITY, FileOffset)) { CcRosVacbIncRefCount(current); KeReleaseSpinLockFromDpcLevel(&SharedCacheMap->CacheMapLock); KeReleaseQueuedSpinLock(LockQueueMasterLock, oldIrql); return current; } if (current->FileOffset.QuadPart > FileOffset) break; current_entry = current_entry->Flink; }
KeReleaseSpinLockFromDpcLevel(&SharedCacheMap->CacheMapLock); KeReleaseQueuedSpinLock(LockQueueMasterLock, oldIrql);
return NULL;}
VOIDCcRosMarkDirtyVacb ( PROS_VACB Vacb){ KIRQL oldIrql; PROS_SHARED_CACHE_MAP SharedCacheMap;
SharedCacheMap = Vacb->SharedCacheMap;
oldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); KeAcquireSpinLockAtDpcLevel(&SharedCacheMap->CacheMapLock);
ASSERT(!Vacb->Dirty);
InsertTailList(&DirtyVacbListHead, &Vacb->DirtyVacbListEntry); /* FIXME: There is no reason to account for the whole VACB. */ CcTotalDirtyPages += VACB_MAPPING_GRANULARITY / PAGE_SIZE; Vacb->SharedCacheMap->DirtyPages += VACB_MAPPING_GRANULARITY / PAGE_SIZE; CcRosVacbIncRefCount(Vacb);
/* Move to the tail of the LRU list */ RemoveEntryList(&Vacb->VacbLruListEntry); InsertTailList(&VacbLruListHead, &Vacb->VacbLruListEntry);
Vacb->Dirty = TRUE;
KeReleaseSpinLockFromDpcLevel(&SharedCacheMap->CacheMapLock);
/* Schedule a lazy writer run to now that we have dirty VACB */ if (!LazyWriter.ScanActive) { CcScheduleLazyWriteScan(FALSE); } KeReleaseQueuedSpinLock(LockQueueMasterLock, oldIrql);}
VOIDCcRosUnmarkDirtyVacb ( PROS_VACB Vacb, BOOLEAN LockViews){ KIRQL oldIrql; PROS_SHARED_CACHE_MAP SharedCacheMap;
SharedCacheMap = Vacb->SharedCacheMap;
if (LockViews) { oldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); KeAcquireSpinLockAtDpcLevel(&SharedCacheMap->CacheMapLock); }
ASSERT(Vacb->Dirty);
Vacb->Dirty = FALSE;
RemoveEntryList(&Vacb->DirtyVacbListEntry); InitializeListHead(&Vacb->DirtyVacbListEntry);
CcTotalDirtyPages -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; Vacb->SharedCacheMap->DirtyPages -= VACB_MAPPING_GRANULARITY / PAGE_SIZE;
CcRosVacbDecRefCount(Vacb);
if (LockViews) { KeReleaseSpinLockFromDpcLevel(&SharedCacheMap->CacheMapLock); KeReleaseQueuedSpinLock(LockQueueMasterLock, oldIrql); }}
BOOLEANCcRosFreeOneUnusedVacb( VOID){ KIRQL oldIrql; PLIST_ENTRY current_entry; PROS_VACB to_free = NULL;
oldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
/* Browse all the available VACB */ current_entry = VacbLruListHead.Flink; while ((current_entry != &VacbLruListHead) && (to_free == NULL)) { ULONG Refs; PROS_VACB current;
current = CONTAINING_RECORD(current_entry, ROS_VACB, VacbLruListEntry);
KeAcquireSpinLockAtDpcLevel(¤t->SharedCacheMap->CacheMapLock);
/* Only deal with unused VACB, we will free them */ Refs = CcRosVacbGetRefCount(current); if (Refs < 2) { ASSERT(!current->Dirty); ASSERT(!current->MappedCount); ASSERT(Refs == 1);
/* Reset it, this is the one we want to free */ RemoveEntryList(¤t->CacheMapVacbListEntry); InitializeListHead(¤t->CacheMapVacbListEntry); RemoveEntryList(¤t->VacbLruListEntry); InitializeListHead(¤t->VacbLruListEntry);
to_free = current; }
KeReleaseSpinLockFromDpcLevel(¤t->SharedCacheMap->CacheMapLock);
current_entry = current_entry->Flink; }
KeReleaseQueuedSpinLock(LockQueueMasterLock, oldIrql);
/* And now, free the VACB that we found, if any. */ if (to_free == NULL) { return FALSE; }
/* This must be its last ref */ NT_VERIFY(CcRosVacbDecRefCount(to_free) == 0);
return TRUE;}
staticNTSTATUSCcRosCreateVacb ( PROS_SHARED_CACHE_MAP SharedCacheMap, LONGLONG FileOffset, PROS_VACB *Vacb){ PROS_VACB current; PROS_VACB previous; PLIST_ENTRY current_entry; NTSTATUS Status; KIRQL oldIrql; ULONG Refs; SIZE_T ViewSize = VACB_MAPPING_GRANULARITY;
ASSERT(SharedCacheMap);
DPRINT("CcRosCreateVacb()\n");
current = ExAllocateFromNPagedLookasideList(&VacbLookasideList); if (!current) { return STATUS_INSUFFICIENT_RESOURCES; } current->BaseAddress = NULL; current->Dirty = FALSE; current->PageOut = FALSE; current->FileOffset.QuadPart = ROUND_DOWN(FileOffset, VACB_MAPPING_GRANULARITY); current->SharedCacheMap = SharedCacheMap; current->MappedCount = 0; current->ReferenceCount = 0; InitializeListHead(¤t->CacheMapVacbListEntry); InitializeListHead(¤t->DirtyVacbListEntry); InitializeListHead(¤t->VacbLruListEntry);
CcRosVacbIncRefCount(current);
while (TRUE) { /* Map VACB in system space */ Status = MmMapViewInSystemSpaceEx(SharedCacheMap->Section, ¤t->BaseAddress, &ViewSize, ¤t->FileOffset, 0); if (NT_SUCCESS(Status)) { break; }
/* * If no space left, try to prune one unused VACB to recover space to map our VACB. * If it succeeds, retry to map, otherwise just fail. */ if (!CcRosFreeOneUnusedVacb()) { ExFreeToNPagedLookasideList(&VacbLookasideList, current); return Status; } }
#if DBG if (SharedCacheMap->Trace) { DPRINT1("CacheMap 0x%p: new VACB: 0x%p, file offset %I64d, BaseAddress %p\n", SharedCacheMap, current, current->FileOffset.QuadPart, current->BaseAddress); }#endif
oldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
*Vacb = current; /* There is window between the call to CcRosLookupVacb * and CcRosCreateVacb. We must check if a VACB for the * file offset exist. If there is a VACB, we release * our newly created VACB and return the existing one. */ KeAcquireSpinLockAtDpcLevel(&SharedCacheMap->CacheMapLock); current_entry = SharedCacheMap->CacheMapVacbListHead.Flink; previous = NULL; while (current_entry != &SharedCacheMap->CacheMapVacbListHead) { current = CONTAINING_RECORD(current_entry, ROS_VACB, CacheMapVacbListEntry); if (IsPointInRange(current->FileOffset.QuadPart, VACB_MAPPING_GRANULARITY, FileOffset)) { CcRosVacbIncRefCount(current); KeReleaseSpinLockFromDpcLevel(&SharedCacheMap->CacheMapLock);#if DBG if (SharedCacheMap->Trace) { DPRINT1("CacheMap 0x%p: deleting newly created VACB 0x%p ( found existing one 0x%p )\n", SharedCacheMap, (*Vacb), current); }#endif KeReleaseQueuedSpinLock(LockQueueMasterLock, oldIrql);
Refs = CcRosVacbDecRefCount(*Vacb); ASSERT(Refs == 0);
*Vacb = current; return STATUS_SUCCESS; } if (current->FileOffset.QuadPart < FileOffset) { ASSERT(previous == NULL || previous->FileOffset.QuadPart < current->FileOffset.QuadPart); previous = current; } if (current->FileOffset.QuadPart > FileOffset) break; current_entry = current_entry->Flink; } /* There was no existing VACB. */ current = *Vacb; if (previous) { InsertHeadList(&previous->CacheMapVacbListEntry, ¤t->CacheMapVacbListEntry); } else { InsertHeadList(&SharedCacheMap->CacheMapVacbListHead, ¤t->CacheMapVacbListEntry); } KeReleaseSpinLockFromDpcLevel(&SharedCacheMap->CacheMapLock); InsertTailList(&VacbLruListHead, ¤t->VacbLruListEntry);
/* Reference it to allow release */ CcRosVacbIncRefCount(current);
KeReleaseQueuedSpinLock(LockQueueMasterLock, oldIrql);
return Status;}
BOOLEANCcRosEnsureVacbResident( _In_ PROS_VACB Vacb, _In_ BOOLEAN Wait, _In_ BOOLEAN NoRead, _In_ ULONG Offset, _In_ ULONG Length){ PROS_SHARED_CACHE_MAP SharedCacheMap = Vacb->SharedCacheMap;
ASSERT((Offset + Length) <= VACB_MAPPING_GRANULARITY);
#if 0 if ((Vacb->FileOffset.QuadPart + Offset) > SharedCacheMap->SectionSize.QuadPart) { DPRINT1("Vacb read beyond the file size!\n"); return FALSE; }#endif
/* Check if the pages are resident */ if (!MmIsDataSectionResident(SharedCacheMap->FileObject->SectionObjectPointer, Vacb->FileOffset.QuadPart + Offset, Length)) { if (!Wait) { return FALSE; }
if (!NoRead) { NTSTATUS Status = MmMakeDataSectionResident(SharedCacheMap->FileObject->SectionObjectPointer, Vacb->FileOffset.QuadPart + Offset, Length, &SharedCacheMap->ValidDataLength); if (!NT_SUCCESS(Status)) ExRaiseStatus(Status); } }
return TRUE;}
NTSTATUSCcRosGetVacb ( PROS_SHARED_CACHE_MAP SharedCacheMap, LONGLONG FileOffset, PROS_VACB *Vacb){ PROS_VACB current; NTSTATUS Status; ULONG Refs; KIRQL OldIrql;
ASSERT(SharedCacheMap);
DPRINT("CcRosGetVacb()\n");
/* * Look for a VACB already mapping the same data. */ current = CcRosLookupVacb(SharedCacheMap, FileOffset); if (current == NULL) { /* * Otherwise create a new VACB. */ Status = CcRosCreateVacb(SharedCacheMap, FileOffset, ¤t); if (!NT_SUCCESS(Status)) { return Status; } }
Refs = CcRosVacbGetRefCount(current);
OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
/* Move to the tail of the LRU list */ RemoveEntryList(¤t->VacbLruListEntry); InsertTailList(&VacbLruListHead, ¤t->VacbLruListEntry);
KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
/* * Return the VACB to the caller. */ *Vacb = current;
ASSERT(Refs > 1);
return STATUS_SUCCESS;}
NTSTATUSCcRosRequestVacb ( PROS_SHARED_CACHE_MAP SharedCacheMap, LONGLONG FileOffset, PROS_VACB *Vacb)/* * FUNCTION: Request a page mapping for a shared cache map */{
ASSERT(SharedCacheMap);
if (FileOffset % VACB_MAPPING_GRANULARITY != 0) { DPRINT1("Bad FileOffset %I64x: should be multiple of %x\n", FileOffset, VACB_MAPPING_GRANULARITY); KeBugCheck(CACHE_MANAGER); }
return CcRosGetVacb(SharedCacheMap, FileOffset, Vacb);}
NTSTATUSCcRosInternalFreeVacb ( PROS_VACB Vacb)/* * FUNCTION: Releases a VACB associated with a shared cache map */{ NTSTATUS Status;
DPRINT("Freeing VACB 0x%p\n", Vacb);#if DBG if (Vacb->SharedCacheMap->Trace) { DPRINT1("CacheMap 0x%p: deleting VACB: 0x%p\n", Vacb->SharedCacheMap, Vacb); }#endif
if (Vacb->ReferenceCount != 0) { DPRINT1("Invalid free: %ld\n", Vacb->ReferenceCount); if (Vacb->SharedCacheMap->FileObject && Vacb->SharedCacheMap->FileObject->FileName.Length) { DPRINT1("For file: %wZ\n", &Vacb->SharedCacheMap->FileObject->FileName); } }
ASSERT(Vacb->ReferenceCount == 0); ASSERT(IsListEmpty(&Vacb->CacheMapVacbListEntry)); ASSERT(IsListEmpty(&Vacb->DirtyVacbListEntry)); ASSERT(IsListEmpty(&Vacb->VacbLruListEntry));
/* Delete the mapping */ Status = MmUnmapViewInSystemSpace(Vacb->BaseAddress); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to unmap VACB from System address space! Status 0x%08X\n", Status); ASSERT(FALSE); /* Proceed with the deĺetion anyway */ }
RtlFillMemory(Vacb, sizeof(*Vacb), 0xfd); ExFreeToNPagedLookasideList(&VacbLookasideList, Vacb); return STATUS_SUCCESS;}
/* * @implemented */VOIDNTAPICcFlushCache ( IN PSECTION_OBJECT_POINTERS SectionObjectPointers, IN PLARGE_INTEGER FileOffset OPTIONAL, IN ULONG Length, OUT PIO_STATUS_BLOCK IoStatus){ PROS_SHARED_CACHE_MAP SharedCacheMap; LONGLONG FlushStart, FlushEnd; NTSTATUS Status;
CCTRACE(CC_API_DEBUG, "SectionObjectPointers=%p FileOffset=0x%I64X Length=%lu\n", SectionObjectPointers, FileOffset ? FileOffset->QuadPart : 0LL, Length);
if (!SectionObjectPointers) { Status = STATUS_INVALID_PARAMETER; goto quit; }
if (!SectionObjectPointers->SharedCacheMap) { /* Forward this to Mm */ MmFlushSegment(SectionObjectPointers, FileOffset, Length, IoStatus); return; }
SharedCacheMap = SectionObjectPointers->SharedCacheMap; ASSERT(SharedCacheMap); if (FileOffset) { FlushStart = FileOffset->QuadPart; Status = RtlLongLongAdd(FlushStart, Length, &FlushEnd); if (!NT_SUCCESS(Status)) goto quit; } else { FlushStart = 0; FlushEnd = SharedCacheMap->FileSize.QuadPart; }
Status = STATUS_SUCCESS; if (IoStatus) { IoStatus->Information = 0; }
KeAcquireGuardedMutex(&SharedCacheMap->FlushCacheLock);
/* * We flush the VACBs that we find here. * If there is no (dirty) VACB, it doesn't mean that there is no data to flush, so we call Mm to be sure. * This is suboptimal, but this is due to the lack of granularity of how we track dirty cache data */ while (FlushStart < FlushEnd) { BOOLEAN DirtyVacb = FALSE; PROS_VACB vacb = CcRosLookupVacb(SharedCacheMap, FlushStart);
if (vacb != NULL) { if (vacb->Dirty) { IO_STATUS_BLOCK VacbIosb = { 0 }; Status = CcRosFlushVacb(vacb, &VacbIosb); if (!NT_SUCCESS(Status)) { CcRosReleaseVacb(SharedCacheMap, vacb, FALSE, FALSE); break; } DirtyVacb = TRUE;
if (IoStatus) IoStatus->Information += VacbIosb.Information; }
CcRosReleaseVacb(SharedCacheMap, vacb, FALSE, FALSE); }
if (!DirtyVacb) { IO_STATUS_BLOCK MmIosb; LARGE_INTEGER MmOffset;
MmOffset.QuadPart = FlushStart;
if (FlushEnd - (FlushEnd % VACB_MAPPING_GRANULARITY) <= FlushStart) { /* The whole range fits within a VACB chunk. */ Status = MmFlushSegment(SectionObjectPointers, &MmOffset, FlushEnd - FlushStart, &MmIosb); } else { ULONG MmLength = VACB_MAPPING_GRANULARITY - (FlushStart % VACB_MAPPING_GRANULARITY); Status = MmFlushSegment(SectionObjectPointers, &MmOffset, MmLength, &MmIosb); }
if (!NT_SUCCESS(Status)) break;
if (IoStatus) IoStatus->Information += MmIosb.Information;
/* Update VDL */ if (SharedCacheMap->ValidDataLength.QuadPart < FlushEnd) SharedCacheMap->ValidDataLength.QuadPart = FlushEnd; }
if (!NT_SUCCESS(RtlLongLongAdd(FlushStart, VACB_MAPPING_GRANULARITY, &FlushStart))) { /* We're at the end of file ! */ break; }
/* Round down to next VACB start now */ FlushStart -= FlushStart % VACB_MAPPING_GRANULARITY; }
KeReleaseGuardedMutex(&SharedCacheMap->FlushCacheLock);
quit: if (IoStatus) { IoStatus->Status = Status; }}
NTSTATUSCcRosReleaseFileCache ( PFILE_OBJECT FileObject)/* * FUNCTION: Called by the file system when a handle to a file object * has been closed. */{ KIRQL OldIrql; PPRIVATE_CACHE_MAP PrivateMap; PROS_SHARED_CACHE_MAP SharedCacheMap;
OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) { SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
/* Closing the handle, so kill the private cache map * Before you event try to remove it from FO, always * lock the master lock, to be sure not to race * with a potential read ahead ongoing! */ PrivateMap = FileObject->PrivateCacheMap; FileObject->PrivateCacheMap = NULL;
if (PrivateMap != NULL) { /* Remove it from the file */ KeAcquireSpinLockAtDpcLevel(&SharedCacheMap->CacheMapLock); RemoveEntryList(&PrivateMap->PrivateLinks); KeReleaseSpinLockFromDpcLevel(&SharedCacheMap->CacheMapLock);
/* And free it. */ if (PrivateMap != &SharedCacheMap->PrivateCacheMap) { ExFreePoolWithTag(PrivateMap, TAG_PRIVATE_CACHE_MAP); } else { PrivateMap->NodeTypeCode = 0; }
ASSERT(SharedCacheMap->OpenCount > 0);
SharedCacheMap->OpenCount--; if (SharedCacheMap->OpenCount == 0) { CcRosDeleteFileCache(FileObject, SharedCacheMap, &OldIrql); } } } KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); return STATUS_SUCCESS;}
NTSTATUSCcRosInitializeFileCache ( PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes, BOOLEAN PinAccess, PCACHE_MANAGER_CALLBACKS CallBacks, PVOID LazyWriterContext)/* * FUNCTION: Initializes a shared cache map for a file object */{ KIRQL OldIrql; BOOLEAN Allocated; PROS_SHARED_CACHE_MAP SharedCacheMap;
DPRINT("CcRosInitializeFileCache(FileObject 0x%p)\n", FileObject);
OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
Allocated = FALSE; SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; if (SharedCacheMap == NULL) { SharedCacheMap = ExAllocateFromNPagedLookasideList(&SharedCacheMapLookasideList); if (SharedCacheMap == NULL) { KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(SharedCacheMap, sizeof(*SharedCacheMap)); SharedCacheMap->NodeTypeCode = NODE_TYPE_SHARED_MAP; SharedCacheMap->NodeByteSize = sizeof(*SharedCacheMap); SharedCacheMap->FileObject = FileObject; SharedCacheMap->Callbacks = CallBacks; SharedCacheMap->LazyWriteContext = LazyWriterContext; SharedCacheMap->SectionSize = FileSizes->AllocationSize; SharedCacheMap->FileSize = FileSizes->FileSize; SharedCacheMap->ValidDataLength = FileSizes->ValidDataLength; SharedCacheMap->PinAccess = PinAccess; SharedCacheMap->DirtyPageThreshold = 0; SharedCacheMap->DirtyPages = 0; InitializeListHead(&SharedCacheMap->PrivateList); KeInitializeSpinLock(&SharedCacheMap->CacheMapLock); InitializeListHead(&SharedCacheMap->CacheMapVacbListHead); InitializeListHead(&SharedCacheMap->BcbList); KeInitializeGuardedMutex(&SharedCacheMap->FlushCacheLock);
SharedCacheMap->Flags = SHARED_CACHE_MAP_IN_CREATION;
ObReferenceObjectByPointer(FileObject, FILE_ALL_ACCESS, NULL, KernelMode);
Allocated = TRUE; FileObject->SectionObjectPointer->SharedCacheMap = SharedCacheMap;
//CcRosTraceCacheMap(SharedCacheMap, TRUE); } else if (SharedCacheMap->Flags & SHARED_CACHE_MAP_IN_CREATION) { /* The shared cache map is being created somewhere else. Wait for that to happen */ KEVENT Waiter; PKEVENT PreviousWaiter = SharedCacheMap->CreateEvent;
KeInitializeEvent(&Waiter, NotificationEvent, FALSE); SharedCacheMap->CreateEvent = &Waiter;
KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
KeWaitForSingleObject(&Waiter, Executive, KernelMode, FALSE, NULL);
if (PreviousWaiter) KeSetEvent(PreviousWaiter, IO_NO_INCREMENT, FALSE);
OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); }
if (FileObject->PrivateCacheMap == NULL) { PPRIVATE_CACHE_MAP PrivateMap;
/* Allocate the private cache map for this handle */ if (SharedCacheMap->PrivateCacheMap.NodeTypeCode != 0) { PrivateMap = ExAllocatePoolWithTag(NonPagedPool, sizeof(PRIVATE_CACHE_MAP), TAG_PRIVATE_CACHE_MAP); } else { PrivateMap = &SharedCacheMap->PrivateCacheMap; }
if (PrivateMap == NULL) { /* If we also allocated the shared cache map for this file, kill it */ if (Allocated) { RemoveEntryList(&SharedCacheMap->SharedCacheMapLinks);
FileObject->SectionObjectPointer->SharedCacheMap = NULL; ObDereferenceObject(FileObject); ExFreeToNPagedLookasideList(&SharedCacheMapLookasideList, SharedCacheMap); }
KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); return STATUS_INSUFFICIENT_RESOURCES; }
/* Initialize it */ RtlZeroMemory(PrivateMap, sizeof(PRIVATE_CACHE_MAP)); PrivateMap->NodeTypeCode = NODE_TYPE_PRIVATE_MAP; PrivateMap->ReadAheadMask = PAGE_SIZE - 1; PrivateMap->FileObject = FileObject; KeInitializeSpinLock(&PrivateMap->ReadAheadSpinLock);
/* Link it to the file */ KeAcquireSpinLockAtDpcLevel(&SharedCacheMap->CacheMapLock); InsertTailList(&SharedCacheMap->PrivateList, &PrivateMap->PrivateLinks); KeReleaseSpinLockFromDpcLevel(&SharedCacheMap->CacheMapLock);
FileObject->PrivateCacheMap = PrivateMap; SharedCacheMap->OpenCount++; }
KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
/* Create the section */ if (Allocated) { NTSTATUS Status;
ASSERT(SharedCacheMap->Section == NULL);
Status = MmCreateSection( &SharedCacheMap->Section, SECTION_ALL_ACCESS, NULL, &SharedCacheMap->SectionSize, PAGE_READWRITE, SEC_RESERVE, NULL, FileObject);
ASSERT(NT_SUCCESS(Status));
if (!NT_SUCCESS(Status)) { CcRosReleaseFileCache(FileObject); return Status; }
OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
InsertTailList(&CcCleanSharedCacheMapList, &SharedCacheMap->SharedCacheMapLinks); SharedCacheMap->Flags &= ~SHARED_CACHE_MAP_IN_CREATION;
if (SharedCacheMap->CreateEvent) { KeSetEvent(SharedCacheMap->CreateEvent, IO_NO_INCREMENT, FALSE); SharedCacheMap->CreateEvent = NULL; }
KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); }
return STATUS_SUCCESS;}
/* * @implemented */PFILE_OBJECTNTAPICcGetFileObjectFromSectionPtrs ( IN PSECTION_OBJECT_POINTERS SectionObjectPointers){ PROS_SHARED_CACHE_MAP SharedCacheMap;
CCTRACE(CC_API_DEBUG, "SectionObjectPointers=%p\n", SectionObjectPointers);
if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap) { SharedCacheMap = SectionObjectPointers->SharedCacheMap; ASSERT(SharedCacheMap); return SharedCacheMap->FileObject; } return NULL;}
CODE_SEG("INIT")VOIDNTAPICcInitView ( VOID){ DPRINT("CcInitView()\n");
InitializeListHead(&DirtyVacbListHead); InitializeListHead(&VacbLruListHead); InitializeListHead(&CcDeferredWrites); InitializeListHead(&CcCleanSharedCacheMapList); KeInitializeSpinLock(&CcDeferredWriteSpinLock); ExInitializeNPagedLookasideList(&iBcbLookasideList, NULL, NULL, 0, sizeof(INTERNAL_BCB), TAG_BCB, 20); ExInitializeNPagedLookasideList(&SharedCacheMapLookasideList, NULL, NULL, 0, sizeof(ROS_SHARED_CACHE_MAP), TAG_SHARED_CACHE_MAP, 20); ExInitializeNPagedLookasideList(&VacbLookasideList, NULL, NULL, 0, sizeof(ROS_VACB), TAG_VACB, 20);
CcInitCacheZeroPage();}
#if DBG && defined(KDBG)
#include <kdbg/kdb.h>
BOOLEANExpKdbgExtFileCache(ULONG Argc, PCHAR Argv[]){ PLIST_ENTRY ListEntry; UNICODE_STRING NoName = RTL_CONSTANT_STRING(L"No name for File");
KdbpPrint(" Usage Summary (in kb)\n"); KdbpPrint("Shared\t\tMapped\tDirty\tName\n"); /* No need to lock the spin lock here, we're in DBG */ for (ListEntry = CcCleanSharedCacheMapList.Flink; ListEntry != &CcCleanSharedCacheMapList; ListEntry = ListEntry->Flink) { PLIST_ENTRY Vacbs; ULONG Mapped = 0, Dirty = 0; PROS_SHARED_CACHE_MAP SharedCacheMap; PUNICODE_STRING FileName; PWSTR Extra = L"";
SharedCacheMap = CONTAINING_RECORD(ListEntry, ROS_SHARED_CACHE_MAP, SharedCacheMapLinks);
/* Dirty size */ Dirty = (SharedCacheMap->DirtyPages * PAGE_SIZE) / 1024;
/* First, count for all the associated VACB */ for (Vacbs = SharedCacheMap->CacheMapVacbListHead.Flink; Vacbs != &SharedCacheMap->CacheMapVacbListHead; Vacbs = Vacbs->Flink) { Mapped += VACB_MAPPING_GRANULARITY / 1024; }
/* Setup name */ if (SharedCacheMap->FileObject != NULL && SharedCacheMap->FileObject->FileName.Length != 0) { FileName = &SharedCacheMap->FileObject->FileName; } else if (SharedCacheMap->FileObject != NULL && SharedCacheMap->FileObject->FsContext != NULL && ((PFSRTL_COMMON_FCB_HEADER)(SharedCacheMap->FileObject->FsContext))->NodeTypeCode == 0x0502 && ((PFSRTL_COMMON_FCB_HEADER)(SharedCacheMap->FileObject->FsContext))->NodeByteSize == 0x1F8 && ((PUNICODE_STRING)(((PUCHAR)SharedCacheMap->FileObject->FsContext) + 0x100))->Length != 0) { FileName = (PUNICODE_STRING)(((PUCHAR)SharedCacheMap->FileObject->FsContext) + 0x100); Extra = L" (FastFAT)"; } else { FileName = &NoName; }
/* And print */ KdbpPrint("%p\t%d\t%d\t%wZ%S\n", SharedCacheMap, Mapped, Dirty, FileName, Extra); }
return TRUE;}
BOOLEANExpKdbgExtDefWrites(ULONG Argc, PCHAR Argv[]){ KdbpPrint("CcTotalDirtyPages:\t%lu (%lu Kb)\n", CcTotalDirtyPages, (CcTotalDirtyPages * PAGE_SIZE) / 1024); KdbpPrint("CcDirtyPageThreshold:\t%lu (%lu Kb)\n", CcDirtyPageThreshold, (CcDirtyPageThreshold * PAGE_SIZE) / 1024); KdbpPrint("MmAvailablePages:\t%lu (%lu Kb)\n", MmAvailablePages, (MmAvailablePages * PAGE_SIZE) / 1024); KdbpPrint("MmThrottleTop:\t\t%lu (%lu Kb)\n", MmThrottleTop, (MmThrottleTop * PAGE_SIZE) / 1024); KdbpPrint("MmThrottleBottom:\t%lu (%lu Kb)\n", MmThrottleBottom, (MmThrottleBottom * PAGE_SIZE) / 1024); KdbpPrint("MmModifiedPageListHead.Total:\t%lu (%lu Kb)\n", MmModifiedPageListHead.Total, (MmModifiedPageListHead.Total * PAGE_SIZE) / 1024);
if (CcTotalDirtyPages >= CcDirtyPageThreshold) { KdbpPrint("CcTotalDirtyPages above the threshold, writes should be throttled\n"); } else if (CcTotalDirtyPages + 64 >= CcDirtyPageThreshold) { KdbpPrint("CcTotalDirtyPages within 64 (max charge) pages of the threshold, writes may be throttled\n"); } else { KdbpPrint("CcTotalDirtyPages below the threshold, writes should not be throttled\n"); }
return TRUE;}
#endif // DBG && defined(KDBG)
/* EOF */