3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: view.c,v 1.47 2002/08/17 15:14:26 hbirr Exp $
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/cc/view.c
23 * PURPOSE: Cache manager
24 * PROGRAMMER: David Welch (welch@mcmail.com)
25 * PORTABILITY: Checked
30 /* NOTES **********************************************************************
32 * This is not the NT implementation of a file cache nor anything much like
35 * The general procedure for a filesystem to implement a read or write
36 * dispatch routine is as follows
38 * (1) If caching for the FCB hasn't been initiated then so do by calling
39 * CcInitializeFileCache.
41 * (2) For each 4k region which is being read or written obtain a cache page
42 * by calling CcRequestCachePage.
44 * (3) If either the page is being read or not completely written, and it is
45 * not up to date then read its data from the underlying medium. If the read
46 * fails then call CcReleaseCachePage with VALID as FALSE and return a error.
48 * (4) Copy the data into or out of the page as necessary.
50 * (5) Release the cache page
52 /* INCLUDES ******************************************************************/
54 #include <ddk/ntddk.h>
55 #include <ddk/ntifs.h>
56 #include <internal/mm.h>
57 #include <internal/cc.h>
58 #include <internal/pool.h>
59 #include <ntos/minmax.h>
62 #include <internal/debug.h>
64 /* GLOBALS *******************************************************************/
66 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
67 #define ROUND_DOWN(N, S) (((N) % (S)) ? ROUND_UP(N, S) - S : N)
69 #define TAG_CSEG TAG('C', 'S', 'E', 'G')
70 #define TAG_BCB TAG('B', 'C', 'B', ' ')
72 static LIST_ENTRY DirtySegmentListHead
;
73 static LIST_ENTRY CacheSegmentListHead
;
74 static LIST_ENTRY CacheSegmentLRUListHead
;
76 static FAST_MUTEX ViewLock
;
79 CcRosInternalFreeCacheSegment(PBCB Bcb
, PCACHE_SEGMENT CacheSeg
);
81 /* FUNCTIONS *****************************************************************/
84 CcRosFlushCacheSegment(PCACHE_SEGMENT CacheSegment
)
87 Status
= WriteCacheSegment(CacheSegment
);
88 if (NT_SUCCESS(Status
))
90 CacheSegment
->Dirty
= FALSE
;
91 RemoveEntryList(&CacheSegment
->DirtySegmentListEntry
);
97 CcRosFlushDirtyPages(ULONG Target
, PULONG Count
)
99 PLIST_ENTRY current_entry
;
100 PCACHE_SEGMENT current
;
101 ULONG PagesPerSegment
;
105 DPRINT("CcRosFlushDirtyPages(Target %d)\n", Target
);
109 ExAcquireFastMutex(&ViewLock
);
110 current_entry
= DirtySegmentListHead
.Flink
;
111 while (current_entry
!= &DirtySegmentListHead
&& Target
> 0)
113 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
114 DirtySegmentListEntry
);
115 current_entry
= current_entry
->Flink
;
116 Locked
= ExTryToAcquireFastMutex(¤t
->Lock
);
121 assert(current
->Dirty
);
122 if (current
->ReferenceCount
> 0)
124 ExReleaseFastMutex(¤t
->Lock
);
127 current
->ReferenceCount
++;
128 ExReleaseFastMutex(&ViewLock
);
129 PagesPerSegment
= current
->Bcb
->CacheSegmentSize
/ PAGESIZE
;
130 Status
= CcRosFlushCacheSegment(current
);
131 current
->ReferenceCount
--;
132 ExReleaseFastMutex(¤t
->Lock
);
133 if (!NT_SUCCESS(Status
))
135 DPRINT1("CC: Failed to flush cache segment.\n");
137 (*Count
) += PagesPerSegment
;
138 Target
-= PagesPerSegment
;
140 ExAcquireFastMutex(&ViewLock
);
141 current_entry
= DirtySegmentListHead
.Flink
;
143 ExReleaseFastMutex(&ViewLock
);
144 DPRINT("CcRosTrimCache() finished\n");
145 return(STATUS_SUCCESS
);
149 CcRosTrimCache(ULONG Target
, ULONG Priority
, PULONG NrFreed
)
151 * FUNCTION: Try to free some memory from the file cache.
153 * Target - The number of pages to be freed.
154 * Priority - The priority of free (currently unused).
155 * NrFreed - Points to a variable where the number of pages
156 * actually freed is returned.
159 PLIST_ENTRY current_entry
;
160 PCACHE_SEGMENT current
;
161 ULONG PagesPerSegment
;
165 DPRINT("CcRosTrimCache(Target %d)\n", Target
);
169 ExAcquireFastMutex(&ViewLock
);
170 current_entry
= CacheSegmentLRUListHead
.Flink
;
171 while (current_entry
!= &CacheSegmentLRUListHead
&& Target
> 0)
173 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
174 CacheSegmentLRUListEntry
);
175 current_entry
= current_entry
->Flink
;
176 Locked
= ExTryToAcquireFastMutex(¤t
->Lock
);
181 if (current
->MappedCount
> 0 || current
->Dirty
||
182 current
->ReferenceCount
> 0)
184 ExReleaseFastMutex(¤t
->Lock
);
187 ExReleaseFastMutex(¤t
->Lock
);
188 DPRINT("current->Bcb->CacheSegmentSize %d\n",
189 current
->Bcb
->CacheSegmentSize
);
190 PagesPerSegment
= current
->Bcb
->CacheSegmentSize
/ PAGESIZE
;
191 CcRosInternalFreeCacheSegment(current
->Bcb
, current
);
192 DPRINT("CcRosTrimCache(): Freed %d\n", PagesPerSegment
);
193 PagesFreed
= min(PagesPerSegment
, Target
);
194 Target
= Target
- PagesFreed
;
195 (*NrFreed
) = (*NrFreed
) + PagesFreed
;
197 ExReleaseFastMutex(&ViewLock
);
198 DPRINT("CcRosTrimCache() finished\n");
199 return(STATUS_SUCCESS
);
203 CcRosReleaseCacheSegment(PBCB Bcb
,
204 PCACHE_SEGMENT CacheSeg
,
209 BOOLEAN WasDirty
= CacheSeg
->Dirty
;
211 DPRINT("CcReleaseCachePage(Bcb %x, CacheSeg %x, Valid %d)\n",
212 Bcb
, CacheSeg
, Valid
);
214 CacheSeg
->Valid
= Valid
;
215 CacheSeg
->Dirty
= CacheSeg
->Dirty
|| Dirty
;
218 CacheSeg
->MappedCount
++;
220 ExReleaseFastMutex(&CacheSeg
->Lock
);
221 ExAcquireFastMutex(&ViewLock
);
222 if (!WasDirty
&& CacheSeg
->Dirty
)
224 InsertTailList(&DirtySegmentListHead
, &CacheSeg
->DirtySegmentListEntry
);
226 RemoveEntryList(&CacheSeg
->CacheSegmentLRUListEntry
);
227 InsertTailList(&CacheSegmentLRUListHead
,
228 &CacheSeg
->CacheSegmentLRUListEntry
);
229 ExReleaseFastMutex(&ViewLock
);
230 InterlockedDecrement(&CacheSeg
->ReferenceCount
);
232 DPRINT("CcReleaseCachePage() finished\n");
234 return(STATUS_SUCCESS
);
237 PCACHE_SEGMENT
CcRosLookupCacheSegment(PBCB Bcb
, ULONG FileOffset
)
239 PLIST_ENTRY current_entry
;
240 PCACHE_SEGMENT current
;
243 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
244 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
245 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
247 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
248 BcbSegmentListEntry
);
249 if (current
->FileOffset
<= FileOffset
&&
250 (current
->FileOffset
+ Bcb
->CacheSegmentSize
) > FileOffset
)
252 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
255 current_entry
= current_entry
->Flink
;
257 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
262 CcRosMarkDirtyCacheSegment(PBCB Bcb
, ULONG FileOffset
)
264 PCACHE_SEGMENT CacheSeg
;
266 ExAcquireFastMutex(&ViewLock
);
267 CacheSeg
= CcRosLookupCacheSegment(Bcb
, FileOffset
);
268 if (CacheSeg
== NULL
)
272 ExAcquireFastMutex(&CacheSeg
->Lock
);
273 if (!CacheSeg
->Dirty
)
275 InsertTailList(&DirtySegmentListHead
, &CacheSeg
->DirtySegmentListEntry
);
277 CacheSeg
->Dirty
= TRUE
;
278 ExReleaseFastMutex(&CacheSeg
->Lock
);
279 ExReleaseFastMutex(&ViewLock
);
280 return(STATUS_SUCCESS
);
284 CcRosSuggestFreeCacheSegment(PBCB Bcb
, ULONG FileOffset
, BOOLEAN NowDirty
)
286 PCACHE_SEGMENT CacheSeg
;
288 ExAcquireFastMutex(&ViewLock
);
289 CacheSeg
= CcRosLookupCacheSegment(Bcb
, FileOffset
);
290 if (CacheSeg
== NULL
)
294 ExAcquireFastMutex(&CacheSeg
->Lock
);
295 if (CacheSeg
->MappedCount
> 0)
299 CacheSeg
->Dirty
= CacheSeg
->Dirty
|| NowDirty
;
300 if (CacheSeg
->Dirty
|| CacheSeg
->ReferenceCount
> 0)
302 ExReleaseFastMutex(&CacheSeg
->Lock
);
303 ExReleaseFastMutex(&ViewLock
);
304 return(STATUS_UNSUCCESSFUL
);
306 ExReleaseFastMutex(&CacheSeg
->Lock
);
307 CcRosInternalFreeCacheSegment(CacheSeg
->Bcb
, CacheSeg
);
308 ExReleaseFastMutex(&ViewLock
);
309 return(STATUS_SUCCESS
);
313 CcRosUnmapCacheSegment(PBCB Bcb
, ULONG FileOffset
, BOOLEAN NowDirty
)
315 PCACHE_SEGMENT CacheSeg
;
317 ExAcquireFastMutex(&ViewLock
);
318 CacheSeg
= CcRosLookupCacheSegment(Bcb
, FileOffset
);
319 if (CacheSeg
== NULL
)
321 ExReleaseFastMutex(&ViewLock
);
322 return(STATUS_UNSUCCESSFUL
);
324 CacheSeg
->ReferenceCount
++;
325 ExReleaseFastMutex(&ViewLock
);
326 ExAcquireFastMutex(&CacheSeg
->Lock
);
327 CacheSeg
->MappedCount
--;
328 CacheSeg
->Dirty
= CacheSeg
->Dirty
|| NowDirty
;
329 CacheSeg
->ReferenceCount
--;
330 ExReleaseFastMutex(&CacheSeg
->Lock
);
331 return(STATUS_SUCCESS
);
335 CcRosCreateCacheSegment(PBCB Bcb
,
337 PCACHE_SEGMENT
* CacheSeg
,
341 PCACHE_SEGMENT current
;
345 current
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(CACHE_SEGMENT
),
348 MmLockAddressSpace(MmGetKernelAddressSpace());
349 current
->BaseAddress
= NULL
;
350 Status
= MmCreateMemoryArea(KernelMode
,
351 MmGetKernelAddressSpace(),
352 MEMORY_AREA_CACHE_SEGMENT
,
353 ¤t
->BaseAddress
,
354 Bcb
->CacheSegmentSize
,
356 (PMEMORY_AREA
*)¤t
->MemoryArea
,
358 if (!NT_SUCCESS(Status
))
360 MmUnlockAddressSpace(MmGetKernelAddressSpace());
363 MmUnlockAddressSpace(MmGetKernelAddressSpace());
364 current
->Valid
= FALSE
;
365 current
->Dirty
= FALSE
;
366 current
->FileOffset
= ROUND_DOWN(FileOffset
, Bcb
->CacheSegmentSize
);
368 current
->MappedCount
= 0;
369 ExInitializeFastMutex(¤t
->Lock
);
370 current
->ReferenceCount
= 1;
371 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
372 InsertTailList(&Bcb
->BcbSegmentListHead
, ¤t
->BcbSegmentListEntry
);
373 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
374 InsertTailList(&CacheSegmentListHead
, ¤t
->CacheSegmentListEntry
);
375 InsertTailList(&CacheSegmentLRUListHead
,
376 ¤t
->CacheSegmentLRUListEntry
);
377 current
->DirtySegmentListEntry
.Flink
=
378 current
->DirtySegmentListEntry
.Blink
= NULL
;
381 ExAcquireFastMutex(¤t
->Lock
);
383 ExReleaseFastMutex(&ViewLock
);
384 for (i
= 0; i
< (Bcb
->CacheSegmentSize
/ PAGESIZE
); i
++)
386 PHYSICAL_ADDRESS Page
;
388 Status
= MmRequestPageMemoryConsumer(MC_CACHE
, TRUE
, &Page
);
389 if (!NT_SUCCESS(Status
))
394 Status
= MmCreateVirtualMapping(NULL
,
395 current
->BaseAddress
+ (i
* PAGESIZE
),
399 if (!NT_SUCCESS(Status
))
405 return(STATUS_SUCCESS
);
409 CcRosGetCacheSegmentChain(PBCB Bcb
,
412 PCACHE_SEGMENT
* CacheSeg
)
414 PCACHE_SEGMENT current
;
416 PCACHE_SEGMENT
* CacheSegList
;
417 PCACHE_SEGMENT Previous
;
419 Length
= ROUND_UP(Length
, Bcb
->CacheSegmentSize
);
421 CacheSegList
= alloca(sizeof(PCACHE_SEGMENT
) *
422 (Length
/ Bcb
->CacheSegmentSize
));
425 * Acquire the global lock.
427 ExAcquireFastMutex(&ViewLock
);
430 * Look for a cache segment already mapping the same data.
432 for (i
= 0; i
< (Length
/ Bcb
->CacheSegmentSize
); i
++)
434 ULONG CurrentOffset
= FileOffset
+ (i
* Bcb
->CacheSegmentSize
);
435 current
= CcRosLookupCacheSegment(Bcb
, CurrentOffset
);
439 * Make sure the cache segment can't go away outside of our control.
441 current
->ReferenceCount
++;
442 CacheSegList
[i
] = current
;
446 CcRosCreateCacheSegment(Bcb
, CurrentOffset
, ¤t
, FALSE
);
447 CacheSegList
[i
] = current
;
448 ExAcquireFastMutex(&ViewLock
);
451 ExReleaseFastMutex(&ViewLock
);
453 for (i
= 0; i
< (Length
/ Bcb
->CacheSegmentSize
); i
++)
455 ExAcquireFastMutex(&CacheSegList
[i
]->Lock
);
458 *CacheSeg
= CacheSegList
[i
];
459 Previous
= CacheSegList
[i
];
463 Previous
->NextInChain
= CacheSegList
[i
];
464 Previous
= CacheSegList
[i
];
467 Previous
->NextInChain
= NULL
;
469 return(STATUS_SUCCESS
);
473 CcRosGetCacheSegment(PBCB Bcb
,
478 PCACHE_SEGMENT
* CacheSeg
)
480 PCACHE_SEGMENT current
;
484 * Acquire the global lock.
486 ExAcquireFastMutex(&ViewLock
);
489 * Look for a cache segment already mapping the same data.
491 current
= CcRosLookupCacheSegment(Bcb
, FileOffset
);
495 * Make sure the cache segment can't go away outside of our control.
497 current
->ReferenceCount
++;
499 * Release the global lock and lock the cache segment.
501 ExReleaseFastMutex(&ViewLock
);
502 ExAcquireFastMutex(¤t
->Lock
);
504 * Return information about the segment to the caller.
506 *UptoDate
= current
->Valid
;
507 *BaseAddress
= current
->BaseAddress
;
508 DPRINT("*BaseAddress 0x%.8X\n", *BaseAddress
);
510 *BaseOffset
= current
->FileOffset
;
511 return(STATUS_SUCCESS
);
515 * Otherwise create a new segment.
517 Status
= CcRosCreateCacheSegment(Bcb
, FileOffset
, ¤t
, TRUE
);
518 *UptoDate
= current
->Valid
;
519 *BaseAddress
= current
->BaseAddress
;
520 DPRINT("*BaseAddress 0x%.8X\n", *BaseAddress
);
522 *BaseOffset
= current
->FileOffset
;
524 return(STATUS_SUCCESS
);
528 CcRosRequestCacheSegment(PBCB Bcb
,
532 PCACHE_SEGMENT
* CacheSeg
)
534 * FUNCTION: Request a page mapping for a BCB
539 if ((FileOffset
% Bcb
->CacheSegmentSize
) != 0)
541 CPRINT("Bad fileoffset %x should be multiple of %x",
542 FileOffset
, Bcb
->CacheSegmentSize
);
546 return(CcRosGetCacheSegment(Bcb
,
555 CcFreeCachePage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
556 PHYSICAL_ADDRESS PhysAddr
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
558 assert(SwapEntry
== 0);
559 if (PhysAddr
.QuadPart
!= 0)
561 MmReleasePageMemoryConsumer(MC_CACHE
, PhysAddr
);
566 CcRosInternalFreeCacheSegment(PBCB Bcb
, PCACHE_SEGMENT CacheSeg
)
568 * FUNCTION: Releases a cache segment associated with a BCB
571 DPRINT("Freeing cache segment %x\n", CacheSeg
);
572 RemoveEntryList(&CacheSeg
->CacheSegmentListEntry
);
573 RemoveEntryList(&CacheSeg
->CacheSegmentLRUListEntry
);
574 RemoveEntryList(&CacheSeg
->BcbSegmentListEntry
);
575 MmLockAddressSpace(MmGetKernelAddressSpace());
576 MmFreeMemoryArea(MmGetKernelAddressSpace(),
577 CacheSeg
->BaseAddress
,
578 Bcb
->CacheSegmentSize
,
581 MmUnlockAddressSpace(MmGetKernelAddressSpace());
582 ExFreePool(CacheSeg
);
583 return(STATUS_SUCCESS
);
587 CcRosFreeCacheSegment(PBCB Bcb
, PCACHE_SEGMENT CacheSeg
)
590 ExAcquireFastMutex(&ViewLock
);
591 Status
= CcRosInternalFreeCacheSegment(Bcb
, CacheSeg
);
592 ExReleaseFastMutex(&ViewLock
);
597 CcRosDeleteFileCache(PFILE_OBJECT FileObject
, PBCB Bcb
)
599 * FUNCTION: Releases the BCB associated with a file object
602 PLIST_ENTRY current_entry
;
603 PCACHE_SEGMENT current
;
606 DPRINT("CcRosDeleteFileCache(FileObject %x, Bcb %x)\n", Bcb
->FileObject
,
609 MmFreeSectionSegments(Bcb
->FileObject
);
612 * Write back dirty cache segments.
614 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
615 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
618 CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
, BcbSegmentListEntry
);
621 Status
= WriteCacheSegment(current
);
622 if (!NT_SUCCESS(Status
))
624 DPRINT1("Failed to write cache segment (Status %X)\n", Status
);
626 ExAcquireFastMutex(&ViewLock
);
627 RemoveEntryList(¤t
->DirtySegmentListEntry
);
628 ExReleaseFastMutex(&ViewLock
);
630 current_entry
= current_entry
->Flink
;
634 * Release all cache segments.
636 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
637 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
640 CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
, BcbSegmentListEntry
);
641 current_entry
= current_entry
->Flink
;
642 CcRosFreeCacheSegment(Bcb
, current
);
644 FileObject
->SectionObjectPointers
->SharedCacheMap
= NULL
;
645 ObDereferenceObject (Bcb
->FileObject
);
648 return(STATUS_SUCCESS
);
651 VOID
CcRosReferenceCache(PFILE_OBJECT FileObject
)
654 PBCB Bcb
= (PBCB
)FileObject
->SectionObjectPointers
->SharedCacheMap
;
655 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
657 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
660 VOID
CcRosDereferenceCache(PFILE_OBJECT FileObject
)
663 PBCB Bcb
= (PBCB
)FileObject
->SectionObjectPointers
->SharedCacheMap
;
664 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
666 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
667 if (Bcb
->RefCount
== 0)
669 CcRosDeleteFileCache(FileObject
, Bcb
);
674 CcRosReleaseFileCache(PFILE_OBJECT FileObject
, PBCB Bcb
)
676 * FUNCTION: Called by the file system when a handle to a file object
681 if (FileObject
->SectionObjectPointers
->SharedCacheMap
!= NULL
)
683 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
684 if (FileObject
->PrivateCacheMap
!= NULL
)
686 FileObject
->PrivateCacheMap
= NULL
;
689 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
690 if (Bcb
->RefCount
== 0)
692 CcRosDeleteFileCache(FileObject
, Bcb
);
695 return(STATUS_SUCCESS
);
699 CcRosInitializeFileCache(PFILE_OBJECT FileObject
,
701 ULONG CacheSegmentSize
)
703 * FUNCTION: Initializes a BCB for a file object
709 (*Bcb
) = ExAllocatePoolWithTag(NonPagedPool
, sizeof(BCB
), TAG_BCB
);
712 return(STATUS_UNSUCCESSFUL
);
715 ObReferenceObjectByPointer(FileObject
,
719 (*Bcb
)->FileObject
= FileObject
;
720 (*Bcb
)->CacheSegmentSize
= CacheSegmentSize
;
721 if (FileObject
->FsContext
)
723 (*Bcb
)->AllocationSize
=
724 ((REACTOS_COMMON_FCB_HEADER
*)FileObject
->FsContext
)->AllocationSize
;
726 ((REACTOS_COMMON_FCB_HEADER
*)FileObject
->FsContext
)->FileSize
;
728 KeInitializeSpinLock(&(*Bcb
)->BcbLock
);
729 InitializeListHead(&(*Bcb
)->BcbSegmentListHead
);
730 FileObject
->SectionObjectPointers
->SharedCacheMap
= *Bcb
;
732 KeAcquireSpinLock(&(*Bcb
)->BcbLock
, &oldIrql
);
733 if (FileObject
->PrivateCacheMap
== NULL
)
735 FileObject
->PrivateCacheMap
= *Bcb
;
738 KeReleaseSpinLock(&(*Bcb
)->BcbLock
, oldIrql
);
740 return(STATUS_SUCCESS
);
746 DPRINT("CcInitView()\n");
747 InitializeListHead(&CacheSegmentListHead
);
748 InitializeListHead(&DirtySegmentListHead
);
749 InitializeListHead(&CacheSegmentLRUListHead
);
750 ExInitializeFastMutex(&ViewLock
);
751 MmInitializeMemoryConsumer(MC_CACHE
, CcRosTrimCache
);
752 CcInitCacheZeroPage();