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)
8 * Pierre Schweitzer (pierre@reactos.org)
11 /* NOTES **********************************************************************
13 * This is not the NT implementation of a file cache nor anything much like
16 * The general procedure for a filesystem to implement a read or write
17 * dispatch routine is as follows
19 * (1) If caching for the FCB hasn't been initiated then so do by calling
20 * CcInitializeFileCache.
22 * (2) For each 4k region which is being read or written obtain a cache page
23 * by calling CcRequestCachePage.
25 * (3) If either the page is being read or not completely written, and it is
26 * not up to date then read its data from the underlying medium. If the read
27 * fails then call CcReleaseCachePage with VALID as FALSE and return a error.
29 * (4) Copy the data into or out of the page as necessary.
31 * (5) Release the cache page
33 /* INCLUDES ******************************************************************/
39 #if defined (ALLOC_PRAGMA)
40 #pragma alloc_text(INIT, CcInitView)
43 /* GLOBALS *******************************************************************/
45 LIST_ENTRY DirtyVacbListHead
;
46 static LIST_ENTRY VacbLruListHead
;
48 KGUARDED_MUTEX ViewLock
;
50 NPAGED_LOOKASIDE_LIST iBcbLookasideList
;
51 static NPAGED_LOOKASIDE_LIST SharedCacheMapLookasideList
;
52 static NPAGED_LOOKASIDE_LIST VacbLookasideList
;
54 /* Internal vars (MS):
55 * - Threshold above which lazy writer will start action
56 * - Amount of dirty pages
57 * - List for deferred writes
58 * - Spinlock when dealing with the deferred list
59 * - List for "clean" shared cache maps
61 ULONG CcDirtyPageThreshold
= 0;
62 ULONG CcTotalDirtyPages
= 0;
63 LIST_ENTRY CcDeferredWrites
;
64 KSPIN_LOCK CcDeferredWriteSpinLock
;
65 LIST_ENTRY CcCleanSharedCacheMapList
;
67 /* Internal vars (ROS):
68 * - Lock for the CcCleanSharedCacheMapList list
70 KSPIN_LOCK iSharedCacheMapLock
;
73 static void CcRosVacbIncRefCount_(PROS_VACB vacb
, const char* file
, int line
)
75 ++vacb
->ReferenceCount
;
76 if (vacb
->SharedCacheMap
->Trace
)
78 DbgPrint("(%s:%i) VACB %p ++RefCount=%lu, Dirty %u, PageOut %lu\n",
79 file
, line
, vacb
, vacb
->ReferenceCount
, vacb
->Dirty
, vacb
->PageOut
);
82 static void CcRosVacbDecRefCount_(PROS_VACB vacb
, const char* file
, int line
)
84 ASSERT(vacb
->ReferenceCount
!= 0);
85 --vacb
->ReferenceCount
;
86 ASSERT(!(vacb
->ReferenceCount
== 0 && vacb
->Dirty
));
87 if (vacb
->SharedCacheMap
->Trace
)
89 DbgPrint("(%s:%i) VACB %p --RefCount=%lu, Dirty %u, PageOut %lu\n",
90 file
, line
, vacb
, vacb
->ReferenceCount
, vacb
->Dirty
, vacb
->PageOut
);
93 #define CcRosVacbIncRefCount(vacb) CcRosVacbIncRefCount_(vacb,__FILE__,__LINE__)
94 #define CcRosVacbDecRefCount(vacb) CcRosVacbDecRefCount_(vacb,__FILE__,__LINE__)
96 #define CcRosVacbIncRefCount(vacb) (++((vacb)->ReferenceCount))
97 #define CcRosVacbDecRefCount(vacb) (--((vacb)->ReferenceCount))
101 CcRosInternalFreeVacb(PROS_VACB Vacb
);
104 /* FUNCTIONS *****************************************************************/
109 PROS_SHARED_CACHE_MAP SharedCacheMap
,
114 PLIST_ENTRY current_entry
;
120 SharedCacheMap
->Trace
= Trace
;
124 DPRINT1("Enabling Tracing for CacheMap 0x%p:\n", SharedCacheMap
);
126 KeAcquireGuardedMutex(&ViewLock
);
127 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldirql
);
129 current_entry
= SharedCacheMap
->CacheMapVacbListHead
.Flink
;
130 while (current_entry
!= &SharedCacheMap
->CacheMapVacbListHead
)
132 current
= CONTAINING_RECORD(current_entry
, ROS_VACB
, CacheMapVacbListEntry
);
133 current_entry
= current_entry
->Flink
;
135 DPRINT1(" VACB 0x%p enabled, RefCount %lu, Dirty %u, PageOut %lu\n",
136 current
, current
->ReferenceCount
, current
->Dirty
, current
->PageOut
);
138 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldirql
);
139 KeReleaseGuardedMutex(&ViewLock
);
143 DPRINT1("Disabling Tracing for CacheMap 0x%p:\n", SharedCacheMap
);
147 UNREFERENCED_PARAMETER(SharedCacheMap
);
148 UNREFERENCED_PARAMETER(Trace
);
159 Status
= CcWriteVirtualAddress(Vacb
);
160 if (NT_SUCCESS(Status
))
162 CcRosUnmarkDirtyVacb(Vacb
, TRUE
);
170 CcRosFlushDirtyPages (
174 BOOLEAN CalledFromLazy
)
176 PLIST_ENTRY current_entry
;
180 LARGE_INTEGER ZeroTimeout
;
182 DPRINT("CcRosFlushDirtyPages(Target %lu)\n", Target
);
185 ZeroTimeout
.QuadPart
= 0;
187 KeEnterCriticalRegion();
188 KeAcquireGuardedMutex(&ViewLock
);
190 current_entry
= DirtyVacbListHead
.Flink
;
191 if (current_entry
== &DirtyVacbListHead
)
193 DPRINT("No Dirty pages\n");
196 while ((current_entry
!= &DirtyVacbListHead
) && (Target
> 0))
198 current
= CONTAINING_RECORD(current_entry
,
201 current_entry
= current_entry
->Flink
;
203 CcRosVacbIncRefCount(current
);
205 /* When performing lazy write, don't handle temporary files */
206 if (CalledFromLazy
&&
207 BooleanFlagOn(current
->SharedCacheMap
->FileObject
->Flags
, FO_TEMPORARY_FILE
))
209 CcRosVacbDecRefCount(current
);
213 Locked
= current
->SharedCacheMap
->Callbacks
->AcquireForLazyWrite(
214 current
->SharedCacheMap
->LazyWriteContext
, Wait
);
217 CcRosVacbDecRefCount(current
);
221 Status
= CcRosAcquireVacbLock(current
,
222 Wait
? NULL
: &ZeroTimeout
);
223 if (Status
!= STATUS_SUCCESS
)
225 current
->SharedCacheMap
->Callbacks
->ReleaseFromLazyWrite(
226 current
->SharedCacheMap
->LazyWriteContext
);
227 CcRosVacbDecRefCount(current
);
231 ASSERT(current
->Dirty
);
233 /* One reference is added above */
234 if (current
->ReferenceCount
> 2)
236 CcRosReleaseVacbLock(current
);
237 current
->SharedCacheMap
->Callbacks
->ReleaseFromLazyWrite(
238 current
->SharedCacheMap
->LazyWriteContext
);
239 CcRosVacbDecRefCount(current
);
243 KeReleaseGuardedMutex(&ViewLock
);
245 Status
= CcRosFlushVacb(current
);
247 CcRosReleaseVacbLock(current
);
248 current
->SharedCacheMap
->Callbacks
->ReleaseFromLazyWrite(
249 current
->SharedCacheMap
->LazyWriteContext
);
251 KeAcquireGuardedMutex(&ViewLock
);
252 CcRosVacbDecRefCount(current
);
254 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
) &&
255 (Status
!= STATUS_MEDIA_WRITE_PROTECTED
))
257 DPRINT1("CC: Failed to flush VACB.\n");
263 /* How many pages did we free? */
264 PagesFreed
= VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
;
265 (*Count
) += PagesFreed
;
267 /* Make sure we don't overflow target! */
268 if (Target
< PagesFreed
)
270 /* If we would have, jump to zero directly */
275 Target
-= PagesFreed
;
279 current_entry
= DirtyVacbListHead
.Flink
;
282 KeReleaseGuardedMutex(&ViewLock
);
283 KeLeaveCriticalRegion();
285 DPRINT("CcRosFlushDirtyPages() finished\n");
286 return STATUS_SUCCESS
;
295 * FUNCTION: Try to free some memory from the file cache.
297 * Target - The number of pages to be freed.
298 * Priority - The priority of free (currently unused).
299 * NrFreed - Points to a variable where the number of pages
300 * actually freed is returned.
303 PLIST_ENTRY current_entry
;
310 BOOLEAN FlushedPages
= FALSE
;
312 DPRINT("CcRosTrimCache(Target %lu)\n", Target
);
314 InitializeListHead(&FreeList
);
319 KeAcquireGuardedMutex(&ViewLock
);
321 current_entry
= VacbLruListHead
.Flink
;
322 while (current_entry
!= &VacbLruListHead
)
324 current
= CONTAINING_RECORD(current_entry
,
327 current_entry
= current_entry
->Flink
;
329 KeAcquireSpinLock(¤t
->SharedCacheMap
->CacheMapLock
, &oldIrql
);
331 /* Reference the VACB */
332 CcRosVacbIncRefCount(current
);
334 /* Check if it's mapped and not dirty */
335 if (current
->MappedCount
> 0 && !current
->Dirty
)
337 /* We have to break these locks because Cc sucks */
338 KeReleaseSpinLock(¤t
->SharedCacheMap
->CacheMapLock
, oldIrql
);
339 KeReleaseGuardedMutex(&ViewLock
);
341 /* Page out the VACB */
342 for (i
= 0; i
< VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
; i
++)
344 Page
= (PFN_NUMBER
)(MmGetPhysicalAddress((PUCHAR
)current
->BaseAddress
+ (i
* PAGE_SIZE
)).QuadPart
>> PAGE_SHIFT
);
346 MmPageOutPhysicalAddress(Page
);
349 /* Reacquire the locks */
350 KeAcquireGuardedMutex(&ViewLock
);
351 KeAcquireSpinLock(¤t
->SharedCacheMap
->CacheMapLock
, &oldIrql
);
354 /* Dereference the VACB */
355 CcRosVacbDecRefCount(current
);
357 /* Check if we can free this entry now */
358 if (current
->ReferenceCount
== 0)
360 ASSERT(!current
->Dirty
);
361 ASSERT(!current
->MappedCount
);
363 RemoveEntryList(¤t
->CacheMapVacbListEntry
);
364 RemoveEntryList(¤t
->VacbLruListEntry
);
365 InsertHeadList(&FreeList
, ¤t
->CacheMapVacbListEntry
);
367 /* Calculate how many pages we freed for Mm */
368 PagesFreed
= min(VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
, Target
);
369 Target
-= PagesFreed
;
370 (*NrFreed
) += PagesFreed
;
373 KeReleaseSpinLock(¤t
->SharedCacheMap
->CacheMapLock
, oldIrql
);
376 KeReleaseGuardedMutex(&ViewLock
);
378 /* Try flushing pages if we haven't met our target */
379 if ((Target
> 0) && !FlushedPages
)
381 /* Flush dirty pages to disk */
382 CcRosFlushDirtyPages(Target
, &PagesFreed
, FALSE
, FALSE
);
385 /* We can only swap as many pages as we flushed */
386 if (PagesFreed
< Target
) Target
= PagesFreed
;
388 /* Check if we flushed anything */
391 /* Try again after flushing dirty pages */
392 DPRINT("Flushed %lu dirty cache pages to disk\n", PagesFreed
);
397 while (!IsListEmpty(&FreeList
))
399 current_entry
= RemoveHeadList(&FreeList
);
400 current
= CONTAINING_RECORD(current_entry
,
402 CacheMapVacbListEntry
);
403 CcRosInternalFreeVacb(current
);
406 DPRINT("Evicted %lu cache pages\n", (*NrFreed
));
408 return STATUS_SUCCESS
;
414 PROS_SHARED_CACHE_MAP SharedCacheMap
,
420 ASSERT(SharedCacheMap
);
422 DPRINT("CcRosReleaseVacb(SharedCacheMap 0x%p, Vacb 0x%p, Valid %u)\n",
423 SharedCacheMap
, Vacb
, Valid
);
427 if (Dirty
&& !Vacb
->Dirty
)
429 CcRosMarkDirtyVacb(Vacb
);
436 CcRosVacbDecRefCount(Vacb
);
437 if (Mapped
&& (Vacb
->MappedCount
== 1))
439 CcRosVacbIncRefCount(Vacb
);
442 CcRosReleaseVacbLock(Vacb
);
444 return STATUS_SUCCESS
;
447 /* Returns with VACB Lock Held! */
451 PROS_SHARED_CACHE_MAP SharedCacheMap
,
454 PLIST_ENTRY current_entry
;
458 ASSERT(SharedCacheMap
);
460 DPRINT("CcRosLookupVacb(SharedCacheMap 0x%p, FileOffset %I64u)\n",
461 SharedCacheMap
, FileOffset
);
463 KeAcquireGuardedMutex(&ViewLock
);
464 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
466 current_entry
= SharedCacheMap
->CacheMapVacbListHead
.Flink
;
467 while (current_entry
!= &SharedCacheMap
->CacheMapVacbListHead
)
469 current
= CONTAINING_RECORD(current_entry
,
471 CacheMapVacbListEntry
);
472 if (IsPointInRange(current
->FileOffset
.QuadPart
,
473 VACB_MAPPING_GRANULARITY
,
476 CcRosVacbIncRefCount(current
);
477 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
478 KeReleaseGuardedMutex(&ViewLock
);
479 CcRosAcquireVacbLock(current
, NULL
);
482 if (current
->FileOffset
.QuadPart
> FileOffset
)
484 current_entry
= current_entry
->Flink
;
487 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
488 KeReleaseGuardedMutex(&ViewLock
);
499 PROS_SHARED_CACHE_MAP SharedCacheMap
;
501 SharedCacheMap
= Vacb
->SharedCacheMap
;
503 KeAcquireGuardedMutex(&ViewLock
);
504 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
506 ASSERT(!Vacb
->Dirty
);
508 InsertTailList(&DirtyVacbListHead
, &Vacb
->DirtyVacbListEntry
);
509 CcTotalDirtyPages
+= VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
;
510 Vacb
->SharedCacheMap
->DirtyPages
+= VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
;
511 CcRosVacbIncRefCount(Vacb
);
513 /* Move to the tail of the LRU list */
514 RemoveEntryList(&Vacb
->VacbLruListEntry
);
515 InsertTailList(&VacbLruListHead
, &Vacb
->VacbLruListEntry
);
519 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
520 KeReleaseGuardedMutex(&ViewLock
);
522 /* Schedule a lazy writer run to now that we have dirty VACB */
523 oldIrql
= KeAcquireQueuedSpinLock(LockQueueMasterLock
);
524 if (!LazyWriter
.ScanActive
)
526 CcScheduleLazyWriteScan(FALSE
);
528 KeReleaseQueuedSpinLock(LockQueueMasterLock
, oldIrql
);
533 CcRosUnmarkDirtyVacb (
538 PROS_SHARED_CACHE_MAP SharedCacheMap
;
540 SharedCacheMap
= Vacb
->SharedCacheMap
;
544 KeAcquireGuardedMutex(&ViewLock
);
545 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
552 RemoveEntryList(&Vacb
->DirtyVacbListEntry
);
553 CcTotalDirtyPages
-= VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
;
554 Vacb
->SharedCacheMap
->DirtyPages
-= VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
;
555 CcRosVacbDecRefCount(Vacb
);
559 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
560 KeReleaseGuardedMutex(&ViewLock
);
567 PROS_SHARED_CACHE_MAP SharedCacheMap
,
572 ASSERT(SharedCacheMap
);
574 DPRINT("CcRosMarkDirtyVacb(SharedCacheMap 0x%p, FileOffset %I64u)\n",
575 SharedCacheMap
, FileOffset
);
577 Vacb
= CcRosLookupVacb(SharedCacheMap
, FileOffset
);
580 KeBugCheck(CACHE_MANAGER
);
585 CcRosMarkDirtyVacb(Vacb
);
588 CcRosReleaseVacbLock(Vacb
);
590 return STATUS_SUCCESS
;
596 PROS_SHARED_CACHE_MAP SharedCacheMap
,
602 ASSERT(SharedCacheMap
);
604 DPRINT("CcRosUnmapVacb(SharedCacheMap 0x%p, FileOffset %I64u, NowDirty %u)\n",
605 SharedCacheMap
, FileOffset
, NowDirty
);
607 Vacb
= CcRosLookupVacb(SharedCacheMap
, FileOffset
);
610 return STATUS_UNSUCCESSFUL
;
613 if (NowDirty
&& !Vacb
->Dirty
)
615 CcRosMarkDirtyVacb(Vacb
);
618 ASSERT(Vacb
->MappedCount
!= 0);
621 CcRosVacbDecRefCount(Vacb
);
622 if (Vacb
->MappedCount
== 0)
624 CcRosVacbDecRefCount(Vacb
);
627 CcRosReleaseVacbLock(Vacb
);
629 return STATUS_SUCCESS
;
639 ULONG_PTR NumberOfPages
;
641 /* Create a memory area. */
642 MmLockAddressSpace(MmGetKernelAddressSpace());
643 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
644 0, // nothing checks for VACB mareas, so set to 0
646 VACB_MAPPING_GRANULARITY
,
648 (PMEMORY_AREA
*)&Vacb
->MemoryArea
,
651 MmUnlockAddressSpace(MmGetKernelAddressSpace());
652 if (!NT_SUCCESS(Status
))
654 DPRINT1("MmCreateMemoryArea failed with %lx for VACB %p\n", Status
, Vacb
);
658 ASSERT(((ULONG_PTR
)Vacb
->BaseAddress
% PAGE_SIZE
) == 0);
659 ASSERT((ULONG_PTR
)Vacb
->BaseAddress
> (ULONG_PTR
)MmSystemRangeStart
);
661 /* Create a virtual mapping for this memory area */
662 NumberOfPages
= BYTES_TO_PAGES(VACB_MAPPING_GRANULARITY
);
663 for (i
= 0; i
< NumberOfPages
; i
++)
665 PFN_NUMBER PageFrameNumber
;
667 MI_SET_USAGE(MI_USAGE_CACHE
);
668 Status
= MmRequestPageMemoryConsumer(MC_CACHE
, TRUE
, &PageFrameNumber
);
669 if (PageFrameNumber
== 0)
671 DPRINT1("Unable to allocate page\n");
672 KeBugCheck(MEMORY_MANAGEMENT
);
675 Status
= MmCreateVirtualMapping(NULL
,
676 (PVOID
)((ULONG_PTR
)Vacb
->BaseAddress
+ (i
* PAGE_SIZE
)),
680 if (!NT_SUCCESS(Status
))
682 DPRINT1("Unable to create virtual mapping\n");
683 KeBugCheck(MEMORY_MANAGEMENT
);
687 return STATUS_SUCCESS
;
693 PROS_SHARED_CACHE_MAP SharedCacheMap
,
699 PLIST_ENTRY current_entry
;
703 ASSERT(SharedCacheMap
);
705 DPRINT("CcRosCreateVacb()\n");
707 if (FileOffset
>= SharedCacheMap
->SectionSize
.QuadPart
)
710 return STATUS_INVALID_PARAMETER
;
713 current
= ExAllocateFromNPagedLookasideList(&VacbLookasideList
);
714 current
->BaseAddress
= NULL
;
715 current
->Valid
= FALSE
;
716 current
->Dirty
= FALSE
;
717 current
->PageOut
= FALSE
;
718 current
->FileOffset
.QuadPart
= ROUND_DOWN(FileOffset
, VACB_MAPPING_GRANULARITY
);
719 current
->SharedCacheMap
= SharedCacheMap
;
721 if (SharedCacheMap
->Trace
)
723 DPRINT1("CacheMap 0x%p: new VACB: 0x%p\n", SharedCacheMap
, current
);
726 current
->MappedCount
= 0;
727 current
->DirtyVacbListEntry
.Flink
= NULL
;
728 current
->DirtyVacbListEntry
.Blink
= NULL
;
729 current
->ReferenceCount
= 1;
730 current
->PinCount
= 0;
731 KeInitializeMutex(¤t
->Mutex
, 0);
732 CcRosAcquireVacbLock(current
, NULL
);
733 KeAcquireGuardedMutex(&ViewLock
);
736 /* There is window between the call to CcRosLookupVacb
737 * and CcRosCreateVacb. We must check if a VACB for the
738 * file offset exist. If there is a VACB, we release
739 * our newly created VACB and return the existing one.
741 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
742 current_entry
= SharedCacheMap
->CacheMapVacbListHead
.Flink
;
744 while (current_entry
!= &SharedCacheMap
->CacheMapVacbListHead
)
746 current
= CONTAINING_RECORD(current_entry
,
748 CacheMapVacbListEntry
);
749 if (IsPointInRange(current
->FileOffset
.QuadPart
,
750 VACB_MAPPING_GRANULARITY
,
753 CcRosVacbIncRefCount(current
);
754 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
756 if (SharedCacheMap
->Trace
)
758 DPRINT1("CacheMap 0x%p: deleting newly created VACB 0x%p ( found existing one 0x%p )\n",
764 CcRosReleaseVacbLock(*Vacb
);
765 KeReleaseGuardedMutex(&ViewLock
);
766 ExFreeToNPagedLookasideList(&VacbLookasideList
, *Vacb
);
768 CcRosAcquireVacbLock(current
, NULL
);
769 return STATUS_SUCCESS
;
771 if (current
->FileOffset
.QuadPart
< FileOffset
)
773 ASSERT(previous
== NULL
||
774 previous
->FileOffset
.QuadPart
< current
->FileOffset
.QuadPart
);
777 if (current
->FileOffset
.QuadPart
> FileOffset
)
779 current_entry
= current_entry
->Flink
;
781 /* There was no existing VACB. */
785 InsertHeadList(&previous
->CacheMapVacbListEntry
, ¤t
->CacheMapVacbListEntry
);
789 InsertHeadList(&SharedCacheMap
->CacheMapVacbListHead
, ¤t
->CacheMapVacbListEntry
);
791 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
792 InsertTailList(&VacbLruListHead
, ¤t
->VacbLruListEntry
);
793 KeReleaseGuardedMutex(&ViewLock
);
795 MI_SET_USAGE(MI_USAGE_CACHE
);
797 if ((SharedCacheMap
->FileObject
) && (SharedCacheMap
->FileObject
->FileName
.Buffer
))
801 pos
= wcsrchr(SharedCacheMap
->FileObject
->FileName
.Buffer
, '\\');
804 len
= wcslen(pos
) * sizeof(WCHAR
);
805 snprintf(MI_PFN_CURRENT_PROCESS_NAME
, min(16, len
), "%S", pos
);
809 snprintf(MI_PFN_CURRENT_PROCESS_NAME
, min(16, len
), "%wZ", &SharedCacheMap
->FileObject
->FileName
);
814 Status
= CcRosMapVacb(current
);
815 if (!NT_SUCCESS(Status
))
817 RemoveEntryList(¤t
->CacheMapVacbListEntry
);
818 RemoveEntryList(¤t
->VacbLruListEntry
);
819 CcRosReleaseVacbLock(current
);
820 ExFreeToNPagedLookasideList(&VacbLookasideList
, current
);
829 PROS_SHARED_CACHE_MAP SharedCacheMap
,
831 PLONGLONG BaseOffset
,
839 ASSERT(SharedCacheMap
);
841 DPRINT("CcRosGetVacb()\n");
844 * Look for a VACB already mapping the same data.
846 current
= CcRosLookupVacb(SharedCacheMap
, FileOffset
);
850 * Otherwise create a new VACB.
852 Status
= CcRosCreateVacb(SharedCacheMap
, FileOffset
, ¤t
);
853 if (!NT_SUCCESS(Status
))
859 KeAcquireGuardedMutex(&ViewLock
);
861 /* Move to the tail of the LRU list */
862 RemoveEntryList(¤t
->VacbLruListEntry
);
863 InsertTailList(&VacbLruListHead
, ¤t
->VacbLruListEntry
);
865 KeReleaseGuardedMutex(&ViewLock
);
868 * Return information about the VACB to the caller.
870 *UptoDate
= current
->Valid
;
871 *BaseAddress
= current
->BaseAddress
;
872 DPRINT("*BaseAddress %p\n", *BaseAddress
);
874 *BaseOffset
= current
->FileOffset
.QuadPart
;
875 return STATUS_SUCCESS
;
881 PROS_SHARED_CACHE_MAP SharedCacheMap
,
887 * FUNCTION: Request a page mapping for a shared cache map
892 ASSERT(SharedCacheMap
);
894 if (FileOffset
% VACB_MAPPING_GRANULARITY
!= 0)
896 DPRINT1("Bad fileoffset %I64x should be multiple of %x",
897 FileOffset
, VACB_MAPPING_GRANULARITY
);
898 KeBugCheck(CACHE_MANAGER
);
901 return CcRosGetVacb(SharedCacheMap
,
913 MEMORY_AREA
* MemoryArea
,
919 ASSERT(SwapEntry
== 0);
922 ASSERT(MmGetReferenceCountPage(Page
) == 1);
923 MmReleasePageMemoryConsumer(MC_CACHE
, Page
);
928 CcRosInternalFreeVacb (
931 * FUNCTION: Releases a VACB associated with a shared cache map
934 DPRINT("Freeing VACB 0x%p\n", Vacb
);
936 if (Vacb
->SharedCacheMap
->Trace
)
938 DPRINT1("CacheMap 0x%p: deleting VACB: 0x%p\n", Vacb
->SharedCacheMap
, Vacb
);
942 MmLockAddressSpace(MmGetKernelAddressSpace());
943 MmFreeMemoryArea(MmGetKernelAddressSpace(),
947 MmUnlockAddressSpace(MmGetKernelAddressSpace());
949 ExFreeToNPagedLookasideList(&VacbLookasideList
, Vacb
);
950 return STATUS_SUCCESS
;
959 IN PSECTION_OBJECT_POINTERS SectionObjectPointers
,
960 IN PLARGE_INTEGER FileOffset OPTIONAL
,
962 OUT PIO_STATUS_BLOCK IoStatus
)
964 PROS_SHARED_CACHE_MAP SharedCacheMap
;
965 LARGE_INTEGER Offset
;
966 LONGLONG RemainingLength
;
971 CCTRACE(CC_API_DEBUG
, "SectionObjectPointers=%p FileOffset=%p Length=%lu\n",
972 SectionObjectPointers
, FileOffset
, Length
);
974 DPRINT("CcFlushCache(SectionObjectPointers 0x%p, FileOffset 0x%p, Length %lu, IoStatus 0x%p)\n",
975 SectionObjectPointers
, FileOffset
, Length
, IoStatus
);
977 if (SectionObjectPointers
&& SectionObjectPointers
->SharedCacheMap
)
979 SharedCacheMap
= SectionObjectPointers
->SharedCacheMap
;
980 ASSERT(SharedCacheMap
);
983 Offset
= *FileOffset
;
984 RemainingLength
= Length
;
989 RemainingLength
= SharedCacheMap
->FileSize
.QuadPart
;
994 IoStatus
->Status
= STATUS_SUCCESS
;
995 IoStatus
->Information
= 0;
998 while (RemainingLength
> 0)
1000 current
= CcRosLookupVacb(SharedCacheMap
, Offset
.QuadPart
);
1001 if (current
!= NULL
)
1005 Status
= CcRosFlushVacb(current
);
1006 if (!NT_SUCCESS(Status
) && IoStatus
!= NULL
)
1008 IoStatus
->Status
= Status
;
1012 CcRosReleaseVacbLock(current
);
1014 KeAcquireGuardedMutex(&ViewLock
);
1015 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
1016 CcRosVacbDecRefCount(current
);
1017 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
1018 KeReleaseGuardedMutex(&ViewLock
);
1021 Offset
.QuadPart
+= VACB_MAPPING_GRANULARITY
;
1022 RemainingLength
-= min(RemainingLength
, VACB_MAPPING_GRANULARITY
);
1029 IoStatus
->Status
= STATUS_INVALID_PARAMETER
;
1036 CcRosDeleteFileCache (
1037 PFILE_OBJECT FileObject
,
1038 PROS_SHARED_CACHE_MAP SharedCacheMap
)
1040 * FUNCTION: Releases the shared cache map associated with a file object
1043 PLIST_ENTRY current_entry
;
1045 LIST_ENTRY FreeList
;
1048 ASSERT(SharedCacheMap
);
1050 SharedCacheMap
->OpenCount
++;
1051 KeReleaseGuardedMutex(&ViewLock
);
1053 CcFlushCache(FileObject
->SectionObjectPointer
, NULL
, 0, NULL
);
1055 KeAcquireGuardedMutex(&ViewLock
);
1056 SharedCacheMap
->OpenCount
--;
1057 if (SharedCacheMap
->OpenCount
== 0)
1061 FileObject
->SectionObjectPointer
->SharedCacheMap
= NULL
;
1066 InitializeListHead(&FreeList
);
1067 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
1068 while (!IsListEmpty(&SharedCacheMap
->CacheMapVacbListHead
))
1070 current_entry
= RemoveTailList(&SharedCacheMap
->CacheMapVacbListHead
);
1071 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
1073 current
= CONTAINING_RECORD(current_entry
, ROS_VACB
, CacheMapVacbListEntry
);
1074 CcRosAcquireVacbLock(current
, NULL
);
1075 RemoveEntryList(¤t
->VacbLruListEntry
);
1078 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
1079 CcRosUnmarkDirtyVacb(current
, FALSE
);
1080 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
1081 DPRINT1("Freeing dirty VACB\n");
1083 InsertHeadList(&FreeList
, ¤t
->CacheMapVacbListEntry
);
1084 CcRosReleaseVacbLock(current
);
1086 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
1089 SharedCacheMap
->Trace
= FALSE
;
1091 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
1093 KeReleaseGuardedMutex(&ViewLock
);
1094 ObDereferenceObject(SharedCacheMap
->FileObject
);
1096 while (!IsListEmpty(&FreeList
))
1098 current_entry
= RemoveTailList(&FreeList
);
1099 current
= CONTAINING_RECORD(current_entry
, ROS_VACB
, CacheMapVacbListEntry
);
1100 CcRosInternalFreeVacb(current
);
1103 KeAcquireSpinLock(&iSharedCacheMapLock
, &OldIrql
);
1104 RemoveEntryList(&SharedCacheMap
->SharedCacheMapLinks
);
1105 KeReleaseSpinLock(&iSharedCacheMapLock
, OldIrql
);
1107 ExFreeToNPagedLookasideList(&SharedCacheMapLookasideList
, SharedCacheMap
);
1108 KeAcquireGuardedMutex(&ViewLock
);
1110 return STATUS_SUCCESS
;
1115 CcRosReferenceCache (
1116 PFILE_OBJECT FileObject
)
1118 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1119 KeAcquireGuardedMutex(&ViewLock
);
1120 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1121 ASSERT(SharedCacheMap
);
1122 ASSERT(SharedCacheMap
->OpenCount
!= 0);
1123 SharedCacheMap
->OpenCount
++;
1124 KeReleaseGuardedMutex(&ViewLock
);
1129 CcRosRemoveIfClosed (
1130 PSECTION_OBJECT_POINTERS SectionObjectPointer
)
1132 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1133 DPRINT("CcRosRemoveIfClosed()\n");
1134 KeAcquireGuardedMutex(&ViewLock
);
1135 SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
1136 if (SharedCacheMap
&& SharedCacheMap
->OpenCount
== 0)
1138 CcRosDeleteFileCache(SharedCacheMap
->FileObject
, SharedCacheMap
);
1140 KeReleaseGuardedMutex(&ViewLock
);
1146 CcRosDereferenceCache (
1147 PFILE_OBJECT FileObject
)
1149 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1150 KeAcquireGuardedMutex(&ViewLock
);
1151 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1152 ASSERT(SharedCacheMap
);
1153 if (SharedCacheMap
->OpenCount
> 0)
1155 SharedCacheMap
->OpenCount
--;
1156 if (SharedCacheMap
->OpenCount
== 0)
1158 MmFreeSectionSegments(SharedCacheMap
->FileObject
);
1159 CcRosDeleteFileCache(FileObject
, SharedCacheMap
);
1162 KeReleaseGuardedMutex(&ViewLock
);
1167 CcRosReleaseFileCache (
1168 PFILE_OBJECT FileObject
)
1170 * FUNCTION: Called by the file system when a handle to a file object
1174 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1176 KeAcquireGuardedMutex(&ViewLock
);
1178 if (FileObject
->SectionObjectPointer
->SharedCacheMap
!= NULL
)
1180 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1181 if (FileObject
->PrivateCacheMap
!= NULL
)
1184 PPRIVATE_CACHE_MAP PrivateMap
;
1186 /* Closing the handle, so kill the private cache map */
1187 PrivateMap
= FileObject
->PrivateCacheMap
;
1189 /* Remove it from the file */
1190 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &OldIrql
);
1191 RemoveEntryList(&PrivateMap
->PrivateLinks
);
1192 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, OldIrql
);
1195 * Before you event try to remove it from FO, always
1196 * lock the master lock, to be sure not to race
1197 * with a potential read ahead ongoing!
1199 OldIrql
= KeAcquireQueuedSpinLock(LockQueueMasterLock
);
1200 FileObject
->PrivateCacheMap
= NULL
;
1201 KeReleaseQueuedSpinLock(LockQueueMasterLock
, OldIrql
);
1202 ExFreePoolWithTag(PrivateMap
, TAG_PRIVATE_CACHE_MAP
);
1204 if (SharedCacheMap
->OpenCount
> 0)
1206 SharedCacheMap
->OpenCount
--;
1207 if (SharedCacheMap
->OpenCount
== 0)
1209 MmFreeSectionSegments(SharedCacheMap
->FileObject
);
1210 CcRosDeleteFileCache(FileObject
, SharedCacheMap
);
1215 KeReleaseGuardedMutex(&ViewLock
);
1216 return STATUS_SUCCESS
;
1221 CcRosInitializeFileCache (
1222 PFILE_OBJECT FileObject
,
1223 PCC_FILE_SIZES FileSizes
,
1225 PCACHE_MANAGER_CALLBACKS CallBacks
,
1226 PVOID LazyWriterContext
)
1228 * FUNCTION: Initializes a shared cache map for a file object
1233 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1235 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1236 DPRINT("CcRosInitializeFileCache(FileObject 0x%p, SharedCacheMap 0x%p)\n",
1237 FileObject
, SharedCacheMap
);
1240 KeAcquireGuardedMutex(&ViewLock
);
1241 if (SharedCacheMap
== NULL
)
1244 SharedCacheMap
= ExAllocateFromNPagedLookasideList(&SharedCacheMapLookasideList
);
1245 if (SharedCacheMap
== NULL
)
1247 KeReleaseGuardedMutex(&ViewLock
);
1248 return STATUS_INSUFFICIENT_RESOURCES
;
1250 RtlZeroMemory(SharedCacheMap
, sizeof(*SharedCacheMap
));
1251 ObReferenceObjectByPointer(FileObject
,
1255 SharedCacheMap
->NodeTypeCode
= NODE_TYPE_SHARED_MAP
;
1256 SharedCacheMap
->NodeByteSize
= sizeof(*SharedCacheMap
);
1257 SharedCacheMap
->FileObject
= FileObject
;
1258 SharedCacheMap
->Callbacks
= CallBacks
;
1259 SharedCacheMap
->LazyWriteContext
= LazyWriterContext
;
1260 SharedCacheMap
->SectionSize
= FileSizes
->AllocationSize
;
1261 SharedCacheMap
->FileSize
= FileSizes
->FileSize
;
1262 SharedCacheMap
->PinAccess
= PinAccess
;
1263 SharedCacheMap
->DirtyPageThreshold
= 0;
1264 SharedCacheMap
->DirtyPages
= 0;
1265 InitializeListHead(&SharedCacheMap
->PrivateList
);
1266 KeInitializeSpinLock(&SharedCacheMap
->CacheMapLock
);
1267 InitializeListHead(&SharedCacheMap
->CacheMapVacbListHead
);
1268 FileObject
->SectionObjectPointer
->SharedCacheMap
= SharedCacheMap
;
1270 KeAcquireSpinLock(&iSharedCacheMapLock
, &OldIrql
);
1271 InsertTailList(&CcCleanSharedCacheMapList
, &SharedCacheMap
->SharedCacheMapLinks
);
1272 KeReleaseSpinLock(&iSharedCacheMapLock
, OldIrql
);
1274 if (FileObject
->PrivateCacheMap
== NULL
)
1276 PPRIVATE_CACHE_MAP PrivateMap
;
1278 /* Allocate the private cache map for this handle */
1279 PrivateMap
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(PRIVATE_CACHE_MAP
), TAG_PRIVATE_CACHE_MAP
);
1280 if (PrivateMap
== NULL
)
1282 /* If we also allocated the shared cache map for this file, kill it */
1285 KeAcquireSpinLock(&iSharedCacheMapLock
, &OldIrql
);
1286 RemoveEntryList(&SharedCacheMap
->SharedCacheMapLinks
);
1287 KeReleaseSpinLock(&iSharedCacheMapLock
, OldIrql
);
1289 FileObject
->SectionObjectPointer
->SharedCacheMap
= NULL
;
1290 ObDereferenceObject(FileObject
);
1291 ExFreeToNPagedLookasideList(&SharedCacheMapLookasideList
, SharedCacheMap
);
1294 KeReleaseGuardedMutex(&ViewLock
);
1295 return STATUS_INSUFFICIENT_RESOURCES
;
1299 RtlZeroMemory(PrivateMap
, sizeof(PRIVATE_CACHE_MAP
));
1300 PrivateMap
->NodeTypeCode
= NODE_TYPE_PRIVATE_MAP
;
1301 PrivateMap
->ReadAheadMask
= PAGE_SIZE
- 1;
1302 PrivateMap
->FileObject
= FileObject
;
1303 KeInitializeSpinLock(&PrivateMap
->ReadAheadSpinLock
);
1305 /* Link it to the file */
1306 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &OldIrql
);
1307 InsertTailList(&SharedCacheMap
->PrivateList
, &PrivateMap
->PrivateLinks
);
1308 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, OldIrql
);
1310 FileObject
->PrivateCacheMap
= PrivateMap
;
1311 SharedCacheMap
->OpenCount
++;
1313 KeReleaseGuardedMutex(&ViewLock
);
1315 return STATUS_SUCCESS
;
1323 CcGetFileObjectFromSectionPtrs (
1324 IN PSECTION_OBJECT_POINTERS SectionObjectPointers
)
1326 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1328 CCTRACE(CC_API_DEBUG
, "SectionObjectPointers=%p\n", SectionObjectPointers
);
1330 if (SectionObjectPointers
&& SectionObjectPointers
->SharedCacheMap
)
1332 SharedCacheMap
= SectionObjectPointers
->SharedCacheMap
;
1333 ASSERT(SharedCacheMap
);
1334 return SharedCacheMap
->FileObject
;
1345 DPRINT("CcInitView()\n");
1347 InitializeListHead(&DirtyVacbListHead
);
1348 InitializeListHead(&VacbLruListHead
);
1349 InitializeListHead(&CcDeferredWrites
);
1350 InitializeListHead(&CcCleanSharedCacheMapList
);
1351 KeInitializeSpinLock(&CcDeferredWriteSpinLock
);
1352 KeInitializeSpinLock(&iSharedCacheMapLock
);
1353 KeInitializeGuardedMutex(&ViewLock
);
1354 ExInitializeNPagedLookasideList(&iBcbLookasideList
,
1358 sizeof(INTERNAL_BCB
),
1361 ExInitializeNPagedLookasideList(&SharedCacheMapLookasideList
,
1365 sizeof(ROS_SHARED_CACHE_MAP
),
1366 TAG_SHARED_CACHE_MAP
,
1368 ExInitializeNPagedLookasideList(&VacbLookasideList
,
1376 MmInitializeMemoryConsumer(MC_CACHE
, CcRosTrimCache
);
1378 CcInitCacheZeroPage();
1381 #if DBG && defined(KDBG)
1383 ExpKdbgExtFileCache(ULONG Argc
, PCHAR Argv
[])
1385 PLIST_ENTRY ListEntry
;
1386 UNICODE_STRING NoName
= RTL_CONSTANT_STRING(L
"No name for File");
1388 KdbpPrint(" Usage Summary (in kb)\n");
1389 KdbpPrint("Shared\t\tValid\tDirty\tName\n");
1390 /* No need to lock the spin lock here, we're in DBG */
1391 for (ListEntry
= CcCleanSharedCacheMapList
.Flink
;
1392 ListEntry
!= &CcCleanSharedCacheMapList
;
1393 ListEntry
= ListEntry
->Flink
)
1396 ULONG Valid
= 0, Dirty
= 0;
1397 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1398 PUNICODE_STRING FileName
;
1400 SharedCacheMap
= CONTAINING_RECORD(ListEntry
, ROS_SHARED_CACHE_MAP
, SharedCacheMapLinks
);
1403 Dirty
= (SharedCacheMap
->DirtyPages
* PAGE_SIZE
) / 1024;
1405 /* First, count for all the associated VACB */
1406 for (Vacbs
= SharedCacheMap
->CacheMapVacbListHead
.Flink
;
1407 Vacbs
!= &SharedCacheMap
->CacheMapVacbListHead
;
1408 Vacbs
= Vacbs
->Flink
)
1412 Vacb
= CONTAINING_RECORD(Vacbs
, ROS_VACB
, CacheMapVacbListEntry
);
1415 Valid
+= VACB_MAPPING_GRANULARITY
/ 1024;
1420 if (SharedCacheMap
->FileObject
!= NULL
&&
1421 SharedCacheMap
->FileObject
->FileName
.Length
!= 0)
1423 FileName
= &SharedCacheMap
->FileObject
->FileName
;
1431 KdbpPrint("%p\t%d\t%d\t%wZ\n", SharedCacheMap
, Valid
, Dirty
, FileName
);