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 *******************************************************************/
45 * If CACHE_BITMAP is defined, the cache manager uses one large memory region
46 * within the kernel address space and allocate/deallocate space from this block
47 * over a bitmap. If CACHE_BITMAP is used, the size of the mdl mapping region
48 * must be reduced (ntoskrnl\mm\mdl.c, MI_MDLMAPPING_REGION_SIZE).
50 //#define CACHE_BITMAP
52 static LIST_ENTRY DirtySegmentListHead
;
53 static LIST_ENTRY CacheSegmentListHead
;
54 static LIST_ENTRY CacheSegmentLRUListHead
;
55 static LIST_ENTRY ClosedListHead
;
56 ULONG DirtyPageCount
=0;
58 KGUARDED_MUTEX ViewLock
;
61 #define CI_CACHESEG_MAPPING_REGION_SIZE (128*1024*1024)
63 static PVOID CiCacheSegMappingRegionBase
= NULL
;
64 static RTL_BITMAP CiCacheSegMappingRegionAllocMap
;
65 static ULONG CiCacheSegMappingRegionHint
;
66 static KSPIN_LOCK CiCacheSegMappingRegionLock
;
69 NPAGED_LOOKASIDE_LIST iBcbLookasideList
;
70 static NPAGED_LOOKASIDE_LIST BcbLookasideList
;
71 static NPAGED_LOOKASIDE_LIST CacheSegLookasideList
;
74 static void CcRosCacheSegmentIncRefCount_ ( PCACHE_SEGMENT cs
, const char* file
, int line
)
79 DbgPrint("(%s:%i) CacheSegment %p ++RefCount=%d, Dirty %d, PageOut %d\n",
80 file
, line
, cs
, cs
->ReferenceCount
, cs
->Dirty
, cs
->PageOut
);
83 static void CcRosCacheSegmentDecRefCount_ ( PCACHE_SEGMENT cs
, const char* file
, int line
)
88 DbgPrint("(%s:%i) CacheSegment %p --RefCount=%d, Dirty %d, PageOut %d\n",
89 file
, line
, cs
, cs
->ReferenceCount
, cs
->Dirty
, cs
->PageOut
);
92 #define CcRosCacheSegmentIncRefCount(cs) CcRosCacheSegmentIncRefCount_(cs,__FILE__,__LINE__)
93 #define CcRosCacheSegmentDecRefCount(cs) CcRosCacheSegmentDecRefCount_(cs,__FILE__,__LINE__)
95 #define CcRosCacheSegmentIncRefCount(cs) (++((cs)->ReferenceCount))
96 #define CcRosCacheSegmentDecRefCount(cs) (--((cs)->ReferenceCount))
100 CcRosInternalFreeCacheSegment(PCACHE_SEGMENT CacheSeg
);
103 /* FUNCTIONS *****************************************************************/
113 PLIST_ENTRY current_entry
;
114 PCACHE_SEGMENT current
;
123 DPRINT1("Enabling Tracing for CacheMap 0x%p:\n", Bcb
);
125 KeAcquireGuardedMutex(&ViewLock
);
126 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
128 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
129 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
131 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
, BcbSegmentListEntry
);
132 current_entry
= current_entry
->Flink
;
134 DPRINT1(" CacheSegment 0x%p enabled, RefCount %d, Dirty %d, PageOut %d\n",
135 current
, current
->ReferenceCount
, current
->Dirty
, current
->PageOut
);
137 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
138 KeReleaseGuardedMutex(&ViewLock
);
142 DPRINT1("Disabling Tracing for CacheMap 0x%p:\n", Bcb
);
153 CcRosFlushCacheSegment(PCACHE_SEGMENT CacheSegment
)
158 Status
= WriteCacheSegment(CacheSegment
);
159 if (NT_SUCCESS(Status
))
161 KeAcquireGuardedMutex(&ViewLock
);
162 KeAcquireSpinLock(&CacheSegment
->Bcb
->BcbLock
, &oldIrql
);
164 CacheSegment
->Dirty
= FALSE
;
165 RemoveEntryList(&CacheSegment
->DirtySegmentListEntry
);
166 DirtyPageCount
-= CacheSegment
->Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
167 CcRosCacheSegmentDecRefCount ( CacheSegment
);
169 KeReleaseSpinLock(&CacheSegment
->Bcb
->BcbLock
, oldIrql
);
170 KeReleaseGuardedMutex(&ViewLock
);
178 CcRosFlushDirtyPages(ULONG Target
, PULONG Count
)
180 PLIST_ENTRY current_entry
;
181 PCACHE_SEGMENT current
;
182 ULONG PagesPerSegment
;
185 static ULONG WriteCount
[4] = {0, 0, 0, 0};
188 DPRINT("CcRosFlushDirtyPages(Target %d)\n", Target
);
192 KeEnterCriticalRegion();
193 KeAcquireGuardedMutex(&ViewLock
);
195 WriteCount
[0] = WriteCount
[1];
196 WriteCount
[1] = WriteCount
[2];
197 WriteCount
[2] = WriteCount
[3];
200 NewTarget
= WriteCount
[0] + WriteCount
[1] + WriteCount
[2];
202 if (NewTarget
< DirtyPageCount
)
204 NewTarget
= (DirtyPageCount
- NewTarget
+ 3) / 4;
205 WriteCount
[0] += NewTarget
;
206 WriteCount
[1] += NewTarget
;
207 WriteCount
[2] += NewTarget
;
208 WriteCount
[3] += NewTarget
;
211 NewTarget
= WriteCount
[0];
213 Target
= max(NewTarget
, Target
);
215 current_entry
= DirtySegmentListHead
.Flink
;
216 if (current_entry
== &DirtySegmentListHead
)
218 DPRINT("No Dirty pages\n");
221 while (current_entry
!= &DirtySegmentListHead
&& Target
> 0)
223 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
224 DirtySegmentListEntry
);
225 current_entry
= current_entry
->Flink
;
227 Locked
= current
->Bcb
->Callbacks
->AcquireForLazyWrite(
228 current
->Bcb
->LazyWriteContext
, FALSE
);
234 Locked
= ExTryToAcquirePushLockExclusive(¤t
->Lock
);
237 current
->Bcb
->Callbacks
->ReleaseFromLazyWrite(
238 current
->Bcb
->LazyWriteContext
);
243 ASSERT(current
->Dirty
);
244 if (current
->ReferenceCount
> 1)
246 ExReleasePushLock(¤t
->Lock
);
247 current
->Bcb
->Callbacks
->ReleaseFromLazyWrite(
248 current
->Bcb
->LazyWriteContext
);
252 PagesPerSegment
= current
->Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
254 KeReleaseGuardedMutex(&ViewLock
);
256 Status
= CcRosFlushCacheSegment(current
);
258 ExReleasePushLock(¤t
->Lock
);
259 current
->Bcb
->Callbacks
->ReleaseFromLazyWrite(
260 current
->Bcb
->LazyWriteContext
);
262 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
264 DPRINT1("CC: Failed to flush cache segment.\n");
268 (*Count
) += PagesPerSegment
;
269 Target
-= PagesPerSegment
;
272 KeAcquireGuardedMutex(&ViewLock
);
273 current_entry
= DirtySegmentListHead
.Flink
;
276 if (*Count
< NewTarget
)
278 WriteCount
[1] += (NewTarget
- *Count
);
281 KeReleaseGuardedMutex(&ViewLock
);
282 KeLeaveCriticalRegion();
284 DPRINT("CcRosFlushDirtyPages() finished\n");
285 return(STATUS_SUCCESS
);
289 CcRosTrimCache(ULONG Target
, ULONG Priority
, PULONG NrFreed
)
291 * FUNCTION: Try to free some memory from the file cache.
293 * Target - The number of pages to be freed.
294 * Priority - The priority of free (currently unused).
295 * NrFreed - Points to a variable where the number of pages
296 * actually freed is returned.
299 PLIST_ENTRY current_entry
;
300 PCACHE_SEGMENT current
;
301 ULONG PagesPerSegment
;
306 DPRINT("CcRosTrimCache(Target %d)\n", Target
);
310 InitializeListHead(&FreeList
);
312 KeAcquireGuardedMutex(&ViewLock
);
313 current_entry
= CacheSegmentLRUListHead
.Flink
;
314 while (current_entry
!= &CacheSegmentLRUListHead
&& Target
> 0)
316 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
317 CacheSegmentLRUListEntry
);
318 current_entry
= current_entry
->Flink
;
320 KeAcquireSpinLock(¤t
->Bcb
->BcbLock
, &oldIrql
);
322 if (current
->MappedCount
> 0 && !current
->Dirty
&& !current
->PageOut
)
326 CcRosCacheSegmentIncRefCount(current
);
327 current
->PageOut
= TRUE
;
328 KeReleaseSpinLock(¤t
->Bcb
->BcbLock
, oldIrql
);
329 KeReleaseGuardedMutex(&ViewLock
);
330 for (i
= 0; i
< current
->Bcb
->CacheSegmentSize
/ PAGE_SIZE
; i
++)
333 Page
= (PFN_NUMBER
)(MmGetPhysicalAddress((char*)current
->BaseAddress
+ i
* PAGE_SIZE
).QuadPart
>> PAGE_SHIFT
);
334 MmPageOutPhysicalAddress(Page
);
336 KeAcquireGuardedMutex(&ViewLock
);
337 KeAcquireSpinLock(¤t
->Bcb
->BcbLock
, &oldIrql
);
338 CcRosCacheSegmentDecRefCount(current
);
341 if (current
->ReferenceCount
== 0)
343 PagesPerSegment
= current
->Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
344 // PagesFreed = PagesPerSegment;
345 PagesFreed
= min(PagesPerSegment
, Target
);
346 Target
-= PagesFreed
;
347 (*NrFreed
) += PagesFreed
;
350 KeReleaseSpinLock(¤t
->Bcb
->BcbLock
, oldIrql
);
353 current_entry
= CacheSegmentLRUListHead
.Flink
;
354 while (current_entry
!= &CacheSegmentLRUListHead
)
356 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
357 CacheSegmentLRUListEntry
);
358 current
->PageOut
= FALSE
;
359 current_entry
= current_entry
->Flink
;
361 KeAcquireSpinLock(¤t
->Bcb
->BcbLock
, &oldIrql
);
362 if (current
->ReferenceCount
== 0)
364 RemoveEntryList(¤t
->BcbSegmentListEntry
);
365 KeReleaseSpinLock(¤t
->Bcb
->BcbLock
, oldIrql
);
366 RemoveEntryList(¤t
->CacheSegmentListEntry
);
367 RemoveEntryList(¤t
->CacheSegmentLRUListEntry
);
368 InsertHeadList(&FreeList
, ¤t
->BcbSegmentListEntry
);
372 KeReleaseSpinLock(¤t
->Bcb
->BcbLock
, oldIrql
);
376 KeReleaseGuardedMutex(&ViewLock
);
378 while (!IsListEmpty(&FreeList
))
380 current_entry
= RemoveHeadList(&FreeList
);
381 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
382 BcbSegmentListEntry
);
383 CcRosInternalFreeCacheSegment(current
);
386 return(STATUS_SUCCESS
);
391 CcRosReleaseCacheSegment(PBCB Bcb
,
392 PCACHE_SEGMENT CacheSeg
,
397 BOOLEAN WasDirty
= CacheSeg
->Dirty
;
402 DPRINT("CcReleaseCacheSegment(Bcb 0x%p, CacheSeg 0x%p, Valid %d)\n",
403 Bcb
, CacheSeg
, Valid
);
405 CacheSeg
->Valid
= Valid
;
406 CacheSeg
->Dirty
= CacheSeg
->Dirty
|| Dirty
;
408 KeAcquireGuardedMutex(&ViewLock
);
409 if (!WasDirty
&& CacheSeg
->Dirty
)
411 InsertTailList(&DirtySegmentListHead
, &CacheSeg
->DirtySegmentListEntry
);
412 DirtyPageCount
+= Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
414 RemoveEntryList(&CacheSeg
->CacheSegmentLRUListEntry
);
415 InsertTailList(&CacheSegmentLRUListHead
, &CacheSeg
->CacheSegmentLRUListEntry
);
419 CacheSeg
->MappedCount
++;
421 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
422 CcRosCacheSegmentDecRefCount(CacheSeg
);
423 if (Mapped
&& CacheSeg
->MappedCount
== 1)
425 CcRosCacheSegmentIncRefCount(CacheSeg
);
427 if (!WasDirty
&& CacheSeg
->Dirty
)
429 CcRosCacheSegmentIncRefCount(CacheSeg
);
431 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
432 KeReleaseGuardedMutex(&ViewLock
);
433 ExReleasePushLock(&CacheSeg
->Lock
);
435 return(STATUS_SUCCESS
);
438 /* Returns with Cache Segment Lock Held! */
441 CcRosLookupCacheSegment(PBCB Bcb
, ULONG FileOffset
)
443 PLIST_ENTRY current_entry
;
444 PCACHE_SEGMENT current
;
449 DPRINT("CcRosLookupCacheSegment(Bcb -x%p, FileOffset %d)\n", Bcb
, FileOffset
);
451 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
452 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
453 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
455 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
456 BcbSegmentListEntry
);
457 if (current
->FileOffset
<= FileOffset
&&
458 (current
->FileOffset
+ Bcb
->CacheSegmentSize
) > FileOffset
)
460 CcRosCacheSegmentIncRefCount(current
);
461 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
462 ExAcquirePushLockExclusive(¤t
->Lock
);
465 current_entry
= current_entry
->Flink
;
467 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
473 CcRosMarkDirtyCacheSegment(PBCB Bcb
, ULONG FileOffset
)
475 PCACHE_SEGMENT CacheSeg
;
480 DPRINT("CcRosMarkDirtyCacheSegment(Bcb 0x%p, FileOffset %d)\n", Bcb
, FileOffset
);
482 CacheSeg
= CcRosLookupCacheSegment(Bcb
, FileOffset
);
483 if (CacheSeg
== NULL
)
485 KeBugCheck(CACHE_MANAGER
);
487 if (!CacheSeg
->Dirty
)
489 KeAcquireGuardedMutex(&ViewLock
);
490 InsertTailList(&DirtySegmentListHead
, &CacheSeg
->DirtySegmentListEntry
);
491 DirtyPageCount
+= Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
492 KeReleaseGuardedMutex(&ViewLock
);
496 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
497 CcRosCacheSegmentDecRefCount(CacheSeg
);
498 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
502 CacheSeg
->Dirty
= TRUE
;
503 ExReleasePushLock(&CacheSeg
->Lock
);
505 return(STATUS_SUCCESS
);
510 CcRosUnmapCacheSegment(PBCB Bcb
, ULONG FileOffset
, BOOLEAN NowDirty
)
512 PCACHE_SEGMENT CacheSeg
;
518 DPRINT("CcRosUnmapCacheSegment(Bcb 0x%p, FileOffset %d, NowDirty %d)\n",
519 Bcb
, FileOffset
, NowDirty
);
521 CacheSeg
= CcRosLookupCacheSegment(Bcb
, FileOffset
);
522 if (CacheSeg
== NULL
)
524 return(STATUS_UNSUCCESSFUL
);
527 WasDirty
= CacheSeg
->Dirty
;
528 CacheSeg
->Dirty
= CacheSeg
->Dirty
|| NowDirty
;
530 CacheSeg
->MappedCount
--;
532 if (!WasDirty
&& NowDirty
)
534 KeAcquireGuardedMutex(&ViewLock
);
535 InsertTailList(&DirtySegmentListHead
, &CacheSeg
->DirtySegmentListEntry
);
536 DirtyPageCount
+= Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
537 KeReleaseGuardedMutex(&ViewLock
);
540 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
541 CcRosCacheSegmentDecRefCount(CacheSeg
);
542 if (!WasDirty
&& NowDirty
)
544 CcRosCacheSegmentIncRefCount(CacheSeg
);
546 if (CacheSeg
->MappedCount
== 0)
548 CcRosCacheSegmentDecRefCount(CacheSeg
);
550 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
552 ExReleasePushLock(&CacheSeg
->Lock
);
553 return(STATUS_SUCCESS
);
558 CcRosCreateCacheSegment(PBCB Bcb
,
560 PCACHE_SEGMENT
* CacheSeg
)
562 PCACHE_SEGMENT current
;
563 PCACHE_SEGMENT previous
;
564 PLIST_ENTRY current_entry
;
568 ULONG StartingOffset
;
570 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
574 DPRINT("CcRosCreateCacheSegment()\n");
576 BoundaryAddressMultiple
.QuadPart
= 0;
577 if (FileOffset
>= Bcb
->FileSize
.u
.LowPart
)
580 return STATUS_INVALID_PARAMETER
;
583 current
= ExAllocateFromNPagedLookasideList(&CacheSegLookasideList
);
584 current
->Valid
= FALSE
;
585 current
->Dirty
= FALSE
;
586 current
->PageOut
= FALSE
;
587 current
->FileOffset
= ROUND_DOWN(FileOffset
, Bcb
->CacheSegmentSize
);
592 DPRINT1("CacheMap 0x%p: new Cache Segment: 0x%p\n", Bcb
, current
);
595 current
->MappedCount
= 0;
596 current
->DirtySegmentListEntry
.Flink
= NULL
;
597 current
->DirtySegmentListEntry
.Blink
= NULL
;
598 current
->ReferenceCount
= 1;
599 ExInitializePushLock((PULONG_PTR
)¤t
->Lock
);
600 ExAcquirePushLockExclusive(¤t
->Lock
);
601 KeAcquireGuardedMutex(&ViewLock
);
604 /* There is window between the call to CcRosLookupCacheSegment
605 * and CcRosCreateCacheSegment. We must check if a segment on
606 * the fileoffset exist. If there exist a segment, we release
607 * our new created segment and return the existing one.
609 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
610 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
612 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
614 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
615 BcbSegmentListEntry
);
616 if (current
->FileOffset
<= FileOffset
&&
617 (current
->FileOffset
+ Bcb
->CacheSegmentSize
) > FileOffset
)
619 CcRosCacheSegmentIncRefCount(current
);
620 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
624 DPRINT1("CacheMap 0x%p: deleting newly created Cache Segment 0x%p ( found existing one 0x%p )\n",
630 ExReleasePushLock(&(*CacheSeg
)->Lock
);
631 KeReleaseGuardedMutex(&ViewLock
);
632 ExFreeToNPagedLookasideList(&CacheSegLookasideList
, *CacheSeg
);
634 ExAcquirePushLockExclusive(¤t
->Lock
);
635 return STATUS_SUCCESS
;
637 if (current
->FileOffset
< FileOffset
)
639 if (previous
== NULL
)
645 if (previous
->FileOffset
< current
->FileOffset
)
651 current_entry
= current_entry
->Flink
;
653 /* There was no existing segment. */
657 InsertHeadList(&previous
->BcbSegmentListEntry
, ¤t
->BcbSegmentListEntry
);
661 InsertHeadList(&Bcb
->BcbSegmentListHead
, ¤t
->BcbSegmentListEntry
);
663 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
664 InsertTailList(&CacheSegmentListHead
, ¤t
->CacheSegmentListEntry
);
665 InsertTailList(&CacheSegmentLRUListHead
, ¤t
->CacheSegmentLRUListEntry
);
666 KeReleaseGuardedMutex(&ViewLock
);
668 KeAcquireSpinLock(&CiCacheSegMappingRegionLock
, &oldIrql
);
670 StartingOffset
= RtlFindClearBitsAndSet(&CiCacheSegMappingRegionAllocMap
, Bcb
->CacheSegmentSize
/ PAGE_SIZE
, CiCacheSegMappingRegionHint
);
672 if (StartingOffset
== 0xffffffff)
674 DPRINT1("Out of CacheSeg mapping space\n");
675 KeBugCheck(CACHE_MANAGER
);
678 current
->BaseAddress
= CiCacheSegMappingRegionBase
+ StartingOffset
* PAGE_SIZE
;
680 if (CiCacheSegMappingRegionHint
== StartingOffset
)
682 CiCacheSegMappingRegionHint
+= Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
685 KeReleaseSpinLock(&CiCacheSegMappingRegionLock
, oldIrql
);
687 MmLockAddressSpace(MmGetKernelAddressSpace());
688 current
->BaseAddress
= NULL
;
689 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
690 0, // nothing checks for cache_segment mareas, so set to 0
691 ¤t
->BaseAddress
,
692 Bcb
->CacheSegmentSize
,
694 (PMEMORY_AREA
*)¤t
->MemoryArea
,
697 BoundaryAddressMultiple
);
698 MmUnlockAddressSpace(MmGetKernelAddressSpace());
699 if (!NT_SUCCESS(Status
))
701 KeBugCheck(CACHE_MANAGER
);
705 /* Create a virtual mapping for this memory area */
706 MI_SET_USAGE(MI_USAGE_CACHE
);
710 if ((Bcb
->FileObject
) && (Bcb
->FileObject
->FileName
.Buffer
))
712 pos
= wcsrchr(Bcb
->FileObject
->FileName
.Buffer
, '\\');
713 len
= wcslen(pos
) * sizeof(WCHAR
);
714 if (pos
) snprintf(MI_PFN_CURRENT_PROCESS_NAME
, min(16, len
), "%S", pos
);
718 MmMapMemoryArea(current
->BaseAddress
, Bcb
->CacheSegmentSize
,
719 MC_CACHE
, PAGE_READWRITE
);
721 return(STATUS_SUCCESS
);
726 CcRosGetCacheSegmentChain(PBCB Bcb
,
729 PCACHE_SEGMENT
* CacheSeg
)
731 PCACHE_SEGMENT current
;
733 PCACHE_SEGMENT
* CacheSegList
;
734 PCACHE_SEGMENT Previous
= NULL
;
738 DPRINT("CcRosGetCacheSegmentChain()\n");
740 Length
= ROUND_UP(Length
, Bcb
->CacheSegmentSize
);
742 CacheSegList
= _alloca(sizeof(PCACHE_SEGMENT
) *
743 (Length
/ Bcb
->CacheSegmentSize
));
746 * Look for a cache segment already mapping the same data.
748 for (i
= 0; i
< (Length
/ Bcb
->CacheSegmentSize
); i
++)
750 ULONG CurrentOffset
= FileOffset
+ (i
* Bcb
->CacheSegmentSize
);
751 current
= CcRosLookupCacheSegment(Bcb
, CurrentOffset
);
754 CacheSegList
[i
] = current
;
758 CcRosCreateCacheSegment(Bcb
, CurrentOffset
, ¤t
);
759 CacheSegList
[i
] = current
;
763 for (i
= 0; i
< (Length
/ Bcb
->CacheSegmentSize
); i
++)
767 *CacheSeg
= CacheSegList
[i
];
768 Previous
= CacheSegList
[i
];
772 Previous
->NextInChain
= CacheSegList
[i
];
773 Previous
= CacheSegList
[i
];
777 Previous
->NextInChain
= NULL
;
779 return(STATUS_SUCCESS
);
784 CcRosGetCacheSegment(PBCB Bcb
,
789 PCACHE_SEGMENT
* CacheSeg
)
791 PCACHE_SEGMENT current
;
796 DPRINT("CcRosGetCacheSegment()\n");
799 * Look for a cache segment already mapping the same data.
801 current
= CcRosLookupCacheSegment(Bcb
, FileOffset
);
805 * Otherwise create a new segment.
807 Status
= CcRosCreateCacheSegment(Bcb
, FileOffset
, ¤t
);
808 if (!NT_SUCCESS(Status
))
814 * Return information about the segment to the caller.
816 *UptoDate
= current
->Valid
;
817 *BaseAddress
= current
->BaseAddress
;
818 DPRINT("*BaseAddress 0x%.8X\n", *BaseAddress
);
820 *BaseOffset
= current
->FileOffset
;
821 return(STATUS_SUCCESS
);
825 CcRosRequestCacheSegment(PBCB Bcb
,
829 PCACHE_SEGMENT
* CacheSeg
)
831 * FUNCTION: Request a page mapping for a BCB
838 if ((FileOffset
% Bcb
->CacheSegmentSize
) != 0)
840 DPRINT1("Bad fileoffset %x should be multiple of %x",
841 FileOffset
, Bcb
->CacheSegmentSize
);
842 KeBugCheck(CACHE_MANAGER
);
845 return(CcRosGetCacheSegment(Bcb
,
855 CcFreeCachePage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
856 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
858 ASSERT(SwapEntry
== 0);
861 MmReleasePageMemoryConsumer(MC_CACHE
, Page
);
866 CcRosInternalFreeCacheSegment(PCACHE_SEGMENT CacheSeg
)
868 * FUNCTION: Releases a cache segment associated with a BCB
878 DPRINT("Freeing cache segment 0x%p\n", CacheSeg
);
880 if ( CacheSeg
->Bcb
->Trace
)
882 DPRINT1("CacheMap 0x%p: deleting Cache Segment: 0x%p\n", CacheSeg
->Bcb
, CacheSeg
);
886 RegionSize
= CacheSeg
->Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
888 /* Unmap all the pages. */
889 for (i
= 0; i
< RegionSize
; i
++)
891 MmDeleteVirtualMapping(NULL
,
892 CacheSeg
->BaseAddress
+ (i
* PAGE_SIZE
),
896 MmReleasePageMemoryConsumer(MC_CACHE
, Page
);
899 KeAcquireSpinLock(&CiCacheSegMappingRegionLock
, &oldIrql
);
900 /* Deallocate all the pages used. */
901 Base
= (ULONG
)(CacheSeg
->BaseAddress
- CiCacheSegMappingRegionBase
) / PAGE_SIZE
;
903 RtlClearBits(&CiCacheSegMappingRegionAllocMap
, Base
, RegionSize
);
905 CiCacheSegMappingRegionHint
= min (CiCacheSegMappingRegionHint
, Base
);
907 KeReleaseSpinLock(&CiCacheSegMappingRegionLock
, oldIrql
);
909 MmLockAddressSpace(MmGetKernelAddressSpace());
910 MmFreeMemoryArea(MmGetKernelAddressSpace(),
911 CacheSeg
->MemoryArea
,
914 MmUnlockAddressSpace(MmGetKernelAddressSpace());
916 ExFreeToNPagedLookasideList(&CacheSegLookasideList
, CacheSeg
);
917 return(STATUS_SUCCESS
);
922 CcRosFreeCacheSegment(PBCB Bcb
, PCACHE_SEGMENT CacheSeg
)
929 DPRINT("CcRosFreeCacheSegment(Bcb 0x%p, CacheSeg 0x%p)\n",
932 KeAcquireGuardedMutex(&ViewLock
);
933 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
934 RemoveEntryList(&CacheSeg
->BcbSegmentListEntry
);
935 RemoveEntryList(&CacheSeg
->CacheSegmentListEntry
);
936 RemoveEntryList(&CacheSeg
->CacheSegmentLRUListEntry
);
939 RemoveEntryList(&CacheSeg
->DirtySegmentListEntry
);
940 DirtyPageCount
-= Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
943 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
944 KeReleaseGuardedMutex(&ViewLock
);
946 Status
= CcRosInternalFreeCacheSegment(CacheSeg
);
954 CcFlushCache(IN PSECTION_OBJECT_POINTERS SectionObjectPointers
,
955 IN PLARGE_INTEGER FileOffset OPTIONAL
,
957 OUT PIO_STATUS_BLOCK IoStatus
)
960 LARGE_INTEGER Offset
;
961 PCACHE_SEGMENT current
;
965 DPRINT("CcFlushCache(SectionObjectPointers 0x%p, FileOffset 0x%p, Length %d, IoStatus 0x%p)\n",
966 SectionObjectPointers
, FileOffset
, Length
, IoStatus
);
968 if (SectionObjectPointers
&& SectionObjectPointers
->SharedCacheMap
)
970 Bcb
= (PBCB
)SectionObjectPointers
->SharedCacheMap
;
974 Offset
= *FileOffset
;
978 Offset
.QuadPart
= (LONGLONG
)0;
979 Length
= Bcb
->FileSize
.u
.LowPart
;
984 IoStatus
->Status
= STATUS_SUCCESS
;
985 IoStatus
->Information
= 0;
990 current
= CcRosLookupCacheSegment (Bcb
, Offset
.u
.LowPart
);
995 Status
= CcRosFlushCacheSegment(current
);
996 if (!NT_SUCCESS(Status
) && IoStatus
!= NULL
)
998 IoStatus
->Status
= Status
;
1001 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
1002 ExReleasePushLock(¤t
->Lock
);
1003 CcRosCacheSegmentDecRefCount(current
);
1004 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
1007 Offset
.QuadPart
+= Bcb
->CacheSegmentSize
;
1008 if (Length
> Bcb
->CacheSegmentSize
)
1010 Length
-= Bcb
->CacheSegmentSize
;
1022 IoStatus
->Status
= STATUS_INVALID_PARAMETER
;
1029 CcRosDeleteFileCache(PFILE_OBJECT FileObject
, PBCB Bcb
)
1031 * FUNCTION: Releases the BCB associated with a file object
1034 PLIST_ENTRY current_entry
;
1035 PCACHE_SEGMENT current
;
1036 LIST_ENTRY FreeList
;
1042 KeReleaseGuardedMutex(&ViewLock
);
1044 CcFlushCache(FileObject
->SectionObjectPointer
, NULL
, 0, NULL
);
1046 KeAcquireGuardedMutex(&ViewLock
);
1048 if (Bcb
->RefCount
== 0)
1050 if (Bcb
->BcbRemoveListEntry
.Flink
!= NULL
)
1052 RemoveEntryList(&Bcb
->BcbRemoveListEntry
);
1053 Bcb
->BcbRemoveListEntry
.Flink
= NULL
;
1056 FileObject
->SectionObjectPointer
->SharedCacheMap
= NULL
;
1059 * Release all cache segments.
1061 InitializeListHead(&FreeList
);
1062 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
1063 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
1064 while (!IsListEmpty(&Bcb
->BcbSegmentListHead
))
1066 current_entry
= RemoveTailList(&Bcb
->BcbSegmentListHead
);
1067 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
, BcbSegmentListEntry
);
1068 RemoveEntryList(¤t
->CacheSegmentListEntry
);
1069 RemoveEntryList(¤t
->CacheSegmentLRUListEntry
);
1072 RemoveEntryList(¤t
->DirtySegmentListEntry
);
1073 DirtyPageCount
-= Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
1074 DPRINT1("Freeing dirty segment\n");
1076 InsertHeadList(&FreeList
, ¤t
->BcbSegmentListEntry
);
1081 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
1083 KeReleaseGuardedMutex(&ViewLock
);
1084 ObDereferenceObject (Bcb
->FileObject
);
1086 while (!IsListEmpty(&FreeList
))
1088 current_entry
= RemoveTailList(&FreeList
);
1089 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
, BcbSegmentListEntry
);
1090 CcRosInternalFreeCacheSegment(current
);
1092 ExFreeToNPagedLookasideList(&BcbLookasideList
, Bcb
);
1093 KeAcquireGuardedMutex(&ViewLock
);
1095 return(STATUS_SUCCESS
);
1100 CcRosReferenceCache(PFILE_OBJECT FileObject
)
1103 KeAcquireGuardedMutex(&ViewLock
);
1104 Bcb
= (PBCB
)FileObject
->SectionObjectPointer
->SharedCacheMap
;
1106 if (Bcb
->RefCount
== 0)
1108 ASSERT(Bcb
->BcbRemoveListEntry
.Flink
!= NULL
);
1109 RemoveEntryList(&Bcb
->BcbRemoveListEntry
);
1110 Bcb
->BcbRemoveListEntry
.Flink
= NULL
;
1115 ASSERT(Bcb
->BcbRemoveListEntry
.Flink
== NULL
);
1118 KeReleaseGuardedMutex(&ViewLock
);
1123 CcRosSetRemoveOnClose(PSECTION_OBJECT_POINTERS SectionObjectPointer
)
1126 DPRINT("CcRosSetRemoveOnClose()\n");
1127 KeAcquireGuardedMutex(&ViewLock
);
1128 Bcb
= (PBCB
)SectionObjectPointer
->SharedCacheMap
;
1131 Bcb
->RemoveOnClose
= TRUE
;
1132 if (Bcb
->RefCount
== 0)
1134 CcRosDeleteFileCache(Bcb
->FileObject
, Bcb
);
1137 KeReleaseGuardedMutex(&ViewLock
);
1143 CcRosDereferenceCache(PFILE_OBJECT FileObject
)
1146 KeAcquireGuardedMutex(&ViewLock
);
1147 Bcb
= (PBCB
)FileObject
->SectionObjectPointer
->SharedCacheMap
;
1149 if (Bcb
->RefCount
> 0)
1152 if (Bcb
->RefCount
== 0)
1154 MmFreeSectionSegments(Bcb
->FileObject
);
1155 CcRosDeleteFileCache(FileObject
, Bcb
);
1158 KeReleaseGuardedMutex(&ViewLock
);
1162 CcRosReleaseFileCache(PFILE_OBJECT FileObject
)
1164 * FUNCTION: Called by the file system when a handle to a file object
1170 KeAcquireGuardedMutex(&ViewLock
);
1172 if (FileObject
->SectionObjectPointer
->SharedCacheMap
!= NULL
)
1174 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1175 if (FileObject
->PrivateCacheMap
!= NULL
)
1177 FileObject
->PrivateCacheMap
= NULL
;
1178 if (Bcb
->RefCount
> 0)
1181 if (Bcb
->RefCount
== 0)
1183 MmFreeSectionSegments(Bcb
->FileObject
);
1184 CcRosDeleteFileCache(FileObject
, Bcb
);
1189 KeReleaseGuardedMutex(&ViewLock
);
1190 return(STATUS_SUCCESS
);
1195 CcTryToInitializeFileCache(PFILE_OBJECT FileObject
)
1200 KeAcquireGuardedMutex(&ViewLock
);
1202 ASSERT(FileObject
->SectionObjectPointer
);
1203 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1206 Status
= STATUS_UNSUCCESSFUL
;
1210 if (FileObject
->PrivateCacheMap
== NULL
)
1212 FileObject
->PrivateCacheMap
= Bcb
;
1215 if (Bcb
->BcbRemoveListEntry
.Flink
!= NULL
)
1217 RemoveEntryList(&Bcb
->BcbRemoveListEntry
);
1218 Bcb
->BcbRemoveListEntry
.Flink
= NULL
;
1220 Status
= STATUS_SUCCESS
;
1222 KeReleaseGuardedMutex(&ViewLock
);
1229 CcRosInitializeFileCache(PFILE_OBJECT FileObject
,
1230 ULONG CacheSegmentSize
,
1231 PCACHE_MANAGER_CALLBACKS CallBacks
,
1232 PVOID LazyWriterContext
)
1234 * FUNCTION: Initializes a BCB for a file object
1239 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1240 DPRINT("CcRosInitializeFileCache(FileObject 0x%p, Bcb 0x%p, CacheSegmentSize %d)\n",
1241 FileObject
, Bcb
, CacheSegmentSize
);
1243 KeAcquireGuardedMutex(&ViewLock
);
1246 Bcb
= ExAllocateFromNPagedLookasideList(&BcbLookasideList
);
1249 KeReleaseGuardedMutex(&ViewLock
);
1250 return(STATUS_UNSUCCESSFUL
);
1252 memset(Bcb
, 0, sizeof(BCB
));
1253 ObReferenceObjectByPointer(FileObject
,
1257 Bcb
->FileObject
= FileObject
;
1258 Bcb
->CacheSegmentSize
= CacheSegmentSize
;
1259 Bcb
->Callbacks
= CallBacks
;
1260 Bcb
->LazyWriteContext
= LazyWriterContext
;
1261 if (FileObject
->FsContext
)
1263 Bcb
->AllocationSize
=
1264 ((PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)->AllocationSize
;
1266 ((PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)->FileSize
;
1268 KeInitializeSpinLock(&Bcb
->BcbLock
);
1269 InitializeListHead(&Bcb
->BcbSegmentListHead
);
1270 FileObject
->SectionObjectPointer
->SharedCacheMap
= Bcb
;
1272 if (FileObject
->PrivateCacheMap
== NULL
)
1274 FileObject
->PrivateCacheMap
= Bcb
;
1277 if (Bcb
->BcbRemoveListEntry
.Flink
!= NULL
)
1279 RemoveEntryList(&Bcb
->BcbRemoveListEntry
);
1280 Bcb
->BcbRemoveListEntry
.Flink
= NULL
;
1282 KeReleaseGuardedMutex(&ViewLock
);
1284 return(STATUS_SUCCESS
);
1291 CcGetFileObjectFromSectionPtrs(IN PSECTION_OBJECT_POINTERS SectionObjectPointers
)
1294 if (SectionObjectPointers
&& SectionObjectPointers
->SharedCacheMap
)
1296 Bcb
= (PBCB
)SectionObjectPointers
->SharedCacheMap
;
1298 return Bcb
->FileObject
;
1311 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
1314 DPRINT("CcInitView()\n");
1316 BoundaryAddressMultiple
.QuadPart
= 0;
1317 CiCacheSegMappingRegionHint
= 0;
1318 CiCacheSegMappingRegionBase
= NULL
;
1320 MmLockAddressSpace(MmGetKernelAddressSpace());
1322 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
1323 MEMORY_AREA_CACHE_SEGMENT
,
1324 &CiCacheSegMappingRegionBase
,
1325 CI_CACHESEG_MAPPING_REGION_SIZE
,
1330 BoundaryAddressMultiple
);
1331 MmUnlockAddressSpace(MmGetKernelAddressSpace());
1332 if (!NT_SUCCESS(Status
))
1334 KeBugCheck(CACHE_MANAGER
);
1337 Buffer
= ExAllocatePool(NonPagedPool
, CI_CACHESEG_MAPPING_REGION_SIZE
/ (PAGE_SIZE
* 8));
1340 KeBugCheck(CACHE_MANAGER
);
1343 RtlInitializeBitMap(&CiCacheSegMappingRegionAllocMap
, Buffer
, CI_CACHESEG_MAPPING_REGION_SIZE
/ PAGE_SIZE
);
1344 RtlClearAllBits(&CiCacheSegMappingRegionAllocMap
);
1346 KeInitializeSpinLock(&CiCacheSegMappingRegionLock
);
1348 InitializeListHead(&CacheSegmentListHead
);
1349 InitializeListHead(&DirtySegmentListHead
);
1350 InitializeListHead(&CacheSegmentLRUListHead
);
1351 InitializeListHead(&ClosedListHead
);
1352 KeInitializeGuardedMutex(&ViewLock
);
1353 ExInitializeNPagedLookasideList (&iBcbLookasideList
,
1357 sizeof(INTERNAL_BCB
),
1360 ExInitializeNPagedLookasideList (&BcbLookasideList
,
1367 ExInitializeNPagedLookasideList (&CacheSegLookasideList
,
1371 sizeof(CACHE_SEGMENT
),
1375 MmInitializeMemoryConsumer(MC_CACHE
, CcRosTrimCache
);
1377 CcInitCacheZeroPage();