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
;
29 typedef struct _NOCC_PRIVATE_CACHE_MAP
32 PFILE_OBJECT FileObject
;
34 } NOCC_PRIVATE_CACHE_MAP
, *PNOCC_PRIVATE_CACHE_MAP
;
36 LIST_ENTRY CcpAllSharedCacheMaps
;
38 /* FUNCTIONS ******************************************************************/
40 // Interact with legacy balance manager for now
41 // This can fall away when our section implementation supports
42 // demand paging properly
44 CcRosTrimCache(ULONG Target
, ULONG Priority
, PULONG NrFreed
)
46 ULONG i
, Freed
, BcbHead
;
50 for (i
= 0; i
< CACHE_NUM_SECTIONS
; i
++) {
51 BcbHead
= (i
+CcCacheClockHand
) % CACHE_NUM_SECTIONS
;
53 // Reference a cache stripe so it won't go away
55 if (CcCacheSections
[BcbHead
].BaseAddress
) {
63 // Defer to MM to try recovering pages from it
64 Freed
= MiCacheEvictPages
65 (CcCacheSections
[BcbHead
].BaseAddress
, Target
);
71 CcpDereferenceCache(BcbHead
, FALSE
);
75 return STATUS_SUCCESS
;
80 CcInitializeCacheManager(VOID
)
84 DPRINT("Initialize\n");
85 for (i
= 0; i
< CACHE_NUM_SECTIONS
; i
++)
87 KeInitializeEvent(&CcCacheSections
[i
].ExclusiveWait
, SynchronizationEvent
, FALSE
);
88 InitializeListHead(&CcCacheSections
[i
].ThisFileList
);
91 InitializeListHead(&CcpAllSharedCacheMaps
);
93 KeInitializeEvent(&CcDeleteEvent
, SynchronizationEvent
, FALSE
);
94 KeInitializeEvent(&CcFinalizeEvent
, SynchronizationEvent
, FALSE
);
95 KeInitializeEvent(&CcpLazyWriteEvent
, SynchronizationEvent
, FALSE
);
97 CcCacheBitmap
->Buffer
= ((PULONG
)&CcCacheBitmap
[1]);
98 CcCacheBitmap
->SizeOfBitMap
= ROUND_UP(CACHE_NUM_SECTIONS
, 32);
99 DPRINT("Cache has %d entries\n", CcCacheBitmap
->SizeOfBitMap
);
100 ExInitializeFastMutex(&CcMutex
);
103 KeInitializeEvent(&MmWaitPageEvent
, SynchronizationEvent
, FALSE
);
105 // Until we're fully demand paged, we can do things the old way through
106 // the balance manager
107 MmInitializeMemoryConsumer(MC_CACHE
, CcRosTrimCache
);
114 CcPfInitializePrefetcher(VOID
)
116 /* Notify debugger */
117 DbgPrintEx(DPFLTR_PREFETCHER_ID
,
119 "CCPF: InitializePrefetecher()\n");
121 /* Setup the Prefetcher Data */
122 InitializeListHead(&CcPfGlobals
.ActiveTraces
);
123 InitializeListHead(&CcPfGlobals
.CompletedTraces
);
124 ExInitializeFastMutex(&CcPfGlobals
.CompletedTracesLock
);
126 /* FIXME: Setup the rest of the prefetecher */
131 CcpAcquireFileLock(PNOCC_CACHE_MAP Map
)
133 DPRINT("Calling AcquireForLazyWrite: %x\n", Map
->LazyContext
);
134 return Map
->Callbacks
.AcquireForLazyWrite(Map
->LazyContext
, TRUE
);
139 CcpReleaseFileLock(PNOCC_CACHE_MAP Map
)
141 DPRINT("Releasing Lazy Write %x\n", Map
->LazyContext
);
142 Map
->Callbacks
.ReleaseFromLazyWrite(Map
->LazyContext
);
145 // Must have CcpLock()
146 PFILE_OBJECT
CcpFindOtherStreamFileObject(PFILE_OBJECT FileObject
)
148 PLIST_ENTRY Entry
, Private
;
149 for (Entry
= CcpAllSharedCacheMaps
.Flink
;
150 Entry
!= &CcpAllSharedCacheMaps
;
151 Entry
= Entry
->Flink
)
153 // 'Identical' test for other stream file object
154 PNOCC_CACHE_MAP Map
= CONTAINING_RECORD(Entry
, NOCC_CACHE_MAP
, Entry
);
155 for (Private
= Map
->PrivateCacheMaps
.Flink
;
156 Private
!= &Map
->PrivateCacheMaps
;
157 Private
= Private
->Flink
)
159 PNOCC_PRIVATE_CACHE_MAP PrivateMap
= CONTAINING_RECORD(Private
, NOCC_PRIVATE_CACHE_MAP
, ListEntry
);
160 if (PrivateMap
->FileObject
->Flags
& FO_STREAM_FILE
&&
161 PrivateMap
->FileObject
->DeviceObject
== FileObject
->DeviceObject
&&
162 PrivateMap
->FileObject
->Vpb
== FileObject
->Vpb
&&
163 PrivateMap
->FileObject
->FsContext
== FileObject
->FsContext
&&
164 PrivateMap
->FileObject
->FsContext2
== FileObject
->FsContext2
&&
167 return PrivateMap
->FileObject
;
174 // Thanks: http://windowsitpro.com/Windows/Articles/ArticleID/3864/pg/2/2.html
178 CcInitializeCacheMap(IN PFILE_OBJECT FileObject
,
179 IN PCC_FILE_SIZES FileSizes
,
180 IN BOOLEAN PinAccess
,
181 IN PCACHE_MANAGER_CALLBACKS Callbacks
,
182 IN PVOID LazyWriteContext
)
184 PNOCC_CACHE_MAP Map
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
185 PNOCC_PRIVATE_CACHE_MAP PrivateCacheMap
= FileObject
->PrivateCacheMap
;
188 if (!Map
&& FileObject
->Flags
& FO_STREAM_FILE
)
190 PFILE_OBJECT IdenticalStreamFileObject
=
191 CcpFindOtherStreamFileObject(FileObject
);
192 if (IdenticalStreamFileObject
)
193 Map
= IdenticalStreamFileObject
->SectionObjectPointer
->SharedCacheMap
;
197 ("Linking SFO %x to previous SFO %x through cache map %x #\n",
198 FileObject
, IdenticalStreamFileObject
, Map
);
203 DPRINT("Initializing file object for (%p) %wZ\n", FileObject
, &FileObject
->FileName
);
204 Map
= ExAllocatePool(NonPagedPool
, sizeof(NOCC_CACHE_MAP
));
205 FileObject
->SectionObjectPointer
->SharedCacheMap
= Map
;
206 Map
->FileSizes
= *FileSizes
;
207 Map
->LazyContext
= LazyWriteContext
;
208 Map
->ReadAheadGranularity
= PAGE_SIZE
;
209 RtlCopyMemory(&Map
->Callbacks
, Callbacks
, sizeof(*Callbacks
));
211 DPRINT("FileSizes->ValidDataLength %08x%08x\n", FileSizes
->ValidDataLength
.HighPart
, FileSizes
->ValidDataLength
.LowPart
);
212 InitializeListHead(&Map
->AssociatedBcb
);
213 InitializeListHead(&Map
->PrivateCacheMaps
);
214 InsertTailList(&CcpAllSharedCacheMaps
, &Map
->Entry
);
215 DPRINT("New Map %x\n", Map
);
217 if (!PrivateCacheMap
)
219 PrivateCacheMap
= ExAllocatePool(NonPagedPool
, sizeof(*PrivateCacheMap
));
220 FileObject
->PrivateCacheMap
= PrivateCacheMap
;
221 PrivateCacheMap
->FileObject
= FileObject
;
222 ObReferenceObject(PrivateCacheMap
->FileObject
);
225 PrivateCacheMap
->Map
= Map
;
226 InsertTailList(&Map
->PrivateCacheMaps
, &PrivateCacheMap
->ListEntry
);
233 CcpCountCacheSections(IN PNOCC_CACHE_MAP Map
)
238 for (Count
= 0, Entry
= Map
->AssociatedBcb
.Flink
; Entry
!= &Map
->AssociatedBcb
; Entry
= Entry
->Flink
, Count
++);
245 CcUninitializeCacheMap(IN PFILE_OBJECT FileObject
,
246 IN OPTIONAL PLARGE_INTEGER TruncateSize
,
247 IN OPTIONAL PCACHE_UNINITIALIZE_EVENT UninitializeEvent
)
249 BOOLEAN LastMap
= FALSE
;
250 PNOCC_CACHE_MAP Map
= (PNOCC_CACHE_MAP
)FileObject
->SectionObjectPointer
->SharedCacheMap
;
251 PNOCC_PRIVATE_CACHE_MAP PrivateCacheMap
= FileObject
->PrivateCacheMap
;
253 DPRINT("Uninitializing file object for %wZ SectionObjectPointer %x\n", &FileObject
->FileName
, FileObject
->SectionObjectPointer
);
255 ASSERT(UninitializeEvent
== NULL
);
258 CcpFlushCache(Map
, NULL
, 0, NULL
, FALSE
);
263 ASSERT(!Map
|| Map
== PrivateCacheMap
->Map
);
264 ASSERT(PrivateCacheMap
->FileObject
== FileObject
);
266 RemoveEntryList(&PrivateCacheMap
->ListEntry
);
267 if (IsListEmpty(&PrivateCacheMap
->Map
->PrivateCacheMaps
))
269 while (!IsListEmpty(&Map
->AssociatedBcb
))
271 PNOCC_BCB Bcb
= CONTAINING_RECORD(Map
->AssociatedBcb
.Flink
, NOCC_BCB
, ThisFileList
);
272 DPRINT("Evicting cache stripe #%x\n", Bcb
- CcCacheSections
);
274 CcpDereferenceCache(Bcb
- CcCacheSections
, TRUE
);
276 RemoveEntryList(&PrivateCacheMap
->Map
->Entry
);
277 ExFreePool(PrivateCacheMap
->Map
);
278 FileObject
->SectionObjectPointer
->SharedCacheMap
= NULL
;
281 ObDereferenceObject(PrivateCacheMap
->FileObject
);
282 FileObject
->PrivateCacheMap
= NULL
;
283 ExFreePool(PrivateCacheMap
);
287 DPRINT("Uninit complete\n");
294 CcSetFileSizes(IN PFILE_OBJECT FileObject
,
295 IN PCC_FILE_SIZES FileSizes
)
297 PNOCC_CACHE_MAP Map
= (PNOCC_CACHE_MAP
)FileObject
->SectionObjectPointer
->SharedCacheMap
;
299 Map
->FileSizes
= *FileSizes
;
300 PNOCC_BCB Bcb
= Map
->AssociatedBcb
.Flink
== &Map
->AssociatedBcb
?
301 NULL
: CONTAINING_RECORD(Map
->AssociatedBcb
.Flink
, NOCC_BCB
, ThisFileList
);
303 MmExtendCacheSection(Bcb
->SectionObject
, &FileSizes
->FileSize
, FALSE
);
304 DPRINT("FileSizes->FileSize %x\n", FileSizes
->FileSize
.LowPart
);
305 DPRINT("FileSizes->AllocationSize %x\n", FileSizes
->AllocationSize
.LowPart
);
306 DPRINT("FileSizes->ValidDataLength %x\n", FileSizes
->ValidDataLength
.LowPart
);
312 (IN PFILE_OBJECT FileObject
,
313 IN PCC_FILE_SIZES FileSizes
)
315 PNOCC_CACHE_MAP Map
= (PNOCC_CACHE_MAP
)FileObject
->SectionObjectPointer
->SharedCacheMap
;
316 if (!Map
) return FALSE
;
317 *FileSizes
= Map
->FileSizes
;
323 CcPurgeCacheSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
324 IN OPTIONAL PLARGE_INTEGER FileOffset
,
326 IN BOOLEAN UninitializeCacheMaps
)
328 PNOCC_CACHE_MAP Map
= (PNOCC_CACHE_MAP
)SectionObjectPointer
->SharedCacheMap
;
329 if (!Map
) return TRUE
;
330 CcpFlushCache(Map
, NULL
, 0, NULL
, TRUE
);
336 CcSetDirtyPageThreshold(IN PFILE_OBJECT FileObject
,
337 IN ULONG DirtyPageThreshold
)
345 CcZeroData(IN PFILE_OBJECT FileObject
,
346 IN PLARGE_INTEGER StartOffset
,
347 IN PLARGE_INTEGER EndOffset
,
350 PNOCC_BCB Bcb
= NULL
;
351 PLIST_ENTRY ListEntry
= NULL
;
352 LARGE_INTEGER LowerBound
= *StartOffset
;
353 LARGE_INTEGER UpperBound
= *EndOffset
;
354 LARGE_INTEGER Target
, End
;
355 PVOID PinnedBcb
, PinnedBuffer
;
356 PNOCC_CACHE_MAP Map
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
359 ("S %08x%08x E %08x%08x\n",
360 StartOffset
->u
.HighPart
, StartOffset
->u
.LowPart
,
361 EndOffset
->u
.HighPart
, EndOffset
->u
.LowPart
);
366 IO_STATUS_BLOCK IOSB
;
367 PCHAR ZeroBuf
= ExAllocatePool(PagedPool
, PAGE_SIZE
);
370 if (!ZeroBuf
) RtlRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
371 DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf
, PAGE_SIZE
);
372 RtlZeroMemory(ZeroBuf
, PAGE_SIZE
);
374 Target
.QuadPart
= PAGE_ROUND_DOWN(LowerBound
.QuadPart
);
375 End
.QuadPart
= PAGE_ROUND_UP(UpperBound
.QuadPart
);
377 // Handle leading page
378 if (LowerBound
.QuadPart
!= Target
.QuadPart
)
380 ToWrite
= MIN(UpperBound
.QuadPart
- LowerBound
.QuadPart
, (PAGE_SIZE
- LowerBound
.QuadPart
) & (PAGE_SIZE
- 1));
381 DPRINT("Zero last half %08x%08x %x\n", Target
.u
.HighPart
, Target
.u
.LowPart
, ToWrite
);
382 Status
= MiSimpleRead(FileObject
, &Target
, ZeroBuf
, PAGE_SIZE
, &IOSB
);
383 if (!NT_SUCCESS(Status
))
386 RtlRaiseStatus(Status
);
388 DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf
+ LowerBound
.QuadPart
- Target
.QuadPart
, ToWrite
);
389 RtlZeroMemory(ZeroBuf
+ LowerBound
.QuadPart
- Target
.QuadPart
, ToWrite
);
390 Status
= MiSimpleWrite(FileObject
, &Target
, ZeroBuf
, MIN(PAGE_SIZE
,UpperBound
.QuadPart
-Target
.QuadPart
), &IOSB
);
391 if (!NT_SUCCESS(Status
))
394 RtlRaiseStatus(Status
);
396 Target
.QuadPart
+= PAGE_SIZE
;
399 DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf
, PAGE_SIZE
);
400 RtlZeroMemory(ZeroBuf
, PAGE_SIZE
);
402 while (UpperBound
.QuadPart
- Target
.QuadPart
> PAGE_SIZE
)
404 DPRINT("Zero full page %08x%08x\n", Target
.u
.HighPart
, Target
.u
.LowPart
);
405 Status
= MiSimpleWrite(FileObject
, &Target
, ZeroBuf
, PAGE_SIZE
, &IOSB
);
406 if (!NT_SUCCESS(Status
))
409 RtlRaiseStatus(Status
);
411 Target
.QuadPart
+= PAGE_SIZE
;
414 if (UpperBound
.QuadPart
> Target
.QuadPart
)
416 ToWrite
= UpperBound
.QuadPart
- Target
.QuadPart
;
417 DPRINT("Zero first half %08x%08x %x\n", Target
.u
.HighPart
, Target
.u
.LowPart
, ToWrite
);
418 Status
= MiSimpleRead(FileObject
, &Target
, ZeroBuf
, PAGE_SIZE
, &IOSB
);
419 if (!NT_SUCCESS(Status
))
422 RtlRaiseStatus(Status
);
424 DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf
, ToWrite
);
425 RtlZeroMemory(ZeroBuf
, ToWrite
);
426 Status
= MiSimpleWrite(FileObject
, &Target
, ZeroBuf
, MIN(PAGE_SIZE
, UpperBound
.QuadPart
-Target
.QuadPart
), &IOSB
);
427 if (!NT_SUCCESS(Status
))
430 RtlRaiseStatus(Status
);
432 Target
.QuadPart
+= PAGE_SIZE
;
440 ListEntry
= Map
->AssociatedBcb
.Flink
;
442 while (ListEntry
!= &Map
->AssociatedBcb
)
444 Bcb
= CONTAINING_RECORD(ListEntry
, NOCC_BCB
, ThisFileList
);
445 CcpReferenceCache(Bcb
- CcCacheSections
);
447 if (Bcb
->FileOffset
.QuadPart
+ Bcb
->Length
>= LowerBound
.QuadPart
&&
448 Bcb
->FileOffset
.QuadPart
< UpperBound
.QuadPart
)
451 ("Bcb #%x (@%08x%08x)\n",
452 Bcb
- CcCacheSections
,
453 Bcb
->FileOffset
.u
.HighPart
, Bcb
->FileOffset
.u
.LowPart
);
455 Target
.QuadPart
= MAX(Bcb
->FileOffset
.QuadPart
, LowerBound
.QuadPart
);
456 End
.QuadPart
= MIN(Map
->FileSizes
.ValidDataLength
.QuadPart
, UpperBound
.QuadPart
);
457 End
.QuadPart
= MIN(End
.QuadPart
, Bcb
->FileOffset
.QuadPart
+ Bcb
->Length
);
460 if (!CcPreparePinWrite
463 End
.QuadPart
- Target
.QuadPart
,
472 ASSERT(PinnedBcb
== Bcb
);
475 ListEntry
= ListEntry
->Flink
;
476 // Return from pin state
477 CcpUnpinData(PinnedBcb
);
490 CcGetFileObjectFromSectionPtrs(IN PSECTION_OBJECT_POINTERS SectionObjectPointer
)
492 PFILE_OBJECT Result
= NULL
;
493 PNOCC_CACHE_MAP Map
= SectionObjectPointer
->SharedCacheMap
;
495 if (!IsListEmpty(&Map
->AssociatedBcb
))
497 PNOCC_BCB Bcb
= CONTAINING_RECORD(Map
->AssociatedBcb
.Flink
, NOCC_BCB
, ThisFileList
);
498 Result
= MmGetFileObjectForSection((PROS_SECTION_OBJECT
)Bcb
->SectionObject
);
506 CcGetFileObjectFromBcb(PVOID Bcb
)
508 PNOCC_BCB RealBcb
= (PNOCC_BCB
)Bcb
;
509 DPRINT("BCB #%x\n", RealBcb
- CcCacheSections
);
510 return MmGetFileObjectForSection((PROS_SECTION_OBJECT
)RealBcb
->SectionObject
);