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
;
68 ULONG
CcRosVacbIncRefCount_(PROS_VACB vacb
, PCSTR file
, INT line
)
72 Refs
= InterlockedIncrement((PLONG
)&vacb
->ReferenceCount
);
73 if (vacb
->SharedCacheMap
->Trace
)
75 DbgPrint("(%s:%i) VACB %p ++RefCount=%lu, Dirty %u, PageOut %lu\n",
76 file
, line
, vacb
, Refs
, vacb
->Dirty
, vacb
->PageOut
);
81 ULONG
CcRosVacbDecRefCount_(PROS_VACB vacb
, PCSTR file
, INT line
)
85 Refs
= InterlockedDecrement((PLONG
)&vacb
->ReferenceCount
);
86 ASSERT(!(Refs
== 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
, Refs
, vacb
->Dirty
, vacb
->PageOut
);
95 CcRosInternalFreeVacb(vacb
);
100 ULONG
CcRosVacbGetRefCount_(PROS_VACB vacb
, PCSTR file
, INT line
)
104 Refs
= InterlockedCompareExchange((PLONG
)&vacb
->ReferenceCount
, 0, 0);
105 if (vacb
->SharedCacheMap
->Trace
)
107 DbgPrint("(%s:%i) VACB %p ==RefCount=%lu, Dirty %u, PageOut %lu\n",
108 file
, line
, vacb
, Refs
, vacb
->Dirty
, vacb
->PageOut
);
116 /* FUNCTIONS *****************************************************************/
121 PROS_SHARED_CACHE_MAP SharedCacheMap
,
126 PLIST_ENTRY current_entry
;
132 SharedCacheMap
->Trace
= Trace
;
136 DPRINT1("Enabling Tracing for CacheMap 0x%p:\n", SharedCacheMap
);
138 KeAcquireGuardedMutex(&ViewLock
);
139 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldirql
);
141 current_entry
= SharedCacheMap
->CacheMapVacbListHead
.Flink
;
142 while (current_entry
!= &SharedCacheMap
->CacheMapVacbListHead
)
144 current
= CONTAINING_RECORD(current_entry
, ROS_VACB
, CacheMapVacbListEntry
);
145 current_entry
= current_entry
->Flink
;
147 DPRINT1(" VACB 0x%p enabled, RefCount %lu, Dirty %u, PageOut %lu\n",
148 current
, current
->ReferenceCount
, current
->Dirty
, current
->PageOut
);
150 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldirql
);
151 KeReleaseGuardedMutex(&ViewLock
);
155 DPRINT1("Disabling Tracing for CacheMap 0x%p:\n", SharedCacheMap
);
159 UNREFERENCED_PARAMETER(SharedCacheMap
);
160 UNREFERENCED_PARAMETER(Trace
);
171 Status
= CcWriteVirtualAddress(Vacb
);
172 if (NT_SUCCESS(Status
))
174 CcRosUnmarkDirtyVacb(Vacb
, TRUE
);
182 CcRosFlushDirtyPages (
186 BOOLEAN CalledFromLazy
)
188 PLIST_ENTRY current_entry
;
193 DPRINT("CcRosFlushDirtyPages(Target %lu)\n", Target
);
197 KeEnterCriticalRegion();
198 KeAcquireGuardedMutex(&ViewLock
);
200 current_entry
= DirtyVacbListHead
.Flink
;
201 if (current_entry
== &DirtyVacbListHead
)
203 DPRINT("No Dirty pages\n");
206 while ((current_entry
!= &DirtyVacbListHead
) && (Target
> 0))
208 current
= CONTAINING_RECORD(current_entry
,
211 current_entry
= current_entry
->Flink
;
213 CcRosVacbIncRefCount(current
);
215 /* When performing lazy write, don't handle temporary files */
216 if (CalledFromLazy
&&
217 BooleanFlagOn(current
->SharedCacheMap
->FileObject
->Flags
, FO_TEMPORARY_FILE
))
219 CcRosVacbDecRefCount(current
);
223 Locked
= current
->SharedCacheMap
->Callbacks
->AcquireForLazyWrite(
224 current
->SharedCacheMap
->LazyWriteContext
, Wait
);
227 CcRosVacbDecRefCount(current
);
231 ASSERT(current
->Dirty
);
233 /* One reference is added above */
234 if (CcRosVacbGetRefCount(current
) > 2)
236 current
->SharedCacheMap
->Callbacks
->ReleaseFromLazyWrite(
237 current
->SharedCacheMap
->LazyWriteContext
);
238 CcRosVacbDecRefCount(current
);
242 KeReleaseGuardedMutex(&ViewLock
);
244 Status
= CcRosFlushVacb(current
);
246 current
->SharedCacheMap
->Callbacks
->ReleaseFromLazyWrite(
247 current
->SharedCacheMap
->LazyWriteContext
);
249 KeAcquireGuardedMutex(&ViewLock
);
250 CcRosVacbDecRefCount(current
);
252 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
) &&
253 (Status
!= STATUS_MEDIA_WRITE_PROTECTED
))
255 DPRINT1("CC: Failed to flush VACB.\n");
261 /* How many pages did we free? */
262 PagesFreed
= VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
;
263 (*Count
) += PagesFreed
;
265 /* Make sure we don't overflow target! */
266 if (Target
< PagesFreed
)
268 /* If we would have, jump to zero directly */
273 Target
-= PagesFreed
;
277 current_entry
= DirtyVacbListHead
.Flink
;
280 KeReleaseGuardedMutex(&ViewLock
);
281 KeLeaveCriticalRegion();
283 DPRINT("CcRosFlushDirtyPages() finished\n");
284 return STATUS_SUCCESS
;
293 * FUNCTION: Try to free some memory from the file cache.
295 * Target - The number of pages to be freed.
296 * Priority - The priority of free (currently unused).
297 * NrFreed - Points to a variable where the number of pages
298 * actually freed is returned.
301 PLIST_ENTRY current_entry
;
308 BOOLEAN FlushedPages
= FALSE
;
310 DPRINT("CcRosTrimCache(Target %lu)\n", Target
);
312 InitializeListHead(&FreeList
);
317 KeAcquireGuardedMutex(&ViewLock
);
319 current_entry
= VacbLruListHead
.Flink
;
320 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 (InterlockedCompareExchange((PLONG
)¤t
->MappedCount
, 0, 0) > 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 Refs
= CcRosVacbDecRefCount(current
);
357 /* Check if we can free this entry now */
360 ASSERT(!current
->Dirty
);
361 ASSERT(!current
->MappedCount
);
364 RemoveEntryList(¤t
->CacheMapVacbListEntry
);
365 RemoveEntryList(¤t
->VacbLruListEntry
);
366 InitializeListHead(¤t
->VacbLruListEntry
);
367 InsertHeadList(&FreeList
, ¤t
->CacheMapVacbListEntry
);
369 /* Calculate how many pages we freed for Mm */
370 PagesFreed
= min(VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
, Target
);
371 Target
-= PagesFreed
;
372 (*NrFreed
) += PagesFreed
;
375 KeReleaseSpinLock(¤t
->SharedCacheMap
->CacheMapLock
, oldIrql
);
378 KeReleaseGuardedMutex(&ViewLock
);
380 /* Try flushing pages if we haven't met our target */
381 if ((Target
> 0) && !FlushedPages
)
383 /* Flush dirty pages to disk */
384 CcRosFlushDirtyPages(Target
, &PagesFreed
, FALSE
, FALSE
);
387 /* We can only swap as many pages as we flushed */
388 if (PagesFreed
< Target
) Target
= PagesFreed
;
390 /* Check if we flushed anything */
393 /* Try again after flushing dirty pages */
394 DPRINT("Flushed %lu dirty cache pages to disk\n", PagesFreed
);
399 while (!IsListEmpty(&FreeList
))
403 current_entry
= RemoveHeadList(&FreeList
);
404 current
= CONTAINING_RECORD(current_entry
,
406 CacheMapVacbListEntry
);
407 InitializeListHead(¤t
->CacheMapVacbListEntry
);
408 Refs
= CcRosVacbDecRefCount(current
);
412 DPRINT("Evicted %lu cache pages\n", (*NrFreed
));
414 return STATUS_SUCCESS
;
420 PROS_SHARED_CACHE_MAP SharedCacheMap
,
427 ASSERT(SharedCacheMap
);
429 DPRINT("CcRosReleaseVacb(SharedCacheMap 0x%p, Vacb 0x%p, Valid %u)\n",
430 SharedCacheMap
, Vacb
, Valid
);
434 if (Dirty
&& !Vacb
->Dirty
)
436 CcRosMarkDirtyVacb(Vacb
);
441 if (InterlockedIncrement((PLONG
)&Vacb
->MappedCount
) == 1)
443 CcRosVacbIncRefCount(Vacb
);
447 Refs
= CcRosVacbDecRefCount(Vacb
);
450 return STATUS_SUCCESS
;
453 /* Returns with VACB Lock Held! */
457 PROS_SHARED_CACHE_MAP SharedCacheMap
,
460 PLIST_ENTRY current_entry
;
464 ASSERT(SharedCacheMap
);
466 DPRINT("CcRosLookupVacb(SharedCacheMap 0x%p, FileOffset %I64u)\n",
467 SharedCacheMap
, FileOffset
);
469 KeAcquireGuardedMutex(&ViewLock
);
470 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
472 current_entry
= SharedCacheMap
->CacheMapVacbListHead
.Flink
;
473 while (current_entry
!= &SharedCacheMap
->CacheMapVacbListHead
)
475 current
= CONTAINING_RECORD(current_entry
,
477 CacheMapVacbListEntry
);
478 if (IsPointInRange(current
->FileOffset
.QuadPart
,
479 VACB_MAPPING_GRANULARITY
,
482 CcRosVacbIncRefCount(current
);
483 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
484 KeReleaseGuardedMutex(&ViewLock
);
487 if (current
->FileOffset
.QuadPart
> FileOffset
)
489 current_entry
= current_entry
->Flink
;
492 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
493 KeReleaseGuardedMutex(&ViewLock
);
504 PROS_SHARED_CACHE_MAP SharedCacheMap
;
506 SharedCacheMap
= Vacb
->SharedCacheMap
;
508 KeAcquireGuardedMutex(&ViewLock
);
509 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
511 ASSERT(!Vacb
->Dirty
);
513 InsertTailList(&DirtyVacbListHead
, &Vacb
->DirtyVacbListEntry
);
514 CcTotalDirtyPages
+= VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
;
515 Vacb
->SharedCacheMap
->DirtyPages
+= VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
;
516 CcRosVacbIncRefCount(Vacb
);
518 /* Move to the tail of the LRU list */
519 RemoveEntryList(&Vacb
->VacbLruListEntry
);
520 InsertTailList(&VacbLruListHead
, &Vacb
->VacbLruListEntry
);
524 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
525 KeReleaseGuardedMutex(&ViewLock
);
527 /* Schedule a lazy writer run to now that we have dirty VACB */
528 oldIrql
= KeAcquireQueuedSpinLock(LockQueueMasterLock
);
529 if (!LazyWriter
.ScanActive
)
531 CcScheduleLazyWriteScan(FALSE
);
533 KeReleaseQueuedSpinLock(LockQueueMasterLock
, oldIrql
);
538 CcRosUnmarkDirtyVacb (
543 PROS_SHARED_CACHE_MAP SharedCacheMap
;
545 SharedCacheMap
= Vacb
->SharedCacheMap
;
549 KeAcquireGuardedMutex(&ViewLock
);
550 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
557 RemoveEntryList(&Vacb
->DirtyVacbListEntry
);
558 InitializeListHead(&Vacb
->DirtyVacbListEntry
);
559 CcTotalDirtyPages
-= VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
;
560 Vacb
->SharedCacheMap
->DirtyPages
-= VACB_MAPPING_GRANULARITY
/ PAGE_SIZE
;
561 CcRosVacbDecRefCount(Vacb
);
565 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
566 KeReleaseGuardedMutex(&ViewLock
);
573 PROS_SHARED_CACHE_MAP SharedCacheMap
,
578 ASSERT(SharedCacheMap
);
580 DPRINT("CcRosMarkDirtyVacb(SharedCacheMap 0x%p, FileOffset %I64u)\n",
581 SharedCacheMap
, FileOffset
);
583 Vacb
= CcRosLookupVacb(SharedCacheMap
, FileOffset
);
586 KeBugCheck(CACHE_MANAGER
);
589 CcRosReleaseVacb(SharedCacheMap
, Vacb
, Vacb
->Valid
, TRUE
, FALSE
);
591 return STATUS_SUCCESS
;
595 * Note: this is not the contrary function of
596 * CcRosMapVacbInKernelSpace()
601 PROS_SHARED_CACHE_MAP SharedCacheMap
,
607 ASSERT(SharedCacheMap
);
609 DPRINT("CcRosUnmapVacb(SharedCacheMap 0x%p, FileOffset %I64u, NowDirty %u)\n",
610 SharedCacheMap
, FileOffset
, NowDirty
);
612 Vacb
= CcRosLookupVacb(SharedCacheMap
, FileOffset
);
615 return STATUS_UNSUCCESSFUL
;
618 ASSERT(Vacb
->MappedCount
!= 0);
619 if (InterlockedDecrement((PLONG
)&Vacb
->MappedCount
) == 0)
621 CcRosVacbDecRefCount(Vacb
);
624 CcRosReleaseVacb(SharedCacheMap
, Vacb
, Vacb
->Valid
, NowDirty
, FALSE
);
626 return STATUS_SUCCESS
;
631 CcRosMapVacbInKernelSpace(
636 ULONG_PTR NumberOfPages
;
637 PVOID BaseAddress
= NULL
;
639 /* Create a memory area. */
640 MmLockAddressSpace(MmGetKernelAddressSpace());
641 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
642 0, // nothing checks for VACB mareas, so set to 0
644 VACB_MAPPING_GRANULARITY
,
646 (PMEMORY_AREA
*)&Vacb
->MemoryArea
,
649 ASSERT(Vacb
->BaseAddress
== NULL
);
650 Vacb
->BaseAddress
= BaseAddress
;
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
);
660 ASSERT((ULONG_PTR
)Vacb
->BaseAddress
+ VACB_MAPPING_GRANULARITY
- 1 > (ULONG_PTR
)MmSystemRangeStart
);
662 /* Create a virtual mapping for this memory area */
663 NumberOfPages
= BYTES_TO_PAGES(VACB_MAPPING_GRANULARITY
);
664 for (i
= 0; i
< NumberOfPages
; i
++)
666 PFN_NUMBER PageFrameNumber
;
668 MI_SET_USAGE(MI_USAGE_CACHE
);
669 Status
= MmRequestPageMemoryConsumer(MC_CACHE
, TRUE
, &PageFrameNumber
);
670 if (PageFrameNumber
== 0)
672 DPRINT1("Unable to allocate page\n");
673 KeBugCheck(MEMORY_MANAGEMENT
);
676 ASSERT(BaseAddress
== Vacb
->BaseAddress
);
677 ASSERT(i
* PAGE_SIZE
< VACB_MAPPING_GRANULARITY
);
678 ASSERT((ULONG_PTR
)Vacb
->BaseAddress
+ (i
* PAGE_SIZE
) >= (ULONG_PTR
)BaseAddress
);
679 ASSERT((ULONG_PTR
)Vacb
->BaseAddress
+ (i
* PAGE_SIZE
) > (ULONG_PTR
)MmSystemRangeStart
);
681 Status
= MmCreateVirtualMapping(NULL
,
682 (PVOID
)((ULONG_PTR
)Vacb
->BaseAddress
+ (i
* PAGE_SIZE
)),
686 if (!NT_SUCCESS(Status
))
688 DPRINT1("Unable to create virtual mapping\n");
689 KeBugCheck(MEMORY_MANAGEMENT
);
693 return STATUS_SUCCESS
;
699 PROS_SHARED_CACHE_MAP SharedCacheMap
,
705 PLIST_ENTRY current_entry
;
710 ASSERT(SharedCacheMap
);
712 DPRINT("CcRosCreateVacb()\n");
714 if (FileOffset
>= SharedCacheMap
->SectionSize
.QuadPart
)
717 return STATUS_INVALID_PARAMETER
;
720 current
= ExAllocateFromNPagedLookasideList(&VacbLookasideList
);
721 current
->BaseAddress
= NULL
;
722 current
->Valid
= FALSE
;
723 current
->Dirty
= FALSE
;
724 current
->PageOut
= FALSE
;
725 current
->FileOffset
.QuadPart
= ROUND_DOWN(FileOffset
, VACB_MAPPING_GRANULARITY
);
726 current
->SharedCacheMap
= SharedCacheMap
;
728 if (SharedCacheMap
->Trace
)
730 DPRINT1("CacheMap 0x%p: new VACB: 0x%p\n", SharedCacheMap
, current
);
733 current
->MappedCount
= 0;
734 current
->ReferenceCount
= 0;
735 current
->PinCount
= 0;
736 InitializeListHead(¤t
->CacheMapVacbListEntry
);
737 InitializeListHead(¤t
->DirtyVacbListEntry
);
738 InitializeListHead(¤t
->VacbLruListEntry
);
740 CcRosVacbIncRefCount(current
);
742 Status
= CcRosMapVacbInKernelSpace(current
);
743 if (!NT_SUCCESS(Status
))
745 CcRosVacbDecRefCount(current
);
746 ExFreeToNPagedLookasideList(&VacbLookasideList
, current
);
750 KeAcquireGuardedMutex(&ViewLock
);
753 /* There is window between the call to CcRosLookupVacb
754 * and CcRosCreateVacb. We must check if a VACB for the
755 * file offset exist. If there is a VACB, we release
756 * our newly created VACB and return the existing one.
758 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
759 current_entry
= SharedCacheMap
->CacheMapVacbListHead
.Flink
;
761 while (current_entry
!= &SharedCacheMap
->CacheMapVacbListHead
)
763 current
= CONTAINING_RECORD(current_entry
,
765 CacheMapVacbListEntry
);
766 if (IsPointInRange(current
->FileOffset
.QuadPart
,
767 VACB_MAPPING_GRANULARITY
,
770 CcRosVacbIncRefCount(current
);
771 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
773 if (SharedCacheMap
->Trace
)
775 DPRINT1("CacheMap 0x%p: deleting newly created VACB 0x%p ( found existing one 0x%p )\n",
781 KeReleaseGuardedMutex(&ViewLock
);
783 Refs
= CcRosVacbDecRefCount(*Vacb
);
787 return STATUS_SUCCESS
;
789 if (current
->FileOffset
.QuadPart
< FileOffset
)
791 ASSERT(previous
== NULL
||
792 previous
->FileOffset
.QuadPart
< current
->FileOffset
.QuadPart
);
795 if (current
->FileOffset
.QuadPart
> FileOffset
)
797 current_entry
= current_entry
->Flink
;
799 /* There was no existing VACB. */
803 InsertHeadList(&previous
->CacheMapVacbListEntry
, ¤t
->CacheMapVacbListEntry
);
807 InsertHeadList(&SharedCacheMap
->CacheMapVacbListHead
, ¤t
->CacheMapVacbListEntry
);
809 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
810 InsertTailList(&VacbLruListHead
, ¤t
->VacbLruListEntry
);
811 KeReleaseGuardedMutex(&ViewLock
);
813 MI_SET_USAGE(MI_USAGE_CACHE
);
815 if ((SharedCacheMap
->FileObject
) && (SharedCacheMap
->FileObject
->FileName
.Buffer
))
819 pos
= wcsrchr(SharedCacheMap
->FileObject
->FileName
.Buffer
, '\\');
822 len
= wcslen(pos
) * sizeof(WCHAR
);
823 snprintf(MI_PFN_CURRENT_PROCESS_NAME
, min(16, len
), "%S", pos
);
827 snprintf(MI_PFN_CURRENT_PROCESS_NAME
, min(16, len
), "%wZ", &SharedCacheMap
->FileObject
->FileName
);
832 /* Reference it to allow release */
833 CcRosVacbIncRefCount(current
);
841 PROS_SHARED_CACHE_MAP SharedCacheMap
,
843 PLONGLONG BaseOffset
,
852 ASSERT(SharedCacheMap
);
854 DPRINT("CcRosGetVacb()\n");
857 * Look for a VACB already mapping the same data.
859 current
= CcRosLookupVacb(SharedCacheMap
, FileOffset
);
863 * Otherwise create a new VACB.
865 Status
= CcRosCreateVacb(SharedCacheMap
, FileOffset
, ¤t
);
866 if (!NT_SUCCESS(Status
))
872 Refs
= CcRosVacbGetRefCount(current
);
874 KeAcquireGuardedMutex(&ViewLock
);
876 /* Move to the tail of the LRU list */
877 RemoveEntryList(¤t
->VacbLruListEntry
);
878 InsertTailList(&VacbLruListHead
, ¤t
->VacbLruListEntry
);
880 KeReleaseGuardedMutex(&ViewLock
);
883 * Return information about the VACB to the caller.
885 *UptoDate
= current
->Valid
;
886 *BaseAddress
= current
->BaseAddress
;
887 DPRINT("*BaseAddress %p\n", *BaseAddress
);
889 *BaseOffset
= current
->FileOffset
.QuadPart
;
893 return STATUS_SUCCESS
;
899 PROS_SHARED_CACHE_MAP SharedCacheMap
,
905 * FUNCTION: Request a page mapping for a shared cache map
910 ASSERT(SharedCacheMap
);
912 if (FileOffset
% VACB_MAPPING_GRANULARITY
!= 0)
914 DPRINT1("Bad fileoffset %I64x should be multiple of %x",
915 FileOffset
, VACB_MAPPING_GRANULARITY
);
916 KeBugCheck(CACHE_MANAGER
);
919 return CcRosGetVacb(SharedCacheMap
,
931 MEMORY_AREA
* MemoryArea
,
937 ASSERT(SwapEntry
== 0);
940 ASSERT(MmGetReferenceCountPage(Page
) == 1);
941 MmReleasePageMemoryConsumer(MC_CACHE
, Page
);
946 CcRosInternalFreeVacb (
949 * FUNCTION: Releases a VACB associated with a shared cache map
952 DPRINT("Freeing VACB 0x%p\n", Vacb
);
954 if (Vacb
->SharedCacheMap
->Trace
)
956 DPRINT1("CacheMap 0x%p: deleting VACB: 0x%p\n", Vacb
->SharedCacheMap
, Vacb
);
960 MmLockAddressSpace(MmGetKernelAddressSpace());
961 MmFreeMemoryArea(MmGetKernelAddressSpace(),
965 MmUnlockAddressSpace(MmGetKernelAddressSpace());
967 if (Vacb
->PinCount
!= 0 || Vacb
->ReferenceCount
!= 0)
969 DPRINT1("Invalid free: %ld, %ld\n", Vacb
->ReferenceCount
, Vacb
->PinCount
);
970 if (Vacb
->SharedCacheMap
->FileObject
&& Vacb
->SharedCacheMap
->FileObject
->FileName
.Length
)
972 DPRINT1("For file: %wZ\n", &Vacb
->SharedCacheMap
->FileObject
->FileName
);
976 ASSERT(Vacb
->PinCount
== 0);
977 ASSERT(Vacb
->ReferenceCount
== 0);
978 ASSERT(IsListEmpty(&Vacb
->CacheMapVacbListEntry
));
979 ASSERT(IsListEmpty(&Vacb
->DirtyVacbListEntry
));
980 ASSERT(IsListEmpty(&Vacb
->VacbLruListEntry
));
981 RtlFillMemory(Vacb
, sizeof(*Vacb
), 0xfd);
982 ExFreeToNPagedLookasideList(&VacbLookasideList
, Vacb
);
983 return STATUS_SUCCESS
;
992 IN PSECTION_OBJECT_POINTERS SectionObjectPointers
,
993 IN PLARGE_INTEGER FileOffset OPTIONAL
,
995 OUT PIO_STATUS_BLOCK IoStatus
)
997 PROS_SHARED_CACHE_MAP SharedCacheMap
;
998 LARGE_INTEGER Offset
;
999 LONGLONG RemainingLength
;
1003 CCTRACE(CC_API_DEBUG
, "SectionObjectPointers=%p FileOffset=%p Length=%lu\n",
1004 SectionObjectPointers
, FileOffset
, Length
);
1006 DPRINT("CcFlushCache(SectionObjectPointers 0x%p, FileOffset 0x%p, Length %lu, IoStatus 0x%p)\n",
1007 SectionObjectPointers
, FileOffset
, Length
, IoStatus
);
1009 if (SectionObjectPointers
&& SectionObjectPointers
->SharedCacheMap
)
1011 SharedCacheMap
= SectionObjectPointers
->SharedCacheMap
;
1012 ASSERT(SharedCacheMap
);
1015 Offset
= *FileOffset
;
1016 RemainingLength
= Length
;
1020 Offset
.QuadPart
= 0;
1021 RemainingLength
= SharedCacheMap
->FileSize
.QuadPart
;
1026 IoStatus
->Status
= STATUS_SUCCESS
;
1027 IoStatus
->Information
= 0;
1030 while (RemainingLength
> 0)
1032 current
= CcRosLookupVacb(SharedCacheMap
, Offset
.QuadPart
);
1033 if (current
!= NULL
)
1037 Status
= CcRosFlushVacb(current
);
1038 if (!NT_SUCCESS(Status
) && IoStatus
!= NULL
)
1040 IoStatus
->Status
= Status
;
1044 CcRosReleaseVacb(SharedCacheMap
, current
, current
->Valid
, current
->Dirty
, FALSE
);
1047 Offset
.QuadPart
+= VACB_MAPPING_GRANULARITY
;
1048 RemainingLength
-= min(RemainingLength
, VACB_MAPPING_GRANULARITY
);
1055 IoStatus
->Status
= STATUS_INVALID_PARAMETER
;
1062 CcRosDeleteFileCache (
1063 PFILE_OBJECT FileObject
,
1064 PROS_SHARED_CACHE_MAP SharedCacheMap
)
1066 * FUNCTION: Releases the shared cache map associated with a file object
1069 PLIST_ENTRY current_entry
;
1071 LIST_ENTRY FreeList
;
1074 ASSERT(SharedCacheMap
);
1076 SharedCacheMap
->OpenCount
++;
1077 KeReleaseGuardedMutex(&ViewLock
);
1079 CcFlushCache(FileObject
->SectionObjectPointer
, NULL
, 0, NULL
);
1081 KeAcquireGuardedMutex(&ViewLock
);
1082 SharedCacheMap
->OpenCount
--;
1083 if (SharedCacheMap
->OpenCount
== 0)
1087 FileObject
->SectionObjectPointer
->SharedCacheMap
= NULL
;
1092 InitializeListHead(&FreeList
);
1093 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
1094 while (!IsListEmpty(&SharedCacheMap
->CacheMapVacbListHead
))
1096 current_entry
= RemoveTailList(&SharedCacheMap
->CacheMapVacbListHead
);
1097 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
1099 current
= CONTAINING_RECORD(current_entry
, ROS_VACB
, CacheMapVacbListEntry
);
1100 RemoveEntryList(¤t
->VacbLruListEntry
);
1101 InitializeListHead(¤t
->VacbLruListEntry
);
1104 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
1105 CcRosUnmarkDirtyVacb(current
, FALSE
);
1106 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
1107 DPRINT1("Freeing dirty VACB\n");
1109 if (current
->MappedCount
!= 0)
1111 current
->MappedCount
= 0;
1112 NT_VERIFY(CcRosVacbDecRefCount(current
) > 0);
1113 DPRINT1("Freeing mapped VACB\n");
1115 InsertHeadList(&FreeList
, ¤t
->CacheMapVacbListEntry
);
1117 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &oldIrql
);
1120 SharedCacheMap
->Trace
= FALSE
;
1122 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, oldIrql
);
1124 KeReleaseGuardedMutex(&ViewLock
);
1125 ObDereferenceObject(SharedCacheMap
->FileObject
);
1127 while (!IsListEmpty(&FreeList
))
1131 current_entry
= RemoveTailList(&FreeList
);
1132 current
= CONTAINING_RECORD(current_entry
, ROS_VACB
, CacheMapVacbListEntry
);
1133 InitializeListHead(¤t
->CacheMapVacbListEntry
);
1134 Refs
= CcRosVacbDecRefCount(current
);
1135 #if DBG // CORE-14578
1138 DPRINT1("Leaking VACB %p attached to %p (%I64d)\n", current
, FileObject
, current
->FileOffset
.QuadPart
);
1139 DPRINT1("There are: %d references left\n", Refs
);
1140 DPRINT1("Pin: %d, Map: %d\n", current
->PinCount
, current
->MappedCount
);
1141 DPRINT1("Dirty: %d\n", current
->Dirty
);
1142 if (FileObject
->FileName
.Length
!= 0)
1144 DPRINT1("File was: %wZ\n", &FileObject
->FileName
);
1148 DPRINT1("No name for the file\n");
1156 OldIrql
= KeAcquireQueuedSpinLock(LockQueueMasterLock
);
1157 RemoveEntryList(&SharedCacheMap
->SharedCacheMapLinks
);
1158 KeReleaseQueuedSpinLock(LockQueueMasterLock
, OldIrql
);
1160 ExFreeToNPagedLookasideList(&SharedCacheMapLookasideList
, SharedCacheMap
);
1161 KeAcquireGuardedMutex(&ViewLock
);
1163 return STATUS_SUCCESS
;
1168 CcRosReferenceCache (
1169 PFILE_OBJECT FileObject
)
1171 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1172 KeAcquireGuardedMutex(&ViewLock
);
1173 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1174 ASSERT(SharedCacheMap
);
1175 ASSERT(SharedCacheMap
->OpenCount
!= 0);
1176 SharedCacheMap
->OpenCount
++;
1177 KeReleaseGuardedMutex(&ViewLock
);
1182 CcRosRemoveIfClosed (
1183 PSECTION_OBJECT_POINTERS SectionObjectPointer
)
1185 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1186 DPRINT("CcRosRemoveIfClosed()\n");
1187 KeAcquireGuardedMutex(&ViewLock
);
1188 SharedCacheMap
= SectionObjectPointer
->SharedCacheMap
;
1189 if (SharedCacheMap
&& SharedCacheMap
->OpenCount
== 0)
1191 CcRosDeleteFileCache(SharedCacheMap
->FileObject
, SharedCacheMap
);
1193 KeReleaseGuardedMutex(&ViewLock
);
1199 CcRosDereferenceCache (
1200 PFILE_OBJECT FileObject
)
1202 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1203 KeAcquireGuardedMutex(&ViewLock
);
1204 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1205 ASSERT(SharedCacheMap
);
1206 if (SharedCacheMap
->OpenCount
> 0)
1208 SharedCacheMap
->OpenCount
--;
1209 if (SharedCacheMap
->OpenCount
== 0)
1211 MmFreeSectionSegments(SharedCacheMap
->FileObject
);
1212 CcRosDeleteFileCache(FileObject
, SharedCacheMap
);
1215 KeReleaseGuardedMutex(&ViewLock
);
1220 CcRosReleaseFileCache (
1221 PFILE_OBJECT FileObject
)
1223 * FUNCTION: Called by the file system when a handle to a file object
1228 PPRIVATE_CACHE_MAP PrivateMap
;
1229 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1231 KeAcquireGuardedMutex(&ViewLock
);
1233 if (FileObject
->SectionObjectPointer
->SharedCacheMap
!= NULL
)
1235 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1237 /* Closing the handle, so kill the private cache map
1238 * Before you event try to remove it from FO, always
1239 * lock the master lock, to be sure not to race
1240 * with a potential read ahead ongoing!
1242 OldIrql
= KeAcquireQueuedSpinLock(LockQueueMasterLock
);
1243 PrivateMap
= FileObject
->PrivateCacheMap
;
1244 FileObject
->PrivateCacheMap
= NULL
;
1245 KeReleaseQueuedSpinLock(LockQueueMasterLock
, OldIrql
);
1247 if (PrivateMap
!= NULL
)
1249 /* Remove it from the file */
1250 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &OldIrql
);
1251 RemoveEntryList(&PrivateMap
->PrivateLinks
);
1252 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, OldIrql
);
1255 if (PrivateMap
!= &SharedCacheMap
->PrivateCacheMap
)
1257 ExFreePoolWithTag(PrivateMap
, TAG_PRIVATE_CACHE_MAP
);
1261 PrivateMap
->NodeTypeCode
= 0;
1264 if (SharedCacheMap
->OpenCount
> 0)
1266 SharedCacheMap
->OpenCount
--;
1267 if (SharedCacheMap
->OpenCount
== 0)
1269 MmFreeSectionSegments(SharedCacheMap
->FileObject
);
1270 CcRosDeleteFileCache(FileObject
, SharedCacheMap
);
1275 KeReleaseGuardedMutex(&ViewLock
);
1276 return STATUS_SUCCESS
;
1281 CcRosInitializeFileCache (
1282 PFILE_OBJECT FileObject
,
1283 PCC_FILE_SIZES FileSizes
,
1285 PCACHE_MANAGER_CALLBACKS CallBacks
,
1286 PVOID LazyWriterContext
)
1288 * FUNCTION: Initializes a shared cache map for a file object
1293 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1295 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1296 DPRINT("CcRosInitializeFileCache(FileObject 0x%p, SharedCacheMap 0x%p)\n",
1297 FileObject
, SharedCacheMap
);
1300 KeAcquireGuardedMutex(&ViewLock
);
1301 if (SharedCacheMap
== NULL
)
1304 SharedCacheMap
= ExAllocateFromNPagedLookasideList(&SharedCacheMapLookasideList
);
1305 if (SharedCacheMap
== NULL
)
1307 KeReleaseGuardedMutex(&ViewLock
);
1308 return STATUS_INSUFFICIENT_RESOURCES
;
1310 RtlZeroMemory(SharedCacheMap
, sizeof(*SharedCacheMap
));
1311 ObReferenceObjectByPointer(FileObject
,
1315 SharedCacheMap
->NodeTypeCode
= NODE_TYPE_SHARED_MAP
;
1316 SharedCacheMap
->NodeByteSize
= sizeof(*SharedCacheMap
);
1317 SharedCacheMap
->FileObject
= FileObject
;
1318 SharedCacheMap
->Callbacks
= CallBacks
;
1319 SharedCacheMap
->LazyWriteContext
= LazyWriterContext
;
1320 SharedCacheMap
->SectionSize
= FileSizes
->AllocationSize
;
1321 SharedCacheMap
->FileSize
= FileSizes
->FileSize
;
1322 SharedCacheMap
->PinAccess
= PinAccess
;
1323 SharedCacheMap
->DirtyPageThreshold
= 0;
1324 SharedCacheMap
->DirtyPages
= 0;
1325 InitializeListHead(&SharedCacheMap
->PrivateList
);
1326 KeInitializeSpinLock(&SharedCacheMap
->CacheMapLock
);
1327 InitializeListHead(&SharedCacheMap
->CacheMapVacbListHead
);
1328 FileObject
->SectionObjectPointer
->SharedCacheMap
= SharedCacheMap
;
1330 OldIrql
= KeAcquireQueuedSpinLock(LockQueueMasterLock
);
1331 InsertTailList(&CcCleanSharedCacheMapList
, &SharedCacheMap
->SharedCacheMapLinks
);
1332 KeReleaseQueuedSpinLock(LockQueueMasterLock
, OldIrql
);
1334 if (FileObject
->PrivateCacheMap
== NULL
)
1336 PPRIVATE_CACHE_MAP PrivateMap
;
1338 /* Allocate the private cache map for this handle */
1339 if (SharedCacheMap
->PrivateCacheMap
.NodeTypeCode
!= 0)
1341 PrivateMap
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(PRIVATE_CACHE_MAP
), TAG_PRIVATE_CACHE_MAP
);
1345 PrivateMap
= &SharedCacheMap
->PrivateCacheMap
;
1348 if (PrivateMap
== NULL
)
1350 /* If we also allocated the shared cache map for this file, kill it */
1353 OldIrql
= KeAcquireQueuedSpinLock(LockQueueMasterLock
);
1354 RemoveEntryList(&SharedCacheMap
->SharedCacheMapLinks
);
1355 KeReleaseQueuedSpinLock(LockQueueMasterLock
, OldIrql
);
1357 FileObject
->SectionObjectPointer
->SharedCacheMap
= NULL
;
1358 ObDereferenceObject(FileObject
);
1359 ExFreeToNPagedLookasideList(&SharedCacheMapLookasideList
, SharedCacheMap
);
1362 KeReleaseGuardedMutex(&ViewLock
);
1363 return STATUS_INSUFFICIENT_RESOURCES
;
1367 RtlZeroMemory(PrivateMap
, sizeof(PRIVATE_CACHE_MAP
));
1368 PrivateMap
->NodeTypeCode
= NODE_TYPE_PRIVATE_MAP
;
1369 PrivateMap
->ReadAheadMask
= PAGE_SIZE
- 1;
1370 PrivateMap
->FileObject
= FileObject
;
1371 KeInitializeSpinLock(&PrivateMap
->ReadAheadSpinLock
);
1373 /* Link it to the file */
1374 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &OldIrql
);
1375 InsertTailList(&SharedCacheMap
->PrivateList
, &PrivateMap
->PrivateLinks
);
1376 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, OldIrql
);
1378 FileObject
->PrivateCacheMap
= PrivateMap
;
1379 SharedCacheMap
->OpenCount
++;
1381 KeReleaseGuardedMutex(&ViewLock
);
1383 return STATUS_SUCCESS
;
1391 CcGetFileObjectFromSectionPtrs (
1392 IN PSECTION_OBJECT_POINTERS SectionObjectPointers
)
1394 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1396 CCTRACE(CC_API_DEBUG
, "SectionObjectPointers=%p\n", SectionObjectPointers
);
1398 if (SectionObjectPointers
&& SectionObjectPointers
->SharedCacheMap
)
1400 SharedCacheMap
= SectionObjectPointers
->SharedCacheMap
;
1401 ASSERT(SharedCacheMap
);
1402 return SharedCacheMap
->FileObject
;
1413 DPRINT("CcInitView()\n");
1415 InitializeListHead(&DirtyVacbListHead
);
1416 InitializeListHead(&VacbLruListHead
);
1417 InitializeListHead(&CcDeferredWrites
);
1418 InitializeListHead(&CcCleanSharedCacheMapList
);
1419 KeInitializeSpinLock(&CcDeferredWriteSpinLock
);
1420 KeInitializeGuardedMutex(&ViewLock
);
1421 ExInitializeNPagedLookasideList(&iBcbLookasideList
,
1425 sizeof(INTERNAL_BCB
),
1428 ExInitializeNPagedLookasideList(&SharedCacheMapLookasideList
,
1432 sizeof(ROS_SHARED_CACHE_MAP
),
1433 TAG_SHARED_CACHE_MAP
,
1435 ExInitializeNPagedLookasideList(&VacbLookasideList
,
1443 MmInitializeMemoryConsumer(MC_CACHE
, CcRosTrimCache
);
1445 CcInitCacheZeroPage();
1448 #if DBG && defined(KDBG)
1450 ExpKdbgExtFileCache(ULONG Argc
, PCHAR Argv
[])
1452 PLIST_ENTRY ListEntry
;
1453 UNICODE_STRING NoName
= RTL_CONSTANT_STRING(L
"No name for File");
1455 KdbpPrint(" Usage Summary (in kb)\n");
1456 KdbpPrint("Shared\t\tValid\tDirty\tName\n");
1457 /* No need to lock the spin lock here, we're in DBG */
1458 for (ListEntry
= CcCleanSharedCacheMapList
.Flink
;
1459 ListEntry
!= &CcCleanSharedCacheMapList
;
1460 ListEntry
= ListEntry
->Flink
)
1463 ULONG Valid
= 0, Dirty
= 0;
1464 PROS_SHARED_CACHE_MAP SharedCacheMap
;
1465 PUNICODE_STRING FileName
;
1467 SharedCacheMap
= CONTAINING_RECORD(ListEntry
, ROS_SHARED_CACHE_MAP
, SharedCacheMapLinks
);
1470 Dirty
= (SharedCacheMap
->DirtyPages
* PAGE_SIZE
) / 1024;
1472 /* First, count for all the associated VACB */
1473 for (Vacbs
= SharedCacheMap
->CacheMapVacbListHead
.Flink
;
1474 Vacbs
!= &SharedCacheMap
->CacheMapVacbListHead
;
1475 Vacbs
= Vacbs
->Flink
)
1479 Vacb
= CONTAINING_RECORD(Vacbs
, ROS_VACB
, CacheMapVacbListEntry
);
1482 Valid
+= VACB_MAPPING_GRANULARITY
/ 1024;
1487 if (SharedCacheMap
->FileObject
!= NULL
&&
1488 SharedCacheMap
->FileObject
->FileName
.Length
!= 0)
1490 FileName
= &SharedCacheMap
->FileObject
->FileName
;
1498 KdbpPrint("%p\t%d\t%d\t%wZ\n", SharedCacheMap
, Valid
, Dirty
, FileName
);
1505 ExpKdbgExtDefWrites(ULONG Argc
, PCHAR Argv
[])
1507 KdbpPrint("CcTotalDirtyPages:\t%lu (%lu Kb)\n", CcTotalDirtyPages
,
1508 (CcTotalDirtyPages
* PAGE_SIZE
) / 1024);
1509 KdbpPrint("CcDirtyPageThreshold:\t%lu (%lu Kb)\n", CcDirtyPageThreshold
,
1510 (CcDirtyPageThreshold
* PAGE_SIZE
) / 1024);
1511 KdbpPrint("MmAvailablePages:\t%lu (%lu Kb)\n", MmAvailablePages
,
1512 (MmAvailablePages
* PAGE_SIZE
) / 1024);
1513 KdbpPrint("MmThrottleTop:\t\t%lu (%lu Kb)\n", MmThrottleTop
,
1514 (MmThrottleTop
* PAGE_SIZE
) / 1024);
1515 KdbpPrint("MmThrottleBottom:\t%lu (%lu Kb)\n", MmThrottleBottom
,
1516 (MmThrottleBottom
* PAGE_SIZE
) / 1024);
1517 KdbpPrint("MmModifiedPageListHead.Total:\t%lu (%lu Kb)\n", MmModifiedPageListHead
.Total
,
1518 (MmModifiedPageListHead
.Total
* PAGE_SIZE
) / 1024);
1520 if (CcTotalDirtyPages
>= CcDirtyPageThreshold
)
1522 KdbpPrint("CcTotalDirtyPages above the threshold, writes should be throttled\n");
1524 else if (CcTotalDirtyPages
+ 64 >= CcDirtyPageThreshold
)
1526 KdbpPrint("CcTotalDirtyPages within 64 (max charge) pages of the threshold, writes may be throttled\n");
1530 KdbpPrint("CcTotalDirtyPages below the threshold, writes should not be throttled\n");