3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/cc/view.c
6 * PURPOSE: Cache manager
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
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 ******************************************************************/
37 #include <internal/debug.h>
39 /* GLOBALS *******************************************************************/
42 * If CACHE_BITMAP is defined, the cache manager uses one large memory region
43 * within the kernel address space and allocate/deallocate space from this block
44 * over a bitmap. If CACHE_BITMAP is used, the size of the mdl mapping region
45 * must be reduced (ntoskrnl\mm\mdl.c, MI_MDLMAPPING_REGION_SIZE).
47 //#define CACHE_BITMAP
49 static LIST_ENTRY DirtySegmentListHead
;
50 static LIST_ENTRY CacheSegmentListHead
;
51 static LIST_ENTRY CacheSegmentLRUListHead
;
52 static LIST_ENTRY ClosedListHead
;
53 ULONG DirtyPageCount
=0;
58 #define CI_CACHESEG_MAPPING_REGION_SIZE (128*1024*1024)
60 static PVOID CiCacheSegMappingRegionBase
= NULL
;
61 static RTL_BITMAP CiCacheSegMappingRegionAllocMap
;
62 static ULONG CiCacheSegMappingRegionHint
;
63 static KSPIN_LOCK CiCacheSegMappingRegionLock
;
66 NPAGED_LOOKASIDE_LIST iBcbLookasideList
;
67 static NPAGED_LOOKASIDE_LIST BcbLookasideList
;
68 static NPAGED_LOOKASIDE_LIST CacheSegLookasideList
;
70 static ULONG CcTimeStamp
;
71 static KEVENT LazyCloseThreadEvent
;
72 static HANDLE LazyCloseThreadHandle
;
73 static CLIENT_ID LazyCloseThreadId
;
74 static volatile BOOLEAN LazyCloseThreadShouldTerminate
;
77 /* void * alloca(size_t size); */
78 #elif defined(_MSC_VER)
79 void* _alloca(size_t size
);
81 #error Unknown compiler for alloca intrinsic stack allocation "function"
84 #if defined(DBG) || defined(KDBG)
85 static void CcRosCacheSegmentIncRefCount ( PCACHE_SEGMENT cs
)
90 DPRINT1("CacheSegment %p ++RefCount=%d, Dirty %d, PageOut %d\n",
91 cs
, cs
->ReferenceCount
, cs
->Dirty
, cs
->PageOut
);
94 static void CcRosCacheSegmentDecRefCount ( PCACHE_SEGMENT cs
)
99 DPRINT1("CacheSegment %p --RefCount=%d, Dirty %d, PageOut %d\n",
100 cs
, cs
->ReferenceCount
, cs
->Dirty
, cs
->PageOut
);
104 #define CcRosCacheSegmentIncRefCount(cs) (++((cs)->ReferenceCount))
105 #define CcRosCacheSegmentDecRefCount(cs) (--((cs)->ReferenceCount))
109 CcRosInternalFreeCacheSegment(PCACHE_SEGMENT CacheSeg
);
111 /* FUNCTIONS *****************************************************************/
119 #if defined(DBG) || defined(KDBG)
121 PLIST_ENTRY current_entry
;
122 PCACHE_SEGMENT current
;
131 DPRINT1("Enabling Tracing for CacheMap 0x%p:\n", Bcb
);
133 ExAcquireFastMutex(&ViewLock
);
134 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
136 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
137 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
139 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
, BcbSegmentListEntry
);
140 current_entry
= current_entry
->Flink
;
142 DPRINT1(" CacheSegment 0x%p enabled, RefCount %d, Dirty %d, PageOut %d\n",
143 current
, current
->ReferenceCount
, current
->Dirty
, current
->PageOut
);
145 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
146 ExReleaseFastMutex(&ViewLock
);
150 DPRINT1("Disabling Tracing for CacheMap 0x%p:\n", Bcb
);
160 CcRosFlushCacheSegment(PCACHE_SEGMENT CacheSegment
)
164 Status
= WriteCacheSegment(CacheSegment
);
165 if (NT_SUCCESS(Status
))
167 ExAcquireFastMutex(&ViewLock
);
168 KeAcquireSpinLock(&CacheSegment
->Bcb
->BcbLock
, &oldIrql
);
169 CacheSegment
->Dirty
= FALSE
;
170 RemoveEntryList(&CacheSegment
->DirtySegmentListEntry
);
171 DirtyPageCount
-= CacheSegment
->Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
172 CcRosCacheSegmentDecRefCount ( CacheSegment
);
173 KeReleaseSpinLock(&CacheSegment
->Bcb
->BcbLock
, oldIrql
);
174 ExReleaseFastMutex(&ViewLock
);
180 CcRosFlushDirtyPages(ULONG Target
, PULONG Count
)
182 PLIST_ENTRY current_entry
;
183 PCACHE_SEGMENT current
;
184 ULONG PagesPerSegment
;
187 static ULONG WriteCount
[4] = {0, 0, 0, 0};
190 DPRINT("CcRosFlushDirtyPages(Target %d)\n", Target
);
194 ExAcquireFastMutex(&ViewLock
);
196 WriteCount
[0] = WriteCount
[1];
197 WriteCount
[1] = WriteCount
[2];
198 WriteCount
[2] = WriteCount
[3];
201 NewTarget
= WriteCount
[0] + WriteCount
[1] + WriteCount
[2];
203 if (NewTarget
< DirtyPageCount
)
205 NewTarget
= (DirtyPageCount
- NewTarget
+ 3) / 4;
206 WriteCount
[0] += NewTarget
;
207 WriteCount
[1] += NewTarget
;
208 WriteCount
[2] += NewTarget
;
209 WriteCount
[3] += NewTarget
;
212 NewTarget
= WriteCount
[0];
214 Target
= max(NewTarget
, Target
);
216 current_entry
= DirtySegmentListHead
.Flink
;
217 if (current_entry
== &DirtySegmentListHead
)
219 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
;
226 Locked
= ExTryToAcquireFastMutex(¤t
->Lock
);
231 ASSERT(current
->Dirty
);
232 if (current
->ReferenceCount
> 1)
234 ExReleaseFastMutex(¤t
->Lock
);
237 ExReleaseFastMutex(&ViewLock
);
238 PagesPerSegment
= current
->Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
239 Status
= CcRosFlushCacheSegment(current
);
240 ExReleaseFastMutex(¤t
->Lock
);
241 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
243 DPRINT1("CC: Failed to flush cache segment.\n");
247 (*Count
) += PagesPerSegment
;
248 Target
-= PagesPerSegment
;
250 ExAcquireFastMutex(&ViewLock
);
251 current_entry
= DirtySegmentListHead
.Flink
;
253 if (*Count
< NewTarget
)
255 WriteCount
[1] += (NewTarget
- *Count
);
257 ExReleaseFastMutex(&ViewLock
);
258 DPRINT("CcRosFlushDirtyPages() finished\n");
260 return(STATUS_SUCCESS
);
264 CcRosTrimCache(ULONG Target
, ULONG Priority
, PULONG NrFreed
)
266 * FUNCTION: Try to free some memory from the file cache.
268 * Target - The number of pages to be freed.
269 * Priority - The priority of free (currently unused).
270 * NrFreed - Points to a variable where the number of pages
271 * actually freed is returned.
274 PLIST_ENTRY current_entry
;
275 PCACHE_SEGMENT current
, last
= NULL
;
276 ULONG PagesPerSegment
;
281 DPRINT("CcRosTrimCache(Target %d)\n", Target
);
285 InitializeListHead(&FreeList
);
287 ExAcquireFastMutex(&ViewLock
);
288 current_entry
= CacheSegmentLRUListHead
.Flink
;
289 while (current_entry
!= &CacheSegmentLRUListHead
&& Target
> 0)
291 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
292 CacheSegmentLRUListEntry
);
293 current_entry
= current_entry
->Flink
;
295 KeAcquireSpinLock(¤t
->Bcb
->BcbLock
, &oldIrql
);
296 if (current
->ReferenceCount
== 0)
298 RemoveEntryList(¤t
->BcbSegmentListEntry
);
299 KeReleaseSpinLock(¤t
->Bcb
->BcbLock
, oldIrql
);
300 RemoveEntryList(¤t
->CacheSegmentListEntry
);
301 RemoveEntryList(¤t
->CacheSegmentLRUListEntry
);
302 InsertHeadList(&FreeList
, ¤t
->BcbSegmentListEntry
);
303 PagesPerSegment
= current
->Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
304 PagesFreed
= min(PagesPerSegment
, Target
);
305 Target
-= PagesFreed
;
306 (*NrFreed
) += PagesFreed
;
310 if (last
!= current
&& current
->MappedCount
> 0 && !current
->Dirty
&& !current
->PageOut
)
315 CcRosCacheSegmentIncRefCount(current
);
317 current
->PageOut
= TRUE
;
318 KeReleaseSpinLock(¤t
->Bcb
->BcbLock
, oldIrql
);
319 ExReleaseFastMutex(&ViewLock
);
320 for (i
= 0; i
< current
->Bcb
->CacheSegmentSize
/ PAGE_SIZE
; i
++)
323 Page
= MmGetPhysicalAddress((char*)current
->BaseAddress
+ i
* PAGE_SIZE
).QuadPart
>> PAGE_SHIFT
;
324 Status
= MmPageOutPhysicalAddress(Page
);
325 if (!NT_SUCCESS(Status
))
330 ExAcquireFastMutex(&ViewLock
);
331 KeAcquireSpinLock(¤t
->Bcb
->BcbLock
, &oldIrql
);
332 CcRosCacheSegmentDecRefCount(current
);
333 current
->PageOut
= FALSE
;
334 KeReleaseSpinLock(¤t
->Bcb
->BcbLock
, oldIrql
);
335 current_entry
= ¤t
->CacheSegmentLRUListEntry
;
338 KeReleaseSpinLock(¤t
->Bcb
->BcbLock
, oldIrql
);
341 ExReleaseFastMutex(&ViewLock
);
343 while (!IsListEmpty(&FreeList
))
345 current_entry
= RemoveHeadList(&FreeList
);
346 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
347 BcbSegmentListEntry
);
348 CcRosInternalFreeCacheSegment(current
);
351 DPRINT("CcRosTrimCache() finished\n");
352 return(STATUS_SUCCESS
);
356 CcRosReleaseCacheSegment(PBCB Bcb
,
357 PCACHE_SEGMENT CacheSeg
,
362 BOOLEAN WasDirty
= CacheSeg
->Dirty
;
367 DPRINT("CcReleaseCacheSegment(Bcb 0x%p, CacheSeg 0x%p, Valid %d)\n",
368 Bcb
, CacheSeg
, Valid
);
370 CacheSeg
->Valid
= Valid
;
371 CacheSeg
->Dirty
= CacheSeg
->Dirty
|| Dirty
;
373 ExAcquireFastMutex(&ViewLock
);
374 if (!WasDirty
&& CacheSeg
->Dirty
)
376 InsertTailList(&DirtySegmentListHead
, &CacheSeg
->DirtySegmentListEntry
);
377 DirtyPageCount
+= Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
379 RemoveEntryList(&CacheSeg
->CacheSegmentLRUListEntry
);
380 InsertTailList(&CacheSegmentLRUListHead
, &CacheSeg
->CacheSegmentLRUListEntry
);
384 CacheSeg
->MappedCount
++;
386 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
387 CcRosCacheSegmentDecRefCount(CacheSeg
);
388 if (Mapped
&& CacheSeg
->MappedCount
== 1)
390 CcRosCacheSegmentIncRefCount(CacheSeg
);
392 if (!WasDirty
&& CacheSeg
->Dirty
)
394 CcRosCacheSegmentIncRefCount(CacheSeg
);
396 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
397 ExReleaseFastMutex(&ViewLock
);
398 ExReleaseFastMutex(&CacheSeg
->Lock
);
400 return(STATUS_SUCCESS
);
404 CcRosLookupCacheSegment(PBCB Bcb
, ULONG FileOffset
)
406 PLIST_ENTRY current_entry
;
407 PCACHE_SEGMENT current
;
412 DPRINT("CcRosLookupCacheSegment(Bcb -x%p, FileOffset %d)\n", Bcb
, FileOffset
);
414 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
415 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
416 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
418 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
419 BcbSegmentListEntry
);
420 if (current
->FileOffset
<= FileOffset
&&
421 (current
->FileOffset
+ Bcb
->CacheSegmentSize
) > FileOffset
)
423 CcRosCacheSegmentIncRefCount(current
);
424 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
425 ExAcquireFastMutex(¤t
->Lock
);
428 current_entry
= current_entry
->Flink
;
430 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
435 CcRosMarkDirtyCacheSegment(PBCB Bcb
, ULONG FileOffset
)
437 PCACHE_SEGMENT CacheSeg
;
442 DPRINT("CcRosMarkDirtyCacheSegment(Bcb 0x%p, FileOffset %d)\n", Bcb
, FileOffset
);
444 CacheSeg
= CcRosLookupCacheSegment(Bcb
, FileOffset
);
445 if (CacheSeg
== NULL
)
449 if (!CacheSeg
->Dirty
)
451 ExAcquireFastMutex(&ViewLock
);
452 InsertTailList(&DirtySegmentListHead
, &CacheSeg
->DirtySegmentListEntry
);
453 DirtyPageCount
+= Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
454 ExReleaseFastMutex(&ViewLock
);
458 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
459 CcRosCacheSegmentDecRefCount(CacheSeg
);
460 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
464 CacheSeg
->Dirty
= TRUE
;
465 ExReleaseFastMutex(&CacheSeg
->Lock
);
467 return(STATUS_SUCCESS
);
471 CcRosUnmapCacheSegment(PBCB Bcb
, ULONG FileOffset
, BOOLEAN NowDirty
)
473 PCACHE_SEGMENT CacheSeg
;
479 DPRINT("CcRosUnmapCacheSegment(Bcb 0x%p, FileOffset %d, NowDirty %d)\n",
480 Bcb
, FileOffset
, NowDirty
);
482 CacheSeg
= CcRosLookupCacheSegment(Bcb
, FileOffset
);
483 if (CacheSeg
== NULL
)
485 return(STATUS_UNSUCCESSFUL
);
488 WasDirty
= CacheSeg
->Dirty
;
489 CacheSeg
->Dirty
= CacheSeg
->Dirty
|| NowDirty
;
491 CacheSeg
->MappedCount
--;
493 if (!WasDirty
&& NowDirty
)
495 ExAcquireFastMutex(&ViewLock
);
496 InsertTailList(&DirtySegmentListHead
, &CacheSeg
->DirtySegmentListEntry
);
497 DirtyPageCount
+= Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
498 ExReleaseFastMutex(&ViewLock
);
501 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
502 CcRosCacheSegmentDecRefCount(CacheSeg
);
503 if (!WasDirty
&& NowDirty
)
505 CcRosCacheSegmentIncRefCount(CacheSeg
);
507 if (CacheSeg
->MappedCount
== 0)
509 CcRosCacheSegmentDecRefCount(CacheSeg
);
511 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
513 ExReleaseFastMutex(&CacheSeg
->Lock
);
514 return(STATUS_SUCCESS
);
518 CcRosCreateCacheSegment(PBCB Bcb
,
520 PCACHE_SEGMENT
* CacheSeg
)
523 PCACHE_SEGMENT current
;
524 PCACHE_SEGMENT previous
;
525 PLIST_ENTRY current_entry
;
530 ULONG StartingOffset
;
533 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
537 DPRINT("CcRosCreateCacheSegment()\n");
539 BoundaryAddressMultiple
.QuadPart
= 0;
540 if (FileOffset
>= Bcb
->FileSize
.u
.LowPart
)
543 return STATUS_INVALID_PARAMETER
;
546 current
= ExAllocateFromNPagedLookasideList(&CacheSegLookasideList
);
547 current
->Valid
= FALSE
;
548 current
->Dirty
= FALSE
;
549 current
->PageOut
= FALSE
;
550 current
->FileOffset
= ROUND_DOWN(FileOffset
, Bcb
->CacheSegmentSize
);
552 #if defined(DBG) || defined(KDBG)
555 DPRINT1("CacheMap 0x%p: new Cache Segment: 0x%p\n", Bcb
, current
);
558 current
->MappedCount
= 0;
559 current
->DirtySegmentListEntry
.Flink
= NULL
;
560 current
->DirtySegmentListEntry
.Blink
= NULL
;
561 current
->ReferenceCount
= 1;
562 ExInitializeFastMutex(¤t
->Lock
);
563 ExAcquireFastMutex(¤t
->Lock
);
564 ExAcquireFastMutex(&ViewLock
);
567 /* There is window between the call to CcRosLookupCacheSegment
568 * and CcRosCreateCacheSegment. We must check if a segment on
569 * the fileoffset exist. If there exist a segment, we release
570 * our new created segment and return the existing one.
572 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
573 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
575 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
577 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
578 BcbSegmentListEntry
);
579 if (current
->FileOffset
<= FileOffset
&&
580 (current
->FileOffset
+ Bcb
->CacheSegmentSize
) > FileOffset
)
582 CcRosCacheSegmentIncRefCount(current
);
583 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
584 #if defined(DBG) || defined(KDBG)
587 DPRINT1("CacheMap 0x%p: deleting newly created Cache Segment 0x%p ( found existing one 0x%p )\n",
593 ExReleaseFastMutex(&(*CacheSeg
)->Lock
);
594 ExReleaseFastMutex(&ViewLock
);
595 ExFreeToNPagedLookasideList(&CacheSegLookasideList
, *CacheSeg
);
597 ExAcquireFastMutex(¤t
->Lock
);
598 return STATUS_SUCCESS
;
600 if (current
->FileOffset
< FileOffset
)
602 if (previous
== NULL
)
608 if (previous
->FileOffset
< current
->FileOffset
)
614 current_entry
= current_entry
->Flink
;
616 /* There was no existing segment. */
620 InsertHeadList(&previous
->BcbSegmentListEntry
, ¤t
->BcbSegmentListEntry
);
624 InsertHeadList(&Bcb
->BcbSegmentListHead
, ¤t
->BcbSegmentListEntry
);
626 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
627 InsertTailList(&CacheSegmentListHead
, ¤t
->CacheSegmentListEntry
);
628 InsertTailList(&CacheSegmentLRUListHead
, ¤t
->CacheSegmentLRUListEntry
);
629 ExReleaseFastMutex(&ViewLock
);
631 KeAcquireSpinLock(&CiCacheSegMappingRegionLock
, &oldIrql
);
633 StartingOffset
= RtlFindClearBitsAndSet(&CiCacheSegMappingRegionAllocMap
, Bcb
->CacheSegmentSize
/ PAGE_SIZE
, CiCacheSegMappingRegionHint
);
635 if (StartingOffset
== 0xffffffff)
637 DPRINT1("Out of CacheSeg mapping space\n");
641 current
->BaseAddress
= CiCacheSegMappingRegionBase
+ StartingOffset
* PAGE_SIZE
;
643 if (CiCacheSegMappingRegionHint
== StartingOffset
)
645 CiCacheSegMappingRegionHint
+= Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
648 KeReleaseSpinLock(&CiCacheSegMappingRegionLock
, oldIrql
);
650 MmLockAddressSpace(MmGetKernelAddressSpace());
651 current
->BaseAddress
= NULL
;
652 Status
= MmCreateMemoryArea(NULL
,
653 MmGetKernelAddressSpace(),
654 MEMORY_AREA_CACHE_SEGMENT
,
655 ¤t
->BaseAddress
,
656 Bcb
->CacheSegmentSize
,
658 (PMEMORY_AREA
*)¤t
->MemoryArea
,
661 BoundaryAddressMultiple
);
662 MmUnlockAddressSpace(MmGetKernelAddressSpace());
663 if (!NT_SUCCESS(Status
))
668 Pfn
= alloca(sizeof(PFN_TYPE
) * (Bcb
->CacheSegmentSize
/ PAGE_SIZE
));
669 for (i
= 0; i
< (Bcb
->CacheSegmentSize
/ PAGE_SIZE
); i
++)
671 Status
= MmRequestPageMemoryConsumer(MC_CACHE
, TRUE
, &Pfn
[i
]);
672 if (!NT_SUCCESS(Status
))
677 Status
= MmCreateVirtualMapping(NULL
,
678 current
->BaseAddress
,
681 Bcb
->CacheSegmentSize
/ PAGE_SIZE
);
682 if (!NT_SUCCESS(Status
))
686 return(STATUS_SUCCESS
);
690 CcRosGetCacheSegmentChain(PBCB Bcb
,
693 PCACHE_SEGMENT
* CacheSeg
)
695 PCACHE_SEGMENT current
;
697 PCACHE_SEGMENT
* CacheSegList
;
698 PCACHE_SEGMENT Previous
= NULL
;
702 DPRINT("CcRosGetCacheSegmentChain()\n");
704 Length
= ROUND_UP(Length
, Bcb
->CacheSegmentSize
);
706 #if defined(__GNUC__)
707 CacheSegList
= alloca(sizeof(PCACHE_SEGMENT
) *
708 (Length
/ Bcb
->CacheSegmentSize
));
709 #elif defined(_MSC_VER)
710 CacheSegList
= _alloca(sizeof(PCACHE_SEGMENT
) *
711 (Length
/ Bcb
->CacheSegmentSize
));
713 #error Unknown compiler for alloca intrinsic stack allocation "function"
717 * Look for a cache segment already mapping the same data.
719 for (i
= 0; i
< (Length
/ Bcb
->CacheSegmentSize
); i
++)
721 ULONG CurrentOffset
= FileOffset
+ (i
* Bcb
->CacheSegmentSize
);
722 current
= CcRosLookupCacheSegment(Bcb
, CurrentOffset
);
725 CacheSegList
[i
] = current
;
729 CcRosCreateCacheSegment(Bcb
, CurrentOffset
, ¤t
);
730 CacheSegList
[i
] = current
;
734 for (i
= 0; i
< (Length
/ Bcb
->CacheSegmentSize
); i
++)
738 *CacheSeg
= CacheSegList
[i
];
739 Previous
= CacheSegList
[i
];
743 Previous
->NextInChain
= CacheSegList
[i
];
744 Previous
= CacheSegList
[i
];
747 Previous
->NextInChain
= NULL
;
749 return(STATUS_SUCCESS
);
753 CcRosGetCacheSegment(PBCB Bcb
,
758 PCACHE_SEGMENT
* CacheSeg
)
760 PCACHE_SEGMENT current
;
765 DPRINT("CcRosGetCacheSegment()\n");
768 * Look for a cache segment already mapping the same data.
770 current
= CcRosLookupCacheSegment(Bcb
, FileOffset
);
774 * Otherwise create a new segment.
776 Status
= CcRosCreateCacheSegment(Bcb
, FileOffset
, ¤t
);
777 if (!NT_SUCCESS(Status
))
783 * Return information about the segment to the caller.
785 *UptoDate
= current
->Valid
;
786 *BaseAddress
= current
->BaseAddress
;
787 DPRINT("*BaseAddress 0x%.8X\n", *BaseAddress
);
789 *BaseOffset
= current
->FileOffset
;
790 return(STATUS_SUCCESS
);
794 CcRosRequestCacheSegment(PBCB Bcb
,
798 PCACHE_SEGMENT
* CacheSeg
)
800 * FUNCTION: Request a page mapping for a BCB
807 if ((FileOffset
% Bcb
->CacheSegmentSize
) != 0)
809 CPRINT("Bad fileoffset %x should be multiple of %x",
810 FileOffset
, Bcb
->CacheSegmentSize
);
814 return(CcRosGetCacheSegment(Bcb
,
824 CcFreeCachePage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
825 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
827 ASSERT(SwapEntry
== 0);
830 MmReleasePageMemoryConsumer(MC_CACHE
, Page
);
835 CcRosInternalFreeCacheSegment(PCACHE_SEGMENT CacheSeg
)
837 * FUNCTION: Releases a cache segment associated with a BCB
847 DPRINT("Freeing cache segment 0x%p\n", CacheSeg
);
848 #if defined(DBG) || defined(KDBG)
849 if ( CacheSeg
->Bcb
->Trace
)
851 DPRINT1("CacheMap 0x%p: deleting Cache Segment: 0x%p\n", CacheSeg
->Bcb
, CacheSeg
);
855 RegionSize
= CacheSeg
->Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
857 /* Unmap all the pages. */
858 for (i
= 0; i
< RegionSize
; i
++)
860 MmDeleteVirtualMapping(NULL
,
861 CacheSeg
->BaseAddress
+ (i
* PAGE_SIZE
),
865 MmReleasePageMemoryConsumer(MC_CACHE
, Page
);
868 KeAcquireSpinLock(&CiCacheSegMappingRegionLock
, &oldIrql
);
869 /* Deallocate all the pages used. */
870 Base
= (ULONG
)(CacheSeg
->BaseAddress
- CiCacheSegMappingRegionBase
) / PAGE_SIZE
;
872 RtlClearBits(&CiCacheSegMappingRegionAllocMap
, Base
, RegionSize
);
874 CiCacheSegMappingRegionHint
= min (CiCacheSegMappingRegionHint
, Base
);
876 KeReleaseSpinLock(&CiCacheSegMappingRegionLock
, oldIrql
);
878 MmLockAddressSpace(MmGetKernelAddressSpace());
879 MmFreeMemoryArea(MmGetKernelAddressSpace(),
880 CacheSeg
->MemoryArea
,
883 MmUnlockAddressSpace(MmGetKernelAddressSpace());
885 ExFreeToNPagedLookasideList(&CacheSegLookasideList
, CacheSeg
);
886 return(STATUS_SUCCESS
);
890 CcRosFreeCacheSegment(PBCB Bcb
, PCACHE_SEGMENT CacheSeg
)
897 DPRINT("CcRosFreeCacheSegment(Bcb 0x%p, CacheSeg 0x%p)\n",
900 ExAcquireFastMutex(&ViewLock
);
901 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
902 RemoveEntryList(&CacheSeg
->BcbSegmentListEntry
);
903 RemoveEntryList(&CacheSeg
->CacheSegmentListEntry
);
904 RemoveEntryList(&CacheSeg
->CacheSegmentLRUListEntry
);
907 RemoveEntryList(&CacheSeg
->DirtySegmentListEntry
);
908 DirtyPageCount
-= Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
911 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
912 ExReleaseFastMutex(&ViewLock
);
914 Status
= CcRosInternalFreeCacheSegment(CacheSeg
);
922 CcFlushCache(IN PSECTION_OBJECT_POINTERS SectionObjectPointers
,
923 IN PLARGE_INTEGER FileOffset OPTIONAL
,
925 OUT PIO_STATUS_BLOCK IoStatus
)
928 LARGE_INTEGER Offset
;
929 PCACHE_SEGMENT current
;
933 DPRINT("CcFlushCache(SectionObjectPointers 0x%p, FileOffset 0x%p, Length %d, IoStatus 0x%p)\n",
934 SectionObjectPointers
, FileOffset
, Length
, IoStatus
);
936 if (SectionObjectPointers
&& SectionObjectPointers
->SharedCacheMap
)
938 Bcb
= (PBCB
)SectionObjectPointers
->SharedCacheMap
;
942 Offset
= *FileOffset
;
946 Offset
.QuadPart
= (LONGLONG
)0;
947 Length
= Bcb
->FileSize
.u
.LowPart
;
952 IoStatus
->Status
= STATUS_SUCCESS
;
953 IoStatus
->Information
= 0;
958 current
= CcRosLookupCacheSegment (Bcb
, Offset
.u
.LowPart
);
963 Status
= CcRosFlushCacheSegment(current
);
964 if (!NT_SUCCESS(Status
) && IoStatus
!= NULL
)
966 IoStatus
->Status
= Status
;
969 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
970 ExReleaseFastMutex(¤t
->Lock
);
971 CcRosCacheSegmentDecRefCount(current
);
972 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
975 Offset
.QuadPart
+= Bcb
->CacheSegmentSize
;
976 if (Length
> Bcb
->CacheSegmentSize
)
978 Length
-= Bcb
->CacheSegmentSize
;
990 IoStatus
->Status
= STATUS_INVALID_PARAMETER
;
996 CcRosDeleteFileCache(PFILE_OBJECT FileObject
, PBCB Bcb
)
998 * FUNCTION: Releases the BCB associated with a file object
1001 PLIST_ENTRY current_entry
;
1002 PCACHE_SEGMENT current
;
1004 LIST_ENTRY FreeList
;
1010 ExReleaseFastMutex(&ViewLock
);
1012 CcFlushCache(FileObject
->SectionObjectPointer
, NULL
, 0, NULL
);
1014 ExAcquireFastMutex(&ViewLock
);
1016 if (Bcb
->RefCount
== 0)
1018 if (Bcb
->BcbRemoveListEntry
.Flink
!= NULL
)
1020 RemoveEntryList(&Bcb
->BcbRemoveListEntry
);
1021 Bcb
->BcbRemoveListEntry
.Flink
= NULL
;
1024 FileObject
->SectionObjectPointer
->SharedCacheMap
= NULL
;
1027 * Release all cache segments.
1029 InitializeListHead(&FreeList
);
1030 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
1031 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
1032 while (!IsListEmpty(&Bcb
->BcbSegmentListHead
))
1034 current_entry
= RemoveTailList(&Bcb
->BcbSegmentListHead
);
1035 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
, BcbSegmentListEntry
);
1036 RemoveEntryList(¤t
->CacheSegmentListEntry
);
1037 RemoveEntryList(¤t
->CacheSegmentLRUListEntry
);
1040 RemoveEntryList(¤t
->DirtySegmentListEntry
);
1041 DirtyPageCount
-= Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
1042 DPRINT1("Freeing dirty segment\n");
1044 InsertHeadList(&FreeList
, ¤t
->BcbSegmentListEntry
);
1046 #if defined(DBG) || defined(KDBG)
1049 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
1051 ExReleaseFastMutex(&ViewLock
);
1052 ObDereferenceObject (Bcb
->FileObject
);
1054 while (!IsListEmpty(&FreeList
))
1056 current_entry
= RemoveTailList(&FreeList
);
1057 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
, BcbSegmentListEntry
);
1058 Status
= CcRosInternalFreeCacheSegment(current
);
1060 ExFreeToNPagedLookasideList(&BcbLookasideList
, Bcb
);
1061 ExAcquireFastMutex(&ViewLock
);
1063 return(STATUS_SUCCESS
);
1066 VOID
CcRosReferenceCache(PFILE_OBJECT FileObject
)
1069 ExAcquireFastMutex(&ViewLock
);
1070 Bcb
= (PBCB
)FileObject
->SectionObjectPointer
->SharedCacheMap
;
1072 if (Bcb
->RefCount
== 0)
1074 ASSERT(Bcb
->BcbRemoveListEntry
.Flink
!= NULL
);
1075 RemoveEntryList(&Bcb
->BcbRemoveListEntry
);
1076 Bcb
->BcbRemoveListEntry
.Flink
= NULL
;
1081 ASSERT(Bcb
->BcbRemoveListEntry
.Flink
== NULL
);
1084 ExReleaseFastMutex(&ViewLock
);
1087 VOID
CcRosSetRemoveOnClose(PSECTION_OBJECT_POINTERS SectionObjectPointer
)
1090 DPRINT("CcRosSetRemoveOnClose()\n");
1091 ExAcquireFastMutex(&ViewLock
);
1092 Bcb
= (PBCB
)SectionObjectPointer
->SharedCacheMap
;
1095 Bcb
->RemoveOnClose
= TRUE
;
1096 if (Bcb
->RefCount
== 0)
1098 CcRosDeleteFileCache(Bcb
->FileObject
, Bcb
);
1101 ExReleaseFastMutex(&ViewLock
);
1105 VOID
CcRosDereferenceCache(PFILE_OBJECT FileObject
)
1108 ExAcquireFastMutex(&ViewLock
);
1109 Bcb
= (PBCB
)FileObject
->SectionObjectPointer
->SharedCacheMap
;
1111 if (Bcb
->RefCount
> 0)
1114 if (Bcb
->RefCount
== 0)
1116 MmFreeSectionSegments(Bcb
->FileObject
);
1117 if (Bcb
->RemoveOnClose
)
1119 CcRosDeleteFileCache(FileObject
, Bcb
);
1123 Bcb
->TimeStamp
= CcTimeStamp
;
1124 InsertHeadList(&ClosedListHead
, &Bcb
->BcbRemoveListEntry
);
1128 ExReleaseFastMutex(&ViewLock
);
1132 CcRosReleaseFileCache(PFILE_OBJECT FileObject
)
1134 * FUNCTION: Called by the file system when a handle to a file object
1140 ExAcquireFastMutex(&ViewLock
);
1142 if (FileObject
->SectionObjectPointer
->SharedCacheMap
!= NULL
)
1144 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1145 if (FileObject
->PrivateCacheMap
!= NULL
)
1147 FileObject
->PrivateCacheMap
= NULL
;
1148 if (Bcb
->RefCount
> 0)
1151 if (Bcb
->RefCount
== 0)
1153 MmFreeSectionSegments(Bcb
->FileObject
);
1154 if (Bcb
->RemoveOnClose
)
1156 CcRosDeleteFileCache(FileObject
, Bcb
);
1160 Bcb
->TimeStamp
= CcTimeStamp
;
1161 InsertHeadList(&ClosedListHead
, &Bcb
->BcbRemoveListEntry
);
1167 ExReleaseFastMutex(&ViewLock
);
1168 return(STATUS_SUCCESS
);
1172 CcTryToInitializeFileCache(PFILE_OBJECT FileObject
)
1177 ExAcquireFastMutex(&ViewLock
);
1179 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1182 Status
= STATUS_UNSUCCESSFUL
;
1186 if (FileObject
->PrivateCacheMap
== NULL
)
1188 FileObject
->PrivateCacheMap
= Bcb
;
1191 if (Bcb
->BcbRemoveListEntry
.Flink
!= NULL
)
1193 RemoveEntryList(&Bcb
->BcbRemoveListEntry
);
1194 Bcb
->BcbRemoveListEntry
.Flink
= NULL
;
1196 Status
= STATUS_SUCCESS
;
1198 ExReleaseFastMutex(&ViewLock
);
1205 CcRosInitializeFileCache(PFILE_OBJECT FileObject
,
1206 ULONG CacheSegmentSize
)
1208 * FUNCTION: Initializes a BCB for a file object
1213 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1214 DPRINT("CcRosInitializeFileCache(FileObject 0x%p, Bcb 0x%p, CacheSegmentSize %d)\n",
1215 FileObject
, Bcb
, CacheSegmentSize
);
1217 ExAcquireFastMutex(&ViewLock
);
1220 Bcb
= ExAllocateFromNPagedLookasideList(&BcbLookasideList
);
1223 ExReleaseFastMutex(&ViewLock
);
1224 return(STATUS_UNSUCCESSFUL
);
1226 memset(Bcb
, 0, sizeof(BCB
));
1227 ObReferenceObjectByPointer(FileObject
,
1231 Bcb
->FileObject
= FileObject
;
1232 Bcb
->CacheSegmentSize
= CacheSegmentSize
;
1233 if (FileObject
->FsContext
)
1235 Bcb
->AllocationSize
=
1236 ((PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)->AllocationSize
;
1238 ((PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)->FileSize
;
1240 KeInitializeSpinLock(&Bcb
->BcbLock
);
1241 InitializeListHead(&Bcb
->BcbSegmentListHead
);
1242 FileObject
->SectionObjectPointer
->SharedCacheMap
= Bcb
;
1244 if (FileObject
->PrivateCacheMap
== NULL
)
1246 FileObject
->PrivateCacheMap
= Bcb
;
1249 if (Bcb
->BcbRemoveListEntry
.Flink
!= NULL
)
1251 RemoveEntryList(&Bcb
->BcbRemoveListEntry
);
1252 Bcb
->BcbRemoveListEntry
.Flink
= NULL
;
1254 ExReleaseFastMutex(&ViewLock
);
1256 return(STATUS_SUCCESS
);
1262 PFILE_OBJECT STDCALL
1263 CcGetFileObjectFromSectionPtrs(IN PSECTION_OBJECT_POINTERS SectionObjectPointers
)
1266 if (SectionObjectPointers
&& SectionObjectPointers
->SharedCacheMap
)
1268 Bcb
= (PBCB
)SectionObjectPointers
->SharedCacheMap
;
1270 return Bcb
->FileObject
;
1276 CmLazyCloseThreadMain(PVOID Ignored
)
1278 LARGE_INTEGER Timeout
;
1279 PLIST_ENTRY current_entry
;
1281 ULONG RemoveTimeStamp
;
1284 KeQuerySystemTime (&Timeout
);
1288 Timeout
.QuadPart
+= (LONGLONG
)100000000; // 10sec
1289 Status
= KeWaitForSingleObject(&LazyCloseThreadEvent
,
1295 DPRINT("LazyCloseThreadMain %d\n", CcTimeStamp
);
1297 if (!NT_SUCCESS(Status
))
1299 DbgPrint("LazyCloseThread: Wait failed\n");
1303 if (LazyCloseThreadShouldTerminate
)
1305 DbgPrint("LazyCloseThread: Terminating\n");
1309 ExAcquireFastMutex(&ViewLock
);
1311 if (CcTimeStamp
>= 30)
1313 RemoveTimeStamp
= CcTimeStamp
- 30; /* 5min = 10sec * 30 */
1314 while (!IsListEmpty(&ClosedListHead
))
1316 current_entry
= ClosedListHead
.Blink
;
1317 current
= CONTAINING_RECORD(current_entry
, BCB
, BcbRemoveListEntry
);
1318 if (current
->TimeStamp
>= RemoveTimeStamp
)
1322 CcRosDeleteFileCache(current
->FileObject
, current
);
1325 ExReleaseFastMutex(&ViewLock
);
1335 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
1340 DPRINT("CcInitView()\n");
1342 BoundaryAddressMultiple
.QuadPart
= 0;
1343 CiCacheSegMappingRegionHint
= 0;
1344 CiCacheSegMappingRegionBase
= NULL
;
1346 MmLockAddressSpace(MmGetKernelAddressSpace());
1348 Status
= MmCreateMemoryArea(NULL
,
1349 MmGetKernelAddressSpace(),
1350 MEMORY_AREA_CACHE_SEGMENT
,
1351 &CiCacheSegMappingRegionBase
,
1352 CI_CACHESEG_MAPPING_REGION_SIZE
,
1357 BoundaryAddressMultiple
);
1358 MmUnlockAddressSpace(MmGetKernelAddressSpace());
1359 if (!NT_SUCCESS(Status
))
1364 Buffer
= ExAllocatePool(NonPagedPool
, CI_CACHESEG_MAPPING_REGION_SIZE
/ (PAGE_SIZE
* 8));
1366 RtlInitializeBitMap(&CiCacheSegMappingRegionAllocMap
, Buffer
, CI_CACHESEG_MAPPING_REGION_SIZE
/ PAGE_SIZE
);
1367 RtlClearAllBits(&CiCacheSegMappingRegionAllocMap
);
1369 KeInitializeSpinLock(&CiCacheSegMappingRegionLock
);
1371 InitializeListHead(&CacheSegmentListHead
);
1372 InitializeListHead(&DirtySegmentListHead
);
1373 InitializeListHead(&CacheSegmentLRUListHead
);
1374 InitializeListHead(&ClosedListHead
);
1375 ExInitializeFastMutex(&ViewLock
);
1376 ExInitializeNPagedLookasideList (&iBcbLookasideList
,
1380 sizeof(INTERNAL_BCB
),
1383 ExInitializeNPagedLookasideList (&BcbLookasideList
,
1390 ExInitializeNPagedLookasideList (&CacheSegLookasideList
,
1394 sizeof(CACHE_SEGMENT
),
1398 MmInitializeMemoryConsumer(MC_CACHE
, CcRosTrimCache
);
1400 CcInitCacheZeroPage();
1403 LazyCloseThreadShouldTerminate
= FALSE
;
1404 KeInitializeEvent (&LazyCloseThreadEvent
, SynchronizationEvent
, FALSE
);
1405 Status
= PsCreateSystemThread(&LazyCloseThreadHandle
,
1410 (PKSTART_ROUTINE
)CmLazyCloseThreadMain
,
1412 if (NT_SUCCESS(Status
))
1414 Priority
= LOW_REALTIME_PRIORITY
;
1415 NtSetInformationThread(LazyCloseThreadHandle
,