2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/cache/fssup.c
5 * PURPOSE: Logging and configuration routines
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
10 /* INCLUDES *******************************************************************/
14 #include "section/newmm.h"
18 /* GLOBALS ********************************************************************/
20 PFSN_PREFETCHER_GLOBALS CcPfGlobals
;
21 extern LONG CcOutstandingDeletes
;
22 extern KEVENT CcpLazyWriteEvent
;
23 extern KEVENT CcFinalizeEvent
;
24 extern VOID NTAPI
CcpUnmapThread(PVOID Unused
);
25 extern VOID NTAPI
CcpLazyWriteThread(PVOID Unused
);
26 HANDLE CcUnmapThreadHandle
, CcLazyWriteThreadHandle
;
27 CLIENT_ID CcUnmapThreadId
, CcLazyWriteThreadId
;
28 FAST_MUTEX GlobalPageOperation
;
30 typedef struct _NOCC_PRIVATE_CACHE_MAP
33 PFILE_OBJECT FileObject
;
35 } NOCC_PRIVATE_CACHE_MAP
, *PNOCC_PRIVATE_CACHE_MAP
;
37 LIST_ENTRY CcpAllSharedCacheMaps
;
39 /* FUNCTIONS ******************************************************************/
41 // Interact with legacy balance manager for now
42 // This can fall away when our section implementation supports
43 // demand paging properly
45 CcRosTrimCache(ULONG Target
, ULONG Priority
, PULONG NrFreed
)
47 ULONG i
, Freed
, BcbHead
;
51 for (i
= 0; i
< CACHE_NUM_SECTIONS
; i
++) {
52 BcbHead
= (i
+CcCacheClockHand
) % CACHE_NUM_SECTIONS
;
54 // Reference a cache stripe so it won't go away
56 if (CcCacheSections
[BcbHead
].BaseAddress
) {
57 CcpReferenceCache(BcbHead
);
64 // Defer to MM to try recovering pages from it
65 Freed
= MiCacheEvictPages
66 (CcCacheSections
[BcbHead
].BaseAddress
, Target
);
72 CcpUnpinData(&CcCacheSections
[BcbHead
], TRUE
);
76 return STATUS_SUCCESS
;
81 CcInitializeCacheManager(VOID
)
85 DPRINT("Initialize\n");
86 for (i
= 0; i
< CACHE_NUM_SECTIONS
; i
++)
88 KeInitializeEvent(&CcCacheSections
[i
].ExclusiveWait
, SynchronizationEvent
, FALSE
);
89 InitializeListHead(&CcCacheSections
[i
].ThisFileList
);
92 InitializeListHead(&CcpAllSharedCacheMaps
);
94 KeInitializeEvent(&CcDeleteEvent
, SynchronizationEvent
, FALSE
);
95 KeInitializeEvent(&CcFinalizeEvent
, SynchronizationEvent
, FALSE
);
96 KeInitializeEvent(&CcpLazyWriteEvent
, SynchronizationEvent
, FALSE
);
98 CcCacheBitmap
->Buffer
= ((PULONG
)&CcCacheBitmap
[1]);
99 CcCacheBitmap
->SizeOfBitMap
= ROUND_UP(CACHE_NUM_SECTIONS
, 32);
100 DPRINT("Cache has %d entries\n", CcCacheBitmap
->SizeOfBitMap
);
101 ExInitializeFastMutex(&CcMutex
);
102 ExInitializeFastMutex(&GlobalPageOperation
);
105 KeInitializeEvent(&MmWaitPageEvent
, SynchronizationEvent
, FALSE
);
107 // Until we're fully demand paged, we can do things the old way through
108 // the balance manager
109 MmInitializeMemoryConsumer(MC_CACHE
, CcRosTrimCache
);
116 CcPfInitializePrefetcher(VOID
)
118 /* Notify debugger */
119 DbgPrintEx(DPFLTR_PREFETCHER_ID
,
121 "CCPF: InitializePrefetecher()\n");
123 /* Setup the Prefetcher Data */
124 InitializeListHead(&CcPfGlobals
.ActiveTraces
);
125 InitializeListHead(&CcPfGlobals
.CompletedTraces
);
126 ExInitializeFastMutex(&CcPfGlobals
.CompletedTracesLock
);
128 /* FIXME: Setup the rest of the prefetecher */
133 CcpAcquireFileLock(PNOCC_CACHE_MAP Map
)
135 DPRINT("Calling AcquireForLazyWrite: %x\n", Map
->LazyContext
);
136 return Map
->Callbacks
.AcquireForLazyWrite(Map
->LazyContext
, TRUE
);
141 CcpReleaseFileLock(PNOCC_CACHE_MAP Map
)
143 DPRINT("Releasing Lazy Write %x\n", Map
->LazyContext
);
144 Map
->Callbacks
.ReleaseFromLazyWrite(Map
->LazyContext
);
147 // Must have CcpLock()
148 PFILE_OBJECT
CcpFindOtherStreamFileObject(PFILE_OBJECT FileObject
)
150 PLIST_ENTRY Entry
, Private
;
151 for (Entry
= CcpAllSharedCacheMaps
.Flink
;
152 Entry
!= &CcpAllSharedCacheMaps
;
153 Entry
= Entry
->Flink
)
155 // 'Identical' test for other stream file object
156 PNOCC_CACHE_MAP Map
= CONTAINING_RECORD(Entry
, NOCC_CACHE_MAP
, Entry
);
157 for (Private
= Map
->PrivateCacheMaps
.Flink
;
158 Private
!= &Map
->PrivateCacheMaps
;
159 Private
= Private
->Flink
)
161 PNOCC_PRIVATE_CACHE_MAP PrivateMap
= CONTAINING_RECORD(Private
, NOCC_PRIVATE_CACHE_MAP
, ListEntry
);
162 if (PrivateMap
->FileObject
->Flags
& FO_STREAM_FILE
&&
163 PrivateMap
->FileObject
->DeviceObject
== FileObject
->DeviceObject
&&
164 PrivateMap
->FileObject
->Vpb
== FileObject
->Vpb
&&
165 PrivateMap
->FileObject
->FsContext
== FileObject
->FsContext
&&
166 PrivateMap
->FileObject
->FsContext2
== FileObject
->FsContext2
&&
169 return PrivateMap
->FileObject
;
176 // Thanks: http://windowsitpro.com/Windows/Articles/ArticleID/3864/pg/2/2.html
180 CcInitializeCacheMap(IN PFILE_OBJECT FileObject
,
181 IN PCC_FILE_SIZES FileSizes
,
182 IN BOOLEAN PinAccess
,
183 IN PCACHE_MANAGER_CALLBACKS Callbacks
,
184 IN PVOID LazyWriteContext
)
186 PNOCC_CACHE_MAP Map
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
187 PNOCC_PRIVATE_CACHE_MAP PrivateCacheMap
= FileObject
->PrivateCacheMap
;
190 if (!Map
&& FileObject
->Flags
& FO_STREAM_FILE
)
192 PFILE_OBJECT IdenticalStreamFileObject
=
193 CcpFindOtherStreamFileObject(FileObject
);
194 if (IdenticalStreamFileObject
)
195 Map
= IdenticalStreamFileObject
->SectionObjectPointer
->SharedCacheMap
;
199 ("Linking SFO %x to previous SFO %x through cache map %x #\n",
200 FileObject
, IdenticalStreamFileObject
, Map
);
205 DPRINT("Initializing file object for (%p) %wZ\n", FileObject
, &FileObject
->FileName
);
206 Map
= ExAllocatePool(NonPagedPool
, sizeof(NOCC_CACHE_MAP
));
207 FileObject
->SectionObjectPointer
->SharedCacheMap
= Map
;
208 Map
->FileSizes
= *FileSizes
;
209 Map
->LazyContext
= LazyWriteContext
;
210 Map
->ReadAheadGranularity
= PAGE_SIZE
;
211 RtlCopyMemory(&Map
->Callbacks
, Callbacks
, sizeof(*Callbacks
));
213 DPRINT("FileSizes->ValidDataLength %08x%08x\n", FileSizes
->ValidDataLength
.HighPart
, FileSizes
->ValidDataLength
.LowPart
);
214 InitializeListHead(&Map
->AssociatedBcb
);
215 InitializeListHead(&Map
->PrivateCacheMaps
);
216 InsertTailList(&CcpAllSharedCacheMaps
, &Map
->Entry
);
217 DPRINT("New Map %x\n", Map
);
219 if (!PrivateCacheMap
)
221 PrivateCacheMap
= ExAllocatePool(NonPagedPool
, sizeof(*PrivateCacheMap
));
222 FileObject
->PrivateCacheMap
= PrivateCacheMap
;
223 PrivateCacheMap
->FileObject
= FileObject
;
224 ObReferenceObject(PrivateCacheMap
->FileObject
);
227 PrivateCacheMap
->Map
= Map
;
228 InsertTailList(&Map
->PrivateCacheMaps
, &PrivateCacheMap
->ListEntry
);
235 CcpCountCacheSections(IN PNOCC_CACHE_MAP Map
)
240 for (Count
= 0, Entry
= Map
->AssociatedBcb
.Flink
; Entry
!= &Map
->AssociatedBcb
; Entry
= Entry
->Flink
, Count
++);
247 CcUninitializeCacheMap(IN PFILE_OBJECT FileObject
,
248 IN OPTIONAL PLARGE_INTEGER TruncateSize
,
249 IN OPTIONAL PCACHE_UNINITIALIZE_EVENT UninitializeEvent
)
251 BOOLEAN LastMap
= FALSE
;
252 PNOCC_CACHE_MAP Map
= (PNOCC_CACHE_MAP
)FileObject
->SectionObjectPointer
->SharedCacheMap
;
253 PNOCC_PRIVATE_CACHE_MAP PrivateCacheMap
= FileObject
->PrivateCacheMap
;
255 DPRINT("Uninitializing file object for %wZ SectionObjectPointer %x\n", &FileObject
->FileName
, FileObject
->SectionObjectPointer
);
257 ASSERT(UninitializeEvent
== NULL
);
260 CcpFlushCache(Map
, NULL
, 0, NULL
, FALSE
);
265 ASSERT(!Map
|| Map
== PrivateCacheMap
->Map
);
266 ASSERT(PrivateCacheMap
->FileObject
== FileObject
);
268 RemoveEntryList(&PrivateCacheMap
->ListEntry
);
269 if (IsListEmpty(&PrivateCacheMap
->Map
->PrivateCacheMaps
))
271 while (!IsListEmpty(&Map
->AssociatedBcb
))
273 PNOCC_BCB Bcb
= CONTAINING_RECORD(Map
->AssociatedBcb
.Flink
, NOCC_BCB
, ThisFileList
);
274 DPRINT("Evicting cache stripe #%x\n", Bcb
- CcCacheSections
);
276 CcpDereferenceCache(Bcb
- CcCacheSections
, TRUE
);
278 RemoveEntryList(&PrivateCacheMap
->Map
->Entry
);
279 ExFreePool(PrivateCacheMap
->Map
);
280 FileObject
->SectionObjectPointer
->SharedCacheMap
= NULL
;
283 ObDereferenceObject(PrivateCacheMap
->FileObject
);
284 FileObject
->PrivateCacheMap
= NULL
;
285 ExFreePool(PrivateCacheMap
);
289 DPRINT("Uninit complete\n");
296 CcSetFileSizes(IN PFILE_OBJECT FileObject
,
297 IN PCC_FILE_SIZES FileSizes
)
299 PNOCC_CACHE_MAP Map
= (PNOCC_CACHE_MAP
)FileObject
->SectionObjectPointer
->SharedCacheMap
;
301 Map
->FileSizes
= *FileSizes
;
302 PNOCC_BCB Bcb
= Map
->AssociatedBcb
.Flink
== &Map
->AssociatedBcb
?
303 NULL
: CONTAINING_RECORD(Map
->AssociatedBcb
.Flink
, NOCC_BCB
, ThisFileList
);
305 MmExtendCacheSection(Bcb
->SectionObject
, &FileSizes
->FileSize
, FALSE
);
306 DPRINT("FileSizes->FileSize %x\n", FileSizes
->FileSize
.LowPart
);
307 DPRINT("FileSizes->AllocationSize %x\n", FileSizes
->AllocationSize
.LowPart
);
308 DPRINT("FileSizes->ValidDataLength %x\n", FileSizes
->ValidDataLength
.LowPart
);
314 (IN PFILE_OBJECT FileObject
,
315 IN PCC_FILE_SIZES FileSizes
)
317 PNOCC_CACHE_MAP Map
= (PNOCC_CACHE_MAP
)FileObject
->SectionObjectPointer
->SharedCacheMap
;
318 if (!Map
) return FALSE
;
319 *FileSizes
= Map
->FileSizes
;
325 CcPurgeCacheSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
326 IN OPTIONAL PLARGE_INTEGER FileOffset
,
328 IN BOOLEAN UninitializeCacheMaps
)
330 PNOCC_CACHE_MAP Map
= (PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
;
331 if (!Map
) return TRUE
;
332 CcpFlushCache(Map
, NULL
, 0, NULL
, TRUE
);
338 CcSetDirtyPageThreshold(IN PFILE_OBJECT FileObject
,
339 IN ULONG DirtyPageThreshold
)
347 CcZeroData(IN PFILE_OBJECT FileObject
,
348 IN PLARGE_INTEGER StartOffset
,
349 IN PLARGE_INTEGER EndOffset
,
352 PNOCC_BCB Bcb
= NULL
;
353 PLIST_ENTRY ListEntry
= NULL
;
354 LARGE_INTEGER LowerBound
= *StartOffset
;
355 LARGE_INTEGER UpperBound
= *EndOffset
;
356 LARGE_INTEGER Target
, End
;
357 PVOID PinnedBcb
, PinnedBuffer
;
358 PNOCC_CACHE_MAP Map
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
361 ("S %08x%08x E %08x%08x\n",
362 StartOffset
->u
.HighPart
, StartOffset
->u
.LowPart
,
363 EndOffset
->u
.HighPart
, EndOffset
->u
.LowPart
);
368 IO_STATUS_BLOCK IOSB
;
369 PCHAR ZeroBuf
= ExAllocatePool(PagedPool
, PAGE_SIZE
);
372 if (!ZeroBuf
) RtlRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
373 DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf
, PAGE_SIZE
);
374 RtlZeroMemory(ZeroBuf
, PAGE_SIZE
);
376 Target
.QuadPart
= PAGE_ROUND_DOWN(LowerBound
.QuadPart
);
377 End
.QuadPart
= PAGE_ROUND_UP(UpperBound
.QuadPart
);
379 // Handle leading page
380 if (LowerBound
.QuadPart
!= Target
.QuadPart
)
382 ToWrite
= MIN(UpperBound
.QuadPart
- LowerBound
.QuadPart
, (PAGE_SIZE
- LowerBound
.QuadPart
) & (PAGE_SIZE
- 1));
383 DPRINT("Zero last half %08x%08x %x\n", Target
.u
.HighPart
, Target
.u
.LowPart
, ToWrite
);
384 Status
= MiSimpleRead(FileObject
, &Target
, ZeroBuf
, PAGE_SIZE
, &IOSB
);
385 if (!NT_SUCCESS(Status
))
388 RtlRaiseStatus(Status
);
390 DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf
+ LowerBound
.QuadPart
- Target
.QuadPart
, ToWrite
);
391 RtlZeroMemory(ZeroBuf
+ LowerBound
.QuadPart
- Target
.QuadPart
, ToWrite
);
392 Status
= MiSimpleWrite(FileObject
, &Target
, ZeroBuf
, MIN(PAGE_SIZE
,UpperBound
.QuadPart
-Target
.QuadPart
), &IOSB
);
393 if (!NT_SUCCESS(Status
))
396 RtlRaiseStatus(Status
);
398 Target
.QuadPart
+= PAGE_SIZE
;
401 DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf
, PAGE_SIZE
);
402 RtlZeroMemory(ZeroBuf
, PAGE_SIZE
);
404 while (UpperBound
.QuadPart
- Target
.QuadPart
> PAGE_SIZE
)
406 DPRINT("Zero full page %08x%08x\n", Target
.u
.HighPart
, Target
.u
.LowPart
);
407 Status
= MiSimpleWrite(FileObject
, &Target
, ZeroBuf
, PAGE_SIZE
, &IOSB
);
408 if (!NT_SUCCESS(Status
))
411 RtlRaiseStatus(Status
);
413 Target
.QuadPart
+= PAGE_SIZE
;
416 if (UpperBound
.QuadPart
> Target
.QuadPart
)
418 ToWrite
= UpperBound
.QuadPart
- Target
.QuadPart
;
419 DPRINT("Zero first half %08x%08x %x\n", Target
.u
.HighPart
, Target
.u
.LowPart
, ToWrite
);
420 Status
= MiSimpleRead(FileObject
, &Target
, ZeroBuf
, PAGE_SIZE
, &IOSB
);
421 if (!NT_SUCCESS(Status
))
424 RtlRaiseStatus(Status
);
426 DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf
, ToWrite
);
427 RtlZeroMemory(ZeroBuf
, ToWrite
);
428 Status
= MiSimpleWrite(FileObject
, &Target
, ZeroBuf
, MIN(PAGE_SIZE
, UpperBound
.QuadPart
-Target
.QuadPart
), &IOSB
);
429 if (!NT_SUCCESS(Status
))
432 RtlRaiseStatus(Status
);
434 Target
.QuadPart
+= PAGE_SIZE
;
442 ListEntry
= Map
->AssociatedBcb
.Flink
;
444 while (ListEntry
!= &Map
->AssociatedBcb
)
446 Bcb
= CONTAINING_RECORD(ListEntry
, NOCC_BCB
, ThisFileList
);
447 CcpReferenceCache(Bcb
- CcCacheSections
);
449 if (Bcb
->FileOffset
.QuadPart
+ Bcb
->Length
>= LowerBound
.QuadPart
&&
450 Bcb
->FileOffset
.QuadPart
< UpperBound
.QuadPart
)
453 ("Bcb #%x (@%08x%08x)\n",
454 Bcb
- CcCacheSections
,
455 Bcb
->FileOffset
.u
.HighPart
, Bcb
->FileOffset
.u
.LowPart
);
457 Target
.QuadPart
= MAX(Bcb
->FileOffset
.QuadPart
, LowerBound
.QuadPart
);
458 End
.QuadPart
= MIN(Map
->FileSizes
.ValidDataLength
.QuadPart
, UpperBound
.QuadPart
);
459 End
.QuadPart
= MIN(End
.QuadPart
, Bcb
->FileOffset
.QuadPart
+ Bcb
->Length
);
462 if (!CcPreparePinWrite
465 End
.QuadPart
- Target
.QuadPart
,
474 ASSERT(PinnedBcb
== Bcb
);
477 ListEntry
= ListEntry
->Flink
;
478 // Return from pin state
479 CcpUnpinData(PinnedBcb
, TRUE
);
482 CcpUnpinData(Bcb
, TRUE
);
492 CcGetFileObjectFromSectionPtrs(IN PSECTION_OBJECT_POINTERS SectionObjectPointer
)
494 PFILE_OBJECT Result
= NULL
;
495 PNOCC_CACHE_MAP Map
= SectionObjectPointer
->SharedCacheMap
;
497 if (!IsListEmpty(&Map
->AssociatedBcb
))
499 PNOCC_BCB Bcb
= CONTAINING_RECORD(Map
->AssociatedBcb
.Flink
, NOCC_BCB
, ThisFileList
);
500 Result
= MmGetFileObjectForSection((PROS_SECTION_OBJECT
)Bcb
->SectionObject
);
508 CcGetFileObjectFromBcb(PVOID Bcb
)
510 PNOCC_BCB RealBcb
= (PNOCC_BCB
)Bcb
;
511 DPRINT("BCB #%x\n", RealBcb
- CcCacheSections
);
512 return MmGetFileObjectForSection((PROS_SECTION_OBJECT
)RealBcb
->SectionObject
);