8646513e3b0ad5445b58dfee0a985bffd77a925f
[reactos.git] / ntoskrnl / cache / fssup.c
1 /*
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)
7 * Art Yerkes
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <ntoskrnl.h>
13 #include "newcc.h"
14 #include "section/newmm.h"
15 #define NDEBUG
16 #include <debug.h>
17
18 /* GLOBALS ********************************************************************/
19
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
29 typedef struct _NOCC_PRIVATE_CACHE_MAP
30 {
31 LIST_ENTRY ListEntry;
32 PFILE_OBJECT FileObject;
33 PNOCC_CACHE_MAP Map;
34 } NOCC_PRIVATE_CACHE_MAP, *PNOCC_PRIVATE_CACHE_MAP;
35
36 LIST_ENTRY CcpAllSharedCacheMaps;
37
38 /* FUNCTIONS ******************************************************************/
39
40 // Interact with legacy balance manager for now
41 // This can fall away when our section implementation supports
42 // demand paging properly
43 NTSTATUS
44 CcRosTrimCache(ULONG Target, ULONG Priority, PULONG NrFreed)
45 {
46 ULONG i, Freed, BcbHead;
47
48 *NrFreed = 0;
49
50 for (i = 0; i < CACHE_NUM_SECTIONS; i++) {
51 BcbHead = (i+CcCacheClockHand) % CACHE_NUM_SECTIONS;
52
53 // Reference a cache stripe so it won't go away
54 CcpLock();
55 if (CcCacheSections[BcbHead].BaseAddress) {
56 CcpReferenceCache(i);
57 CcpUnlock();
58 } else {
59 CcpUnlock();
60 continue;
61 }
62
63 // Defer to MM to try recovering pages from it
64 Freed = MiCacheEvictPages
65 (CcCacheSections[BcbHead].BaseAddress, Target);
66
67 Target -= Freed;
68 *NrFreed += Freed;
69
70 CcpLock();
71 CcpDereferenceCache(BcbHead, FALSE);
72 CcpUnlock();
73 }
74
75 return STATUS_SUCCESS;
76 }
77
78 BOOLEAN
79 NTAPI
80 CcInitializeCacheManager(VOID)
81 {
82 int i;
83
84 DPRINT("Initialize\n");
85 for (i = 0; i < CACHE_NUM_SECTIONS; i++)
86 {
87 KeInitializeEvent(&CcCacheSections[i].ExclusiveWait, SynchronizationEvent, FALSE);
88 InitializeListHead(&CcCacheSections[i].ThisFileList);
89 }
90
91 InitializeListHead(&CcpAllSharedCacheMaps);
92
93 KeInitializeEvent(&CcDeleteEvent, SynchronizationEvent, FALSE);
94 KeInitializeEvent(&CcFinalizeEvent, SynchronizationEvent, FALSE);
95 KeInitializeEvent(&CcpLazyWriteEvent, SynchronizationEvent, FALSE);
96
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);
101
102 // MM stub
103 KeInitializeEvent(&MmWaitPageEvent, SynchronizationEvent, FALSE);
104
105 // Until we're fully demand paged, we can do things the old way through
106 // the balance manager
107 MmInitializeMemoryConsumer(MC_CACHE, CcRosTrimCache);
108
109 return TRUE;
110 }
111
112 VOID
113 NTAPI
114 CcPfInitializePrefetcher(VOID)
115 {
116 /* Notify debugger */
117 DbgPrintEx(DPFLTR_PREFETCHER_ID,
118 DPFLTR_TRACE_LEVEL,
119 "CCPF: InitializePrefetecher()\n");
120
121 /* Setup the Prefetcher Data */
122 InitializeListHead(&CcPfGlobals.ActiveTraces);
123 InitializeListHead(&CcPfGlobals.CompletedTraces);
124 ExInitializeFastMutex(&CcPfGlobals.CompletedTracesLock);
125
126 /* FIXME: Setup the rest of the prefetecher */
127 }
128
129 BOOLEAN
130 NTAPI
131 CcpAcquireFileLock(PNOCC_CACHE_MAP Map)
132 {
133 DPRINT("Calling AcquireForLazyWrite: %x\n", Map->LazyContext);
134 return Map->Callbacks.AcquireForLazyWrite(Map->LazyContext, TRUE);
135 }
136
137 VOID
138 NTAPI
139 CcpReleaseFileLock(PNOCC_CACHE_MAP Map)
140 {
141 DPRINT("Releasing Lazy Write %x\n", Map->LazyContext);
142 Map->Callbacks.ReleaseFromLazyWrite(Map->LazyContext);
143 }
144
145 // Must have CcpLock()
146 PFILE_OBJECT CcpFindOtherStreamFileObject(PFILE_OBJECT FileObject)
147 {
148 PLIST_ENTRY Entry, Private;
149 for (Entry = CcpAllSharedCacheMaps.Flink;
150 Entry != &CcpAllSharedCacheMaps;
151 Entry = Entry->Flink)
152 {
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)
158 {
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 &&
165 1)
166 {
167 return PrivateMap->FileObject;
168 }
169 }
170 }
171 return 0;
172 }
173
174 // Thanks: http://windowsitpro.com/Windows/Articles/ArticleID/3864/pg/2/2.html
175 \f
176 VOID
177 NTAPI
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)
183 {
184 PNOCC_CACHE_MAP Map = FileObject->SectionObjectPointer->SharedCacheMap;
185 PNOCC_PRIVATE_CACHE_MAP PrivateCacheMap = FileObject->PrivateCacheMap;
186
187 CcpLock();
188 if (!Map && FileObject->Flags & FO_STREAM_FILE)
189 {
190 PFILE_OBJECT IdenticalStreamFileObject =
191 CcpFindOtherStreamFileObject(FileObject);
192 if (IdenticalStreamFileObject)
193 Map = IdenticalStreamFileObject->SectionObjectPointer->SharedCacheMap;
194 if (Map)
195 {
196 DPRINT1
197 ("Linking SFO %x to previous SFO %x through cache map %x #\n",
198 FileObject, IdenticalStreamFileObject, Map);
199 }
200 }
201 if (!Map)
202 {
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));
210 // For now ...
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);
216 }
217 if (!PrivateCacheMap)
218 {
219 PrivateCacheMap = ExAllocatePool(NonPagedPool, sizeof(*PrivateCacheMap));
220 FileObject->PrivateCacheMap = PrivateCacheMap;
221 PrivateCacheMap->FileObject = FileObject;
222 ObReferenceObject(PrivateCacheMap->FileObject);
223 }
224
225 PrivateCacheMap->Map = Map;
226 InsertTailList(&Map->PrivateCacheMaps, &PrivateCacheMap->ListEntry);
227
228 CcpUnlock();
229 }
230
231 ULONG
232 NTAPI
233 CcpCountCacheSections(IN PNOCC_CACHE_MAP Map)
234 {
235 PLIST_ENTRY Entry;
236 ULONG Count;
237
238 for (Count = 0, Entry = Map->AssociatedBcb.Flink; Entry != &Map->AssociatedBcb; Entry = Entry->Flink, Count++);
239
240 return Count;
241 }
242
243 BOOLEAN
244 NTAPI
245 CcUninitializeCacheMap(IN PFILE_OBJECT FileObject,
246 IN OPTIONAL PLARGE_INTEGER TruncateSize,
247 IN OPTIONAL PCACHE_UNINITIALIZE_EVENT UninitializeEvent)
248 {
249 BOOLEAN LastMap = FALSE;
250 PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
251 PNOCC_PRIVATE_CACHE_MAP PrivateCacheMap = FileObject->PrivateCacheMap;
252
253 DPRINT("Uninitializing file object for %wZ SectionObjectPointer %x\n", &FileObject->FileName, FileObject->SectionObjectPointer);
254
255 ASSERT(UninitializeEvent == NULL);
256
257 if (Map)
258 CcpFlushCache(Map, NULL, 0, NULL, FALSE);
259
260 CcpLock();
261 if (PrivateCacheMap)
262 {
263 ASSERT(!Map || Map == PrivateCacheMap->Map);
264 ASSERT(PrivateCacheMap->FileObject == FileObject);
265
266 RemoveEntryList(&PrivateCacheMap->ListEntry);
267 if (IsListEmpty(&PrivateCacheMap->Map->PrivateCacheMaps))
268 {
269 while (!IsListEmpty(&Map->AssociatedBcb))
270 {
271 PNOCC_BCB Bcb = CONTAINING_RECORD(Map->AssociatedBcb.Flink, NOCC_BCB, ThisFileList);
272 DPRINT("Evicting cache stripe #%x\n", Bcb - CcCacheSections);
273 Bcb->RefCount = 1;
274 CcpDereferenceCache(Bcb - CcCacheSections, TRUE);
275 }
276 RemoveEntryList(&PrivateCacheMap->Map->Entry);
277 ExFreePool(PrivateCacheMap->Map);
278 FileObject->SectionObjectPointer->SharedCacheMap = NULL;
279 LastMap = TRUE;
280 }
281 ObDereferenceObject(PrivateCacheMap->FileObject);
282 FileObject->PrivateCacheMap = NULL;
283 ExFreePool(PrivateCacheMap);
284 }
285 CcpUnlock();
286
287 DPRINT("Uninit complete\n");
288
289 return LastMap;
290 }
291 \f
292 VOID
293 NTAPI
294 CcSetFileSizes(IN PFILE_OBJECT FileObject,
295 IN PCC_FILE_SIZES FileSizes)
296 {
297 PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
298 if (!Map) return;
299 Map->FileSizes = *FileSizes;
300 PNOCC_BCB Bcb = Map->AssociatedBcb.Flink == &Map->AssociatedBcb ?
301 NULL : CONTAINING_RECORD(Map->AssociatedBcb.Flink, NOCC_BCB, ThisFileList);
302 if (!Bcb) return;
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);
307 }
308
309 BOOLEAN
310 NTAPI
311 CcGetFileSizes
312 (IN PFILE_OBJECT FileObject,
313 IN PCC_FILE_SIZES FileSizes)
314 {
315 PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
316 if (!Map) return FALSE;
317 *FileSizes = Map->FileSizes;
318 return TRUE;
319 }
320
321 BOOLEAN
322 NTAPI
323 CcPurgeCacheSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
324 IN OPTIONAL PLARGE_INTEGER FileOffset,
325 IN ULONG Length,
326 IN BOOLEAN UninitializeCacheMaps)
327 {
328 PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap;
329 if (!Map) return TRUE;
330 CcpFlushCache(Map, NULL, 0, NULL, TRUE);
331 return TRUE;
332 }
333 \f
334 VOID
335 NTAPI
336 CcSetDirtyPageThreshold(IN PFILE_OBJECT FileObject,
337 IN ULONG DirtyPageThreshold)
338 {
339 UNIMPLEMENTED;
340 while (TRUE);
341 }
342 \f
343 BOOLEAN
344 NTAPI
345 CcZeroData(IN PFILE_OBJECT FileObject,
346 IN PLARGE_INTEGER StartOffset,
347 IN PLARGE_INTEGER EndOffset,
348 IN BOOLEAN Wait)
349 {
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;
357
358 DPRINT
359 ("S %08x%08x E %08x%08x\n",
360 StartOffset->u.HighPart, StartOffset->u.LowPart,
361 EndOffset->u.HighPart, EndOffset->u.LowPart);
362
363 if (!Map)
364 {
365 NTSTATUS Status;
366 IO_STATUS_BLOCK IOSB;
367 PCHAR ZeroBuf = ExAllocatePool(PagedPool, PAGE_SIZE);
368 ULONG ToWrite;
369
370 if (!ZeroBuf) RtlRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
371 DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf, PAGE_SIZE);
372 RtlZeroMemory(ZeroBuf, PAGE_SIZE);
373
374 Target.QuadPart = PAGE_ROUND_DOWN(LowerBound.QuadPart);
375 End.QuadPart = PAGE_ROUND_UP(UpperBound.QuadPart);
376
377 // Handle leading page
378 if (LowerBound.QuadPart != Target.QuadPart)
379 {
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))
384 {
385 ExFreePool(ZeroBuf);
386 RtlRaiseStatus(Status);
387 }
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))
392 {
393 ExFreePool(ZeroBuf);
394 RtlRaiseStatus(Status);
395 }
396 Target.QuadPart += PAGE_SIZE;
397 }
398
399 DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf, PAGE_SIZE);
400 RtlZeroMemory(ZeroBuf, PAGE_SIZE);
401
402 while (UpperBound.QuadPart - Target.QuadPart > PAGE_SIZE)
403 {
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))
407 {
408 ExFreePool(ZeroBuf);
409 RtlRaiseStatus(Status);
410 }
411 Target.QuadPart += PAGE_SIZE;
412 }
413
414 if (UpperBound.QuadPart > Target.QuadPart)
415 {
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))
420 {
421 ExFreePool(ZeroBuf);
422 RtlRaiseStatus(Status);
423 }
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))
428 {
429 ExFreePool(ZeroBuf);
430 RtlRaiseStatus(Status);
431 }
432 Target.QuadPart += PAGE_SIZE;
433 }
434
435 ExFreePool(ZeroBuf);
436 return TRUE;
437 }
438
439 CcpLock();
440 ListEntry = Map->AssociatedBcb.Flink;
441
442 while (ListEntry != &Map->AssociatedBcb)
443 {
444 Bcb = CONTAINING_RECORD(ListEntry, NOCC_BCB, ThisFileList);
445 CcpReferenceCache(Bcb - CcCacheSections);
446
447 if (Bcb->FileOffset.QuadPart + Bcb->Length >= LowerBound.QuadPart &&
448 Bcb->FileOffset.QuadPart < UpperBound.QuadPart)
449 {
450 DPRINT
451 ("Bcb #%x (@%08x%08x)\n",
452 Bcb - CcCacheSections,
453 Bcb->FileOffset.u.HighPart, Bcb->FileOffset.u.LowPart);
454
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);
458 CcpUnlock();
459
460 if (!CcPreparePinWrite
461 (FileObject,
462 &Target,
463 End.QuadPart - Target.QuadPart,
464 TRUE,
465 Wait,
466 &PinnedBcb,
467 &PinnedBuffer))
468 {
469 return FALSE;
470 }
471
472 ASSERT(PinnedBcb == Bcb);
473
474 CcpLock();
475 ListEntry = ListEntry->Flink;
476 // Return from pin state
477 CcpUnpinData(PinnedBcb);
478 }
479
480 CcpUnpinData(Bcb);
481 }
482
483 CcpUnlock();
484
485 return TRUE;
486 }
487
488 PFILE_OBJECT
489 NTAPI
490 CcGetFileObjectFromSectionPtrs(IN PSECTION_OBJECT_POINTERS SectionObjectPointer)
491 {
492 PFILE_OBJECT Result = NULL;
493 PNOCC_CACHE_MAP Map = SectionObjectPointer->SharedCacheMap;
494 CcpLock();
495 if (!IsListEmpty(&Map->AssociatedBcb))
496 {
497 PNOCC_BCB Bcb = CONTAINING_RECORD(Map->AssociatedBcb.Flink, NOCC_BCB, ThisFileList);
498 Result = MmGetFileObjectForSection((PROS_SECTION_OBJECT)Bcb->SectionObject);
499 }
500 CcpUnlock();
501 return Result;
502 }
503
504 PFILE_OBJECT
505 NTAPI
506 CcGetFileObjectFromBcb(PVOID Bcb)
507 {
508 PNOCC_BCB RealBcb = (PNOCC_BCB)Bcb;
509 DPRINT("BCB #%x\n", RealBcb - CcCacheSections);
510 return MmGetFileObjectForSection((PROS_SECTION_OBJECT)RealBcb->SectionObject);
511 }
512
513 /* EOF */