2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cc/view.c
5 * PURPOSE: Cache manager
7 * PROGRAMMERS: David Welch (welch@mcmail.com)
10 /* NOTES **********************************************************************
12 * This is not the NT implementation of a file cache nor anything much like
15 * The general procedure for a filesystem to implement a read or write
16 * dispatch routine is as follows
18 * (1) If caching for the FCB hasn't been initiated then so do by calling
19 * CcInitializeFileCache.
21 * (2) For each 4k region which is being read or written obtain a cache page
22 * by calling CcRequestCachePage.
24 * (3) If either the page is being read or not completely written, and it is
25 * not up to date then read its data from the underlying medium. If the read
26 * fails then call CcReleaseCachePage with VALID as FALSE and return a error.
28 * (4) Copy the data into or out of the page as necessary.
30 * (5) Release the cache page
32 /* INCLUDES ******************************************************************/
38 #if defined (ALLOC_PRAGMA)
39 #pragma alloc_text(INIT, CcInitView)
42 /* GLOBALS *******************************************************************/
44 LIST_ENTRY DirtyVacbListHead
;
45 static LIST_ENTRY VacbLruListHead
;
47 KGUARDED_MUTEX ViewLock
;
49 NPAGED_LOOKASIDE_LIST iBcbLookasideList
;
50 static NPAGED_LOOKASIDE_LIST SharedCacheMapLookasideList
;
51 static NPAGED_LOOKASIDE_LIST VacbLookasideList
;
54 * - Amount of pages flushed by lazy writer
55 * - Number of times lazy writer ran
57 ULONG CcLazyWritePages
= 0;
58 ULONG CcLazyWriteIos
= 0;
60 /* Internal vars (MS):
61 * - Threshold above which lazy writer will start action
62 * - Amount of dirty pages
63 * - List for deferred writes
64 * - Spinlock when dealing with the deferred list
66 ULONG CcDirtyPageThreshold
= 0;
67 ULONG CcTotalDirtyPages
= 0;
68 LIST_ENTRY CcDeferredWrites
;
69 KSPIN_LOCK CcDeferredWriteSpinLock
;
71 /* Internal vars (ROS):
72 * - Event to notify lazy writer to shutdown
73 * - Event to inform watchers lazy writer is done for this loop
75 KEVENT iLazyWriterShutdown
;
76 KEVENT iLazyWriterNotify
;
79 static void CcRosVacbIncRefCount_(PROS_VACB vacb
, const char* file
, int line
)
81 ++vacb
->ReferenceCount
;
82 if (vacb
->SharedCacheMap
->Trace
)
84 DbgPrint("(%s:%i) VACB %p ++RefCount=%lu, Dirty %u, PageOut %lu\n",
85 file
, line
, vacb
, vacb
->ReferenceCount
, vacb
->Dirty
, vacb
->PageOut
);
88 static void CcRosVacbDecRefCount_(PROS_VACB vacb
, const char* file
, int line
)
90 --vacb
->ReferenceCount
;
91 if (vacb
->SharedCacheMap
->Trace
)
93 DbgPrint("(%s:%i) VACB %p --RefCount=%lu, Dirty %u, PageOut %lu\n",
94 file
, line
, vacb
, vacb
->ReferenceCount
, vacb
->Dirty
, vacb
->PageOut
);
97 #define CcRosVacbIncRefCount(vacb) CcRosVacbIncRefCount_(vacb,__FILE__,__LINE__)
98 #define CcRosVacbDecRefCount(vacb) CcRosVacbDecRefCount_(vacb,__FILE__,__LINE__)
100 #define CcRosVacbIncRefCount(vacb) (++((vacb)->ReferenceCount))
101 #define CcRosVacbDecRefCount(vacb) (--((vacb)->ReferenceCount))
105 CcRosInternalFreeVacb(PROS_VACB Vacb
);
108 /* FUNCTIONS *****************************************************************/
113 PROS_SHARED_CACHE_MAP SharedCacheMap
,
118 PLIST_ENTRY current_entry
;
124 SharedCacheMap
->Trace
= Trace
;
128 DPRINT1("Enabling Tracing for CacheMap 0x%p:\n", SharedCacheMap
);
130 KeAcquireGuardedMutex(&ViewLock
);
131 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldirql
);
133 current_entry
= SharedCacheMap
->CacheMapVacbListHead
.Flink
;
134 while (current_entry
!= &SharedCacheMap
->CacheMapVacbListHead
)
136 current
= CONTAINING_RECORD(current_entry
, ROS_VACB
, CacheMapVacbListEntry
);
137 current_entry
= current_entry
->Flink
;
139 DPRINT1(" VACB 0x%p enabled, RefCount %lu, Dirty %u, PageOut %lu\n",
140 current
, current
->ReferenceCount
, current
->Dirty
, current
->PageOut
);
142 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldirql
);
143 KeReleaseGuardedMutex(&ViewLock
);
147 DPRINT1("Disabling Tracing for CacheMap 0x%p:\n", SharedCacheMap
);
151 UNREFERENCED_PARAMETER(SharedCacheMap
);
152 UNREFERENCED_PARAMETER(Trace
);
164 Status
= CcWriteVirtualAddress(Vacb
);
165 if (NT_SUCCESS(Status
))
167 KeAcquireGuardedMutex(&ViewLock
);
168 KeAcquireSpinLock(&Vacb
->SharedCacheMap
->CacheMapLock
, &oldIrql
);
171 RemoveEntryList(&Vacb
->DirtyVacbListEntry
);
172 CcTotalDirtyPages
-= VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
;
173 CcRosVacbDecRefCount(Vacb
);
175 KeReleaseSpinLock(&Vacb
->SharedCacheMap
->CacheMapLock
, oldIrql
);
176 KeReleaseGuardedMutex(&ViewLock
);
184 CcRosFlushDirtyPages (
188 BOOLEAN CalledFromLazy
)
190 PLIST_ENTRY current_entry
;
194 LARGE_INTEGER ZeroTimeout
;
196 DPRINT("CcRosFlushDirtyPages(Target %lu)\n", Target
);
199 ZeroTimeout
.QuadPart
= 0;
201 KeEnterCriticalRegion();
202 KeAcquireGuardedMutex(&ViewLock
);
204 current_entry
= DirtyVacbListHead
.Flink
;
205 if (current_entry
== &DirtyVacbListHead
)
207 DPRINT("No Dirty pages\n");
210 while ((current_entry
!= &DirtyVacbListHead
) && (Target
> 0))
212 current
= CONTAINING_RECORD(current_entry
,
215 current_entry
= current_entry
->Flink
;
217 CcRosVacbIncRefCount(current
);
219 /* When performing lazy write, don't handle temporary files */
220 if (CalledFromLazy
&&
221 BooleanFlagOn(current
->SharedCacheMap
->FileObject
->Flags
, FO_TEMPORARY_FILE
))
223 CcRosVacbDecRefCount(current
);
227 Locked
= current
->SharedCacheMap
->Callbacks
->AcquireForLazyWrite(
228 current
->SharedCacheMap
->LazyWriteContext
, Wait
);
231 CcRosVacbDecRefCount(current
);
235 Status
= CcRosAcquireVacbLock(current
,
236 Wait
? NULL
: &ZeroTimeout
);
237 if (Status
!= STATUS_SUCCESS
)
239 current
->SharedCacheMap
->Callbacks
->ReleaseFromLazyWrite(
240 current
->SharedCacheMap
->LazyWriteContext
);
241 CcRosVacbDecRefCount(current
);
245 ASSERT(current
->Dirty
);
247 /* One reference is added above */
248 if (current
->ReferenceCount
> 2)
250 CcRosReleaseVacbLock(current
);
251 current
->SharedCacheMap
->Callbacks
->ReleaseFromLazyWrite(
252 current
->SharedCacheMap
->LazyWriteContext
);
253 CcRosVacbDecRefCount(current
);
257 KeReleaseGuardedMutex(&ViewLock
);
259 Status
= CcRosFlushVacb(current
);
261 CcRosReleaseVacbLock(current
);
262 current
->SharedCacheMap
->Callbacks
->ReleaseFromLazyWrite(
263 current
->SharedCacheMap
->LazyWriteContext
);
265 KeAcquireGuardedMutex(&ViewLock
);
266 CcRosVacbDecRefCount(current
);
268 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
) &&
269 (Status
!= STATUS_MEDIA_WRITE_PROTECTED
))
271 DPRINT1("CC: Failed to flush VACB.\n");
277 /* How many pages did we free? */
278 PagesFreed
= VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
;
279 (*Count
) += PagesFreed
;
281 /* Make sure we don't overflow target! */
282 if (Target
< PagesFreed
)
284 /* If we would have, jump to zero directly */
289 Target
-= PagesFreed
;
293 current_entry
= DirtyVacbListHead
.Flink
;
296 KeReleaseGuardedMutex(&ViewLock
);
297 KeLeaveCriticalRegion();
299 DPRINT("CcRosFlushDirtyPages() finished\n");
300 return STATUS_SUCCESS
;
303 /* FIXME: Someday this could somewhat implement write-behind/read-ahead */
306 CciLazyWriter(PVOID Unused
)
308 LARGE_INTEGER OneSecond
;
310 OneSecond
.QuadPart
= (LONGLONG
)-1*1000*1000*10;
315 PLIST_ENTRY ListEntry
;
316 ULONG Target
, Count
= 0;
318 /* One per second or until we have to stop */
319 Status
= KeWaitForSingleObject(&iLazyWriterShutdown
,
325 /* If we succeeed, we've to stop running! */
326 if (Status
== STATUS_SUCCESS
)
331 /* We're not sleeping anymore */
332 KeClearEvent(&iLazyWriterNotify
);
334 /* Our target is one-eighth of the dirty pages */
335 Target
= CcTotalDirtyPages
/ 8;
339 DPRINT("Lazy writer starting (%d)\n", Target
);
340 CcRosFlushDirtyPages(Target
, &Count
, FALSE
, TRUE
);
342 /* And update stats */
343 CcLazyWritePages
+= Count
;
345 DPRINT("Lazy writer done (%d)\n", Count
);
348 /* Inform people waiting on us that we're done */
349 KeSetEvent(&iLazyWriterNotify
, IO_DISK_INCREMENT
, FALSE
);
351 /* Likely not optimal, but let's handle one deferred write now! */
352 ListEntry
= ExInterlockedRemoveHeadList(&CcDeferredWrites
, &CcDeferredWriteSpinLock
);
353 if (ListEntry
!= NULL
)
355 PROS_DEFERRED_WRITE_CONTEXT Context
;
357 /* Extract the context */
358 Context
= CONTAINING_RECORD(ListEntry
, ROS_DEFERRED_WRITE_CONTEXT
, CcDeferredWritesEntry
);
360 /* Can we write now? */
361 if (CcCanIWrite(Context
->FileObject
, Context
->BytesToWrite
, FALSE
, Context
->Retrying
))
363 /* Yes! Do it, and destroy the associated context */
364 Context
->PostRoutine(Context
->Context1
, Context
->Context2
);
365 ExFreePoolWithTag(Context
, 'CcDw');
369 /* Otherwise, requeue it, but in tail, so that it doesn't block others
370 * This is clearly to improve, but given the poor algorithm used now
371 * It's better than nothing!
373 ExInterlockedInsertTailList(&CcDeferredWrites
,
374 &Context
->CcDeferredWritesEntry
,
375 &CcDeferredWriteSpinLock
);
387 * FUNCTION: Try to free some memory from the file cache.
389 * Target - The number of pages to be freed.
390 * Priority - The priority of free (currently unused).
391 * NrFreed - Points to a variable where the number of pages
392 * actually freed is returned.
395 PLIST_ENTRY current_entry
;
402 BOOLEAN FlushedPages
= FALSE
;
404 DPRINT("CcRosTrimCache(Target %lu)\n", Target
);
406 InitializeListHead(&FreeList
);
411 KeAcquireGuardedMutex(&ViewLock
);
413 current_entry
= VacbLruListHead
.Flink
;
414 while (current_entry
!= &VacbLruListHead
)
416 current
= CONTAINING_RECORD(current_entry
,
419 current_entry
= current_entry
->Flink
;
421 KeAcquireSpinLock(¤t
->SharedCacheMap
->CacheMapLock
, &oldIrql
);
423 /* Reference the VACB */
424 CcRosVacbIncRefCount(current
);
426 /* Check if it's mapped and not dirty */
427 if (current
->MappedCount
> 0 && !current
->Dirty
)
429 /* We have to break these locks because Cc sucks */
430 KeReleaseSpinLock(¤t
->SharedCacheMap
->CacheMapLock
, oldIrql
);
431 KeReleaseGuardedMutex(&ViewLock
);
433 /* Page out the VACB */
434 for (i
= 0; i
< VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
; i
++)
436 Page
= (PFN_NUMBER
)(MmGetPhysicalAddress((PUCHAR
)current
->BaseAddress
+ (i
* PAGE_SIZE
)).QuadPart
>> PAGE_SHIFT
);
438 MmPageOutPhysicalAddress(Page
);
441 /* Reacquire the locks */
442 KeAcquireGuardedMutex(&ViewLock
);
443 KeAcquireSpinLock(¤t
->SharedCacheMap
->CacheMapLock
, &oldIrql
);
446 /* Dereference the VACB */
447 CcRosVacbDecRefCount(current
);
449 /* Check if we can free this entry now */
450 if (current
->ReferenceCount
== 0)
452 ASSERT(!current
->Dirty
);
453 ASSERT(!current
->MappedCount
);
455 RemoveEntryList(¤t
->CacheMapVacbListEntry
);
456 RemoveEntryList(¤t
->VacbLruListEntry
);
457 InsertHeadList(&FreeList
, ¤t
->CacheMapVacbListEntry
);
459 /* Calculate how many pages we freed for Mm */
460 PagesFreed
= min(VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
, Target
);
461 Target
-= PagesFreed
;
462 (*NrFreed
) += PagesFreed
;
465 KeReleaseSpinLock(¤t
->SharedCacheMap
->CacheMapLock
, oldIrql
);
468 KeReleaseGuardedMutex(&ViewLock
);
470 /* Try flushing pages if we haven't met our target */
471 if ((Target
> 0) && !FlushedPages
)
473 /* Flush dirty pages to disk */
474 CcRosFlushDirtyPages(Target
, &PagesFreed
, FALSE
, FALSE
);
477 /* We can only swap as many pages as we flushed */
478 if (PagesFreed
< Target
) Target
= PagesFreed
;
480 /* Check if we flushed anything */
483 /* Try again after flushing dirty pages */
484 DPRINT("Flushed %lu dirty cache pages to disk\n", PagesFreed
);
489 while (!IsListEmpty(&FreeList
))
491 current_entry
= RemoveHeadList(&FreeList
);
492 current
= CONTAINING_RECORD(current_entry
,
494 CacheMapVacbListEntry
);
495 CcRosInternalFreeVacb(current
);
498 DPRINT("Evicted %lu cache pages\n", (*NrFreed
));
500 return STATUS_SUCCESS
;
506 PROS_SHARED_CACHE_MAP SharedCacheMap
,
515 ASSERT(SharedCacheMap
);
517 DPRINT("CcRosReleaseVacb(SharedCacheMap 0x%p, Vacb 0x%p, Valid %u)\n",
518 SharedCacheMap
, Vacb
, Valid
);
520 KeAcquireGuardedMutex(&ViewLock
);
521 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
525 WasDirty
= Vacb
->Dirty
;
526 Vacb
->Dirty
= Vacb
->Dirty
|| Dirty
;
528 if (!WasDirty
&& Vacb
->Dirty
)
530 InsertTailList(&DirtyVacbListHead
, &Vacb
->DirtyVacbListEntry
);
531 CcTotalDirtyPages
+= VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
;
538 CcRosVacbDecRefCount(Vacb
);
539 if (Mapped
&& (Vacb
->MappedCount
== 1))
541 CcRosVacbIncRefCount(Vacb
);
543 if (!WasDirty
&& Vacb
->Dirty
)
545 CcRosVacbIncRefCount(Vacb
);
548 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
549 KeReleaseGuardedMutex(&ViewLock
);
550 CcRosReleaseVacbLock(Vacb
);
552 return STATUS_SUCCESS
;
555 /* Returns with VACB Lock Held! */
559 PROS_SHARED_CACHE_MAP SharedCacheMap
,
562 PLIST_ENTRY current_entry
;
566 ASSERT(SharedCacheMap
);
568 DPRINT("CcRosLookupVacb(SharedCacheMap 0x%p, FileOffset %I64u)\n",
569 SharedCacheMap
, FileOffset
);
571 KeAcquireGuardedMutex(&ViewLock
);
572 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
574 current_entry
= SharedCacheMap
->CacheMapVacbListHead
.Flink
;
575 while (current_entry
!= &SharedCacheMap
->CacheMapVacbListHead
)
577 current
= CONTAINING_RECORD(current_entry
,
579 CacheMapVacbListEntry
);
580 if (IsPointInRange(current
->FileOffset
.QuadPart
,
581 VACB_MAPPING_GRANULARITY
,
584 CcRosVacbIncRefCount(current
);
585 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
586 KeReleaseGuardedMutex(&ViewLock
);
587 CcRosAcquireVacbLock(current
, NULL
);
590 if (current
->FileOffset
.QuadPart
> FileOffset
)
592 current_entry
= current_entry
->Flink
;
595 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
596 KeReleaseGuardedMutex(&ViewLock
);
607 PROS_SHARED_CACHE_MAP SharedCacheMap
;
609 SharedCacheMap
= Vacb
->SharedCacheMap
;
611 KeAcquireGuardedMutex(&ViewLock
);
612 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
616 InsertTailList(&DirtyVacbListHead
, &Vacb
->DirtyVacbListEntry
);
617 CcTotalDirtyPages
+= VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
;
621 CcRosVacbDecRefCount(Vacb
);
624 /* Move to the tail of the LRU list */
625 RemoveEntryList(&Vacb
->VacbLruListEntry
);
626 InsertTailList(&VacbLruListHead
, &Vacb
->VacbLruListEntry
);
630 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
631 KeReleaseGuardedMutex(&ViewLock
);
637 PROS_SHARED_CACHE_MAP SharedCacheMap
,
642 ASSERT(SharedCacheMap
);
644 DPRINT("CcRosMarkDirtyVacb(SharedCacheMap 0x%p, FileOffset %I64u)\n",
645 SharedCacheMap
, FileOffset
);
647 Vacb
= CcRosLookupVacb(SharedCacheMap
, FileOffset
);
650 KeBugCheck(CACHE_MANAGER
);
653 CcRosMarkDirtyVacb(Vacb
);
656 CcRosReleaseVacbLock(Vacb
);
658 return STATUS_SUCCESS
;
664 PROS_SHARED_CACHE_MAP SharedCacheMap
,
672 ASSERT(SharedCacheMap
);
674 DPRINT("CcRosUnmapVacb(SharedCacheMap 0x%p, FileOffset %I64u, NowDirty %u)\n",
675 SharedCacheMap
, FileOffset
, NowDirty
);
677 Vacb
= CcRosLookupVacb(SharedCacheMap
, FileOffset
);
680 return STATUS_UNSUCCESSFUL
;
683 KeAcquireGuardedMutex(&ViewLock
);
684 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
686 WasDirty
= Vacb
->Dirty
;
687 Vacb
->Dirty
= Vacb
->Dirty
|| NowDirty
;
691 if (!WasDirty
&& NowDirty
)
693 InsertTailList(&DirtyVacbListHead
, &Vacb
->DirtyVacbListEntry
);
694 CcTotalDirtyPages
+= VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
;
697 CcRosVacbDecRefCount(Vacb
);
698 if (!WasDirty
&& NowDirty
)
700 CcRosVacbIncRefCount(Vacb
);
702 if (Vacb
->MappedCount
== 0)
704 CcRosVacbDecRefCount(Vacb
);
707 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
708 KeReleaseGuardedMutex(&ViewLock
);
709 CcRosReleaseVacbLock(Vacb
);
711 return STATUS_SUCCESS
;
721 ULONG_PTR NumberOfPages
;
723 /* Create a memory area. */
724 MmLockAddressSpace(MmGetKernelAddressSpace());
725 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
726 0, // nothing checks for VACB mareas, so set to 0
728 VACB_MAPPING_GRANULARITY
,
730 (PMEMORY_AREA
*)&Vacb
->MemoryArea
,
733 MmUnlockAddressSpace(MmGetKernelAddressSpace());
734 if (!NT_SUCCESS(Status
))
736 DPRINT1("MmCreateMemoryArea failed with %lx for VACB %p\n", Status
, Vacb
);
740 ASSERT(((ULONG_PTR
)Vacb
->BaseAddress
% PAGE_SIZE
) == 0);
741 ASSERT((ULONG_PTR
)Vacb
->BaseAddress
> (ULONG_PTR
)MmSystemRangeStart
);
743 /* Create a virtual mapping for this memory area */
744 NumberOfPages
= BYTES_TO_PAGES(VACB_MAPPING_GRANULARITY
);
745 for (i
= 0; i
< NumberOfPages
; i
++)
747 PFN_NUMBER PageFrameNumber
;
749 MI_SET_USAGE(MI_USAGE_CACHE
);
750 Status
= MmRequestPageMemoryConsumer(MC_CACHE
, TRUE
, &PageFrameNumber
);
751 if (PageFrameNumber
== 0)
753 DPRINT1("Unable to allocate page\n");
754 KeBugCheck(MEMORY_MANAGEMENT
);
757 Status
= MmCreateVirtualMapping(NULL
,
758 (PVOID
)((ULONG_PTR
)Vacb
->BaseAddress
+ (i
* PAGE_SIZE
)),
762 if (!NT_SUCCESS(Status
))
764 DPRINT1("Unable to create virtual mapping\n");
765 KeBugCheck(MEMORY_MANAGEMENT
);
769 return STATUS_SUCCESS
;
775 PROS_SHARED_CACHE_MAP SharedCacheMap
,
781 PLIST_ENTRY current_entry
;
785 ASSERT(SharedCacheMap
);
787 DPRINT("CcRosCreateVacb()\n");
789 if (FileOffset
>= SharedCacheMap
->SectionSize
.QuadPart
)
792 return STATUS_INVALID_PARAMETER
;
795 current
= ExAllocateFromNPagedLookasideList(&VacbLookasideList
);
796 current
->BaseAddress
= NULL
;
797 current
->Valid
= FALSE
;
798 current
->Dirty
= FALSE
;
799 current
->PageOut
= FALSE
;
800 current
->FileOffset
.QuadPart
= ROUND_DOWN(FileOffset
, VACB_MAPPING_GRANULARITY
);
801 current
->SharedCacheMap
= SharedCacheMap
;
803 if (SharedCacheMap
->Trace
)
805 DPRINT1("CacheMap 0x%p: new VACB: 0x%p\n", SharedCacheMap
, current
);
808 current
->MappedCount
= 0;
809 current
->DirtyVacbListEntry
.Flink
= NULL
;
810 current
->DirtyVacbListEntry
.Blink
= NULL
;
811 current
->ReferenceCount
= 1;
812 current
->PinCount
= 0;
813 KeInitializeMutex(¤t
->Mutex
, 0);
814 CcRosAcquireVacbLock(current
, NULL
);
815 KeAcquireGuardedMutex(&ViewLock
);
818 /* There is window between the call to CcRosLookupVacb
819 * and CcRosCreateVacb. We must check if a VACB for the
820 * file offset exist. If there is a VACB, we release
821 * our newly created VACB and return the existing one.
823 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
824 current_entry
= SharedCacheMap
->CacheMapVacbListHead
.Flink
;
826 while (current_entry
!= &SharedCacheMap
->CacheMapVacbListHead
)
828 current
= CONTAINING_RECORD(current_entry
,
830 CacheMapVacbListEntry
);
831 if (IsPointInRange(current
->FileOffset
.QuadPart
,
832 VACB_MAPPING_GRANULARITY
,
835 CcRosVacbIncRefCount(current
);
836 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
838 if (SharedCacheMap
->Trace
)
840 DPRINT1("CacheMap 0x%p: deleting newly created VACB 0x%p ( found existing one 0x%p )\n",
846 CcRosReleaseVacbLock(*Vacb
);
847 KeReleaseGuardedMutex(&ViewLock
);
848 ExFreeToNPagedLookasideList(&VacbLookasideList
, *Vacb
);
850 CcRosAcquireVacbLock(current
, NULL
);
851 return STATUS_SUCCESS
;
853 if (current
->FileOffset
.QuadPart
< FileOffset
)
855 ASSERT(previous
== NULL
||
856 previous
->FileOffset
.QuadPart
< current
->FileOffset
.QuadPart
);
859 if (current
->FileOffset
.QuadPart
> FileOffset
)
861 current_entry
= current_entry
->Flink
;
863 /* There was no existing VACB. */
867 InsertHeadList(&previous
->CacheMapVacbListEntry
, ¤t
->CacheMapVacbListEntry
);
871 InsertHeadList(&SharedCacheMap
->CacheMapVacbListHead
, ¤t
->CacheMapVacbListEntry
);
873 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
874 InsertTailList(&VacbLruListHead
, ¤t
->VacbLruListEntry
);
875 KeReleaseGuardedMutex(&ViewLock
);
877 MI_SET_USAGE(MI_USAGE_CACHE
);
879 if ((SharedCacheMap
->FileObject
) && (SharedCacheMap
->FileObject
->FileName
.Buffer
))
883 pos
= wcsrchr(SharedCacheMap
->FileObject
->FileName
.Buffer
, '\\');
886 len
= wcslen(pos
) * sizeof(WCHAR
);
887 snprintf(MI_PFN_CURRENT_PROCESS_NAME
, min(16, len
), "%S", pos
);
891 snprintf(MI_PFN_CURRENT_PROCESS_NAME
, min(16, len
), "%wZ", &SharedCacheMap
->FileObject
->FileName
);
896 Status
= CcRosMapVacb(current
);
897 if (!NT_SUCCESS(Status
))
899 RemoveEntryList(¤t
->CacheMapVacbListEntry
);
900 RemoveEntryList(¤t
->VacbLruListEntry
);
901 CcRosReleaseVacbLock(current
);
902 ExFreeToNPagedLookasideList(&VacbLookasideList
, current
);
911 PROS_SHARED_CACHE_MAP SharedCacheMap
,
913 PLONGLONG BaseOffset
,
921 ASSERT(SharedCacheMap
);
923 DPRINT("CcRosGetVacb()\n");
926 * Look for a VACB already mapping the same data.
928 current
= CcRosLookupVacb(SharedCacheMap
, FileOffset
);
932 * Otherwise create a new VACB.
934 Status
= CcRosCreateVacb(SharedCacheMap
, FileOffset
, ¤t
);
935 if (!NT_SUCCESS(Status
))
941 KeAcquireGuardedMutex(&ViewLock
);
943 /* Move to the tail of the LRU list */
944 RemoveEntryList(¤t
->VacbLruListEntry
);
945 InsertTailList(&VacbLruListHead
, ¤t
->VacbLruListEntry
);
947 KeReleaseGuardedMutex(&ViewLock
);
950 * Return information about the VACB to the caller.
952 *UptoDate
= current
->Valid
;
953 *BaseAddress
= current
->BaseAddress
;
954 DPRINT("*BaseAddress %p\n", *BaseAddress
);
956 *BaseOffset
= current
->FileOffset
.QuadPart
;
957 return STATUS_SUCCESS
;
963 PROS_SHARED_CACHE_MAP SharedCacheMap
,
969 * FUNCTION: Request a page mapping for a shared cache map
974 ASSERT(SharedCacheMap
);
976 if (FileOffset
% VACB_MAPPING_GRANULARITY
!= 0)
978 DPRINT1("Bad fileoffset %I64x should be multiple of %x",
979 FileOffset
, VACB_MAPPING_GRANULARITY
);
980 KeBugCheck(CACHE_MANAGER
);
983 return CcRosGetVacb(SharedCacheMap
,
995 MEMORY_AREA
* MemoryArea
,
1001 ASSERT(SwapEntry
== 0);
1004 ASSERT(MmGetReferenceCountPage(Page
) == 1);
1005 MmReleasePageMemoryConsumer(MC_CACHE
, Page
);
1010 CcRosInternalFreeVacb (
1013 * FUNCTION: Releases a VACB associated with a shared cache map
1016 DPRINT("Freeing VACB 0x%p\n", Vacb
);
1018 if (Vacb
->SharedCacheMap
->Trace
)
1020 DPRINT1("CacheMap 0x%p: deleting VACB: 0x%p\n", Vacb
->SharedCacheMap
, Vacb
);
1024 MmLockAddressSpace(MmGetKernelAddressSpace());
1025 MmFreeMemoryArea(MmGetKernelAddressSpace(),
1029 MmUnlockAddressSpace(MmGetKernelAddressSpace());
1031 ExFreeToNPagedLookasideList(&VacbLookasideList
, Vacb
);
1032 return STATUS_SUCCESS
;
1041 IN PSECTION_OBJECT_POINTERS SectionObjectPointers
,
1042 IN PLARGE_INTEGER FileOffset OPTIONAL
,
1044 OUT PIO_STATUS_BLOCK IoStatus
)
1046 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1047 LARGE_INTEGER Offset
;
1048 LONGLONG RemainingLength
;
1053 CCTRACE(CC_API_DEBUG
, "SectionObjectPointers=%p FileOffset=%p Length=%lu\n",
1054 SectionObjectPointers
, FileOffset
, Length
);
1056 DPRINT("CcFlushCache(SectionObjectPointers 0x%p, FileOffset 0x%p, Length %lu, IoStatus 0x%p)\n",
1057 SectionObjectPointers
, FileOffset
, Length
, IoStatus
);
1059 if (SectionObjectPointers
&& SectionObjectPointers
->SharedCacheMap
)
1061 SharedCacheMap
= SectionObjectPointers
->SharedCacheMap
;
1062 ASSERT(SharedCacheMap
);
1065 Offset
= *FileOffset
;
1066 RemainingLength
= Length
;
1070 Offset
.QuadPart
= 0;
1071 RemainingLength
= SharedCacheMap
->FileSize
.QuadPart
;
1076 IoStatus
->Status
= STATUS_SUCCESS
;
1077 IoStatus
->Information
= 0;
1080 while (RemainingLength
> 0)
1082 current
= CcRosLookupVacb(SharedCacheMap
, Offset
.QuadPart
);
1083 if (current
!= NULL
)
1087 Status
= CcRosFlushVacb(current
);
1088 if (!NT_SUCCESS(Status
) && IoStatus
!= NULL
)
1090 IoStatus
->Status
= Status
;
1094 CcRosReleaseVacbLock(current
);
1096 KeAcquireGuardedMutex(&ViewLock
);
1097 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
1098 CcRosVacbDecRefCount(current
);
1099 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
1100 KeReleaseGuardedMutex(&ViewLock
);
1103 Offset
.QuadPart
+= VACB_MAPPING_GRANULARITY
;
1104 RemainingLength
-= min(RemainingLength
, VACB_MAPPING_GRANULARITY
);
1111 IoStatus
->Status
= STATUS_INVALID_PARAMETER
;
1118 CcRosDeleteFileCache (
1119 PFILE_OBJECT FileObject
,
1120 PROS_SHARED_CACHE_MAP SharedCacheMap
)
1122 * FUNCTION: Releases the shared cache map associated with a file object
1125 PLIST_ENTRY current_entry
;
1127 LIST_ENTRY FreeList
;
1130 ASSERT(SharedCacheMap
);
1132 SharedCacheMap
->OpenCount
++;
1133 KeReleaseGuardedMutex(&ViewLock
);
1135 CcFlushCache(FileObject
->SectionObjectPointer
, NULL
, 0, NULL
);
1137 KeAcquireGuardedMutex(&ViewLock
);
1138 SharedCacheMap
->OpenCount
--;
1139 if (SharedCacheMap
->OpenCount
== 0)
1141 FileObject
->SectionObjectPointer
->SharedCacheMap
= NULL
;
1146 InitializeListHead(&FreeList
);
1147 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
1148 while (!IsListEmpty(&SharedCacheMap
->CacheMapVacbListHead
))
1150 current_entry
= RemoveTailList(&SharedCacheMap
->CacheMapVacbListHead
);
1151 current
= CONTAINING_RECORD(current_entry
, ROS_VACB
, CacheMapVacbListEntry
);
1152 RemoveEntryList(¤t
->VacbLruListEntry
);
1155 RemoveEntryList(¤t
->DirtyVacbListEntry
);
1156 CcTotalDirtyPages
-= VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
;
1157 DPRINT1("Freeing dirty VACB\n");
1159 InsertHeadList(&FreeList
, ¤t
->CacheMapVacbListEntry
);
1162 SharedCacheMap
->Trace
= FALSE
;
1164 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
1166 KeReleaseGuardedMutex(&ViewLock
);
1167 ObDereferenceObject(SharedCacheMap
->FileObject
);
1169 while (!IsListEmpty(&FreeList
))
1171 current_entry
= RemoveTailList(&FreeList
);
1172 current
= CONTAINING_RECORD(current_entry
, ROS_VACB
, CacheMapVacbListEntry
);
1173 CcRosInternalFreeVacb(current
);
1175 ExFreeToNPagedLookasideList(&SharedCacheMapLookasideList
, SharedCacheMap
);
1176 KeAcquireGuardedMutex(&ViewLock
);
1178 return STATUS_SUCCESS
;
1183 CcRosReferenceCache (
1184 PFILE_OBJECT FileObject
)
1186 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1187 KeAcquireGuardedMutex(&ViewLock
);
1188 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1189 ASSERT(SharedCacheMap
);
1190 ASSERT(SharedCacheMap
->OpenCount
!= 0);
1191 SharedCacheMap
->OpenCount
++;
1192 KeReleaseGuardedMutex(&ViewLock
);
1197 CcRosRemoveIfClosed (
1198 PSECTION_OBJECT_POINTERS SectionObjectPointer
)
1200 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1201 DPRINT("CcRosRemoveIfClosed()\n");
1202 KeAcquireGuardedMutex(&ViewLock
);
1203 SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
1204 if (SharedCacheMap
&& SharedCacheMap
->OpenCount
== 0)
1206 CcRosDeleteFileCache(SharedCacheMap
->FileObject
, SharedCacheMap
);
1208 KeReleaseGuardedMutex(&ViewLock
);
1214 CcRosDereferenceCache (
1215 PFILE_OBJECT FileObject
)
1217 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1218 KeAcquireGuardedMutex(&ViewLock
);
1219 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1220 ASSERT(SharedCacheMap
);
1221 if (SharedCacheMap
->OpenCount
> 0)
1223 SharedCacheMap
->OpenCount
--;
1224 if (SharedCacheMap
->OpenCount
== 0)
1226 MmFreeSectionSegments(SharedCacheMap
->FileObject
);
1227 CcRosDeleteFileCache(FileObject
, SharedCacheMap
);
1230 KeReleaseGuardedMutex(&ViewLock
);
1235 CcRosReleaseFileCache (
1236 PFILE_OBJECT FileObject
)
1238 * FUNCTION: Called by the file system when a handle to a file object
1242 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1244 KeAcquireGuardedMutex(&ViewLock
);
1246 if (FileObject
->SectionObjectPointer
->SharedCacheMap
!= NULL
)
1248 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1249 if (FileObject
->PrivateCacheMap
!= NULL
)
1251 FileObject
->PrivateCacheMap
= NULL
;
1252 if (SharedCacheMap
->OpenCount
> 0)
1254 SharedCacheMap
->OpenCount
--;
1255 if (SharedCacheMap
->OpenCount
== 0)
1257 MmFreeSectionSegments(SharedCacheMap
->FileObject
);
1258 CcRosDeleteFileCache(FileObject
, SharedCacheMap
);
1263 KeReleaseGuardedMutex(&ViewLock
);
1264 return STATUS_SUCCESS
;
1269 CcTryToInitializeFileCache (
1270 PFILE_OBJECT FileObject
)
1272 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1275 KeAcquireGuardedMutex(&ViewLock
);
1277 ASSERT(FileObject
->SectionObjectPointer
);
1278 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1279 if (SharedCacheMap
== NULL
)
1281 Status
= STATUS_UNSUCCESSFUL
;
1285 if (FileObject
->PrivateCacheMap
== NULL
)
1287 FileObject
->PrivateCacheMap
= SharedCacheMap
;
1288 SharedCacheMap
->OpenCount
++;
1290 Status
= STATUS_SUCCESS
;
1292 KeReleaseGuardedMutex(&ViewLock
);
1300 CcRosInitializeFileCache (
1301 PFILE_OBJECT FileObject
,
1302 PCC_FILE_SIZES FileSizes
,
1304 PCACHE_MANAGER_CALLBACKS CallBacks
,
1305 PVOID LazyWriterContext
)
1307 * FUNCTION: Initializes a shared cache map for a file object
1310 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1312 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1313 DPRINT("CcRosInitializeFileCache(FileObject 0x%p, SharedCacheMap 0x%p)\n",
1314 FileObject
, SharedCacheMap
);
1316 KeAcquireGuardedMutex(&ViewLock
);
1317 if (SharedCacheMap
== NULL
)
1319 SharedCacheMap
= ExAllocateFromNPagedLookasideList(&SharedCacheMapLookasideList
);
1320 if (SharedCacheMap
== NULL
)
1322 KeReleaseGuardedMutex(&ViewLock
);
1323 return STATUS_INSUFFICIENT_RESOURCES
;
1325 RtlZeroMemory(SharedCacheMap
, sizeof(*SharedCacheMap
));
1326 ObReferenceObjectByPointer(FileObject
,
1330 SharedCacheMap
->FileObject
= FileObject
;
1331 SharedCacheMap
->Callbacks
= CallBacks
;
1332 SharedCacheMap
->LazyWriteContext
= LazyWriterContext
;
1333 SharedCacheMap
->SectionSize
= FileSizes
->AllocationSize
;
1334 SharedCacheMap
->FileSize
= FileSizes
->FileSize
;
1335 SharedCacheMap
->PinAccess
= PinAccess
;
1336 KeInitializeSpinLock(&SharedCacheMap
->CacheMapLock
);
1337 InitializeListHead(&SharedCacheMap
->CacheMapVacbListHead
);
1338 FileObject
->SectionObjectPointer
->SharedCacheMap
= SharedCacheMap
;
1340 if (FileObject
->PrivateCacheMap
== NULL
)
1342 FileObject
->PrivateCacheMap
= SharedCacheMap
;
1343 SharedCacheMap
->OpenCount
++;
1345 KeReleaseGuardedMutex(&ViewLock
);
1347 return STATUS_SUCCESS
;
1355 CcGetFileObjectFromSectionPtrs (
1356 IN PSECTION_OBJECT_POINTERS SectionObjectPointers
)
1358 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1360 CCTRACE(CC_API_DEBUG
, "SectionObjectPointers=%p\n", SectionObjectPointers
);
1362 if (SectionObjectPointers
&& SectionObjectPointers
->SharedCacheMap
)
1364 SharedCacheMap
= SectionObjectPointers
->SharedCacheMap
;
1365 ASSERT(SharedCacheMap
);
1366 return SharedCacheMap
->FileObject
;
1373 CcShutdownLazyWriter (
1376 /* Simply set the event, lazy writer will stop when it's done */
1377 KeSetEvent(&iLazyWriterShutdown
, IO_DISK_INCREMENT
, FALSE
);
1388 OBJECT_ATTRIBUTES ObjectAttributes
;
1390 DPRINT("CcInitView()\n");
1392 InitializeListHead(&DirtyVacbListHead
);
1393 InitializeListHead(&VacbLruListHead
);
1394 InitializeListHead(&CcDeferredWrites
);
1395 KeInitializeSpinLock(&CcDeferredWriteSpinLock
);
1396 KeInitializeGuardedMutex(&ViewLock
);
1397 ExInitializeNPagedLookasideList(&iBcbLookasideList
,
1401 sizeof(INTERNAL_BCB
),
1404 ExInitializeNPagedLookasideList(&SharedCacheMapLookasideList
,
1408 sizeof(ROS_SHARED_CACHE_MAP
),
1409 TAG_SHARED_CACHE_MAP
,
1411 ExInitializeNPagedLookasideList(&VacbLookasideList
,
1419 MmInitializeMemoryConsumer(MC_CACHE
, CcRosTrimCache
);
1421 /* Initialize lazy writer events */
1422 KeInitializeEvent(&iLazyWriterShutdown
, SynchronizationEvent
, FALSE
);
1423 KeInitializeEvent(&iLazyWriterNotify
, NotificationEvent
, FALSE
);
1425 /* Define lazy writer threshold, depending on system type */
1426 switch (MmQuerySystemSize())
1429 CcDirtyPageThreshold
= MmNumberOfPhysicalPages
/ 8;
1432 case MmMediumSystem
:
1433 CcDirtyPageThreshold
= MmNumberOfPhysicalPages
/ 4;
1437 CcDirtyPageThreshold
= MmNumberOfPhysicalPages
/ 8 + MmNumberOfPhysicalPages
/ 4;
1441 /* Start the lazy writer thread */
1442 InitializeObjectAttributes(&ObjectAttributes
,
1447 Status
= PsCreateSystemThread(&LazyWriter
,
1454 if (!NT_SUCCESS(Status
))
1459 /* Handle is not needed */
1460 ObCloseHandle(LazyWriter
, KernelMode
);
1462 CcInitCacheZeroPage();