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