[NTOSKRNL] Drop the always running thread for lazy writer.
[reactos.git] / ntoskrnl / cc / view.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cc/view.c
5 * PURPOSE: Cache manager
6 *
7 * PROGRAMMERS: David Welch (welch@mcmail.com)
8 * Pierre Schweitzer (pierre@reactos.org)
9 */
10
11 /* NOTES **********************************************************************
12 *
13 * This is not the NT implementation of a file cache nor anything much like
14 * it.
15 *
16 * The general procedure for a filesystem to implement a read or write
17 * dispatch routine is as follows
18 *
19 * (1) If caching for the FCB hasn't been initiated then so do by calling
20 * CcInitializeFileCache.
21 *
22 * (2) For each 4k region which is being read or written obtain a cache page
23 * by calling CcRequestCachePage.
24 *
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.
28 *
29 * (4) Copy the data into or out of the page as necessary.
30 *
31 * (5) Release the cache page
32 */
33 /* INCLUDES ******************************************************************/
34
35 #include <ntoskrnl.h>
36 #define NDEBUG
37 #include <debug.h>
38
39 #if defined (ALLOC_PRAGMA)
40 #pragma alloc_text(INIT, CcInitView)
41 #endif
42
43 /* GLOBALS *******************************************************************/
44
45 LIST_ENTRY DirtyVacbListHead;
46 static LIST_ENTRY VacbLruListHead;
47
48 KGUARDED_MUTEX ViewLock;
49
50 NPAGED_LOOKASIDE_LIST iBcbLookasideList;
51 static NPAGED_LOOKASIDE_LIST SharedCacheMapLookasideList;
52 static NPAGED_LOOKASIDE_LIST VacbLookasideList;
53
54 /* Internal vars (MS):
55 * - Threshold above which lazy writer will start action
56 * - Amount of dirty pages
57 * - List for deferred writes
58 * - Spinlock when dealing with the deferred list
59 * - List for "clean" shared cache maps
60 */
61 ULONG CcDirtyPageThreshold = 0;
62 ULONG CcTotalDirtyPages = 0;
63 LIST_ENTRY CcDeferredWrites;
64 KSPIN_LOCK CcDeferredWriteSpinLock;
65 LIST_ENTRY CcCleanSharedCacheMapList;
66
67 /* Internal vars (ROS):
68 * - Lock for the CcCleanSharedCacheMapList list
69 */
70 KSPIN_LOCK iSharedCacheMapLock;
71
72 #if DBG
73 static void CcRosVacbIncRefCount_(PROS_VACB vacb, const char* file, int line)
74 {
75 ++vacb->ReferenceCount;
76 if (vacb->SharedCacheMap->Trace)
77 {
78 DbgPrint("(%s:%i) VACB %p ++RefCount=%lu, Dirty %u, PageOut %lu\n",
79 file, line, vacb, vacb->ReferenceCount, vacb->Dirty, vacb->PageOut);
80 }
81 }
82 static void CcRosVacbDecRefCount_(PROS_VACB vacb, const char* file, int line)
83 {
84 ASSERT(vacb->ReferenceCount != 0);
85 --vacb->ReferenceCount;
86 ASSERT(!(vacb->ReferenceCount == 0 && vacb->Dirty));
87 if (vacb->SharedCacheMap->Trace)
88 {
89 DbgPrint("(%s:%i) VACB %p --RefCount=%lu, Dirty %u, PageOut %lu\n",
90 file, line, vacb, vacb->ReferenceCount, vacb->Dirty, vacb->PageOut);
91 }
92 }
93 #define CcRosVacbIncRefCount(vacb) CcRosVacbIncRefCount_(vacb,__FILE__,__LINE__)
94 #define CcRosVacbDecRefCount(vacb) CcRosVacbDecRefCount_(vacb,__FILE__,__LINE__)
95 #else
96 #define CcRosVacbIncRefCount(vacb) (++((vacb)->ReferenceCount))
97 #define CcRosVacbDecRefCount(vacb) (--((vacb)->ReferenceCount))
98 #endif
99
100 NTSTATUS
101 CcRosInternalFreeVacb(PROS_VACB Vacb);
102
103
104 /* FUNCTIONS *****************************************************************/
105
106 VOID
107 NTAPI
108 CcRosTraceCacheMap (
109 PROS_SHARED_CACHE_MAP SharedCacheMap,
110 BOOLEAN Trace )
111 {
112 #if DBG
113 KIRQL oldirql;
114 PLIST_ENTRY current_entry;
115 PROS_VACB current;
116
117 if (!SharedCacheMap)
118 return;
119
120 SharedCacheMap->Trace = Trace;
121
122 if (Trace)
123 {
124 DPRINT1("Enabling Tracing for CacheMap 0x%p:\n", SharedCacheMap);
125
126 KeAcquireGuardedMutex(&ViewLock);
127 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldirql);
128
129 current_entry = SharedCacheMap->CacheMapVacbListHead.Flink;
130 while (current_entry != &SharedCacheMap->CacheMapVacbListHead)
131 {
132 current = CONTAINING_RECORD(current_entry, ROS_VACB, CacheMapVacbListEntry);
133 current_entry = current_entry->Flink;
134
135 DPRINT1(" VACB 0x%p enabled, RefCount %lu, Dirty %u, PageOut %lu\n",
136 current, current->ReferenceCount, current->Dirty, current->PageOut );
137 }
138 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql);
139 KeReleaseGuardedMutex(&ViewLock);
140 }
141 else
142 {
143 DPRINT1("Disabling Tracing for CacheMap 0x%p:\n", SharedCacheMap);
144 }
145
146 #else
147 UNREFERENCED_PARAMETER(SharedCacheMap);
148 UNREFERENCED_PARAMETER(Trace);
149 #endif
150 }
151
152 NTSTATUS
153 NTAPI
154 CcRosFlushVacb (
155 PROS_VACB Vacb)
156 {
157 NTSTATUS Status;
158
159 Status = CcWriteVirtualAddress(Vacb);
160 if (NT_SUCCESS(Status))
161 {
162 CcRosUnmarkDirtyVacb(Vacb, TRUE);
163 }
164
165 return Status;
166 }
167
168 NTSTATUS
169 NTAPI
170 CcRosFlushDirtyPages (
171 ULONG Target,
172 PULONG Count,
173 BOOLEAN Wait,
174 BOOLEAN CalledFromLazy)
175 {
176 PLIST_ENTRY current_entry;
177 PROS_VACB current;
178 BOOLEAN Locked;
179 NTSTATUS Status;
180 LARGE_INTEGER ZeroTimeout;
181
182 DPRINT("CcRosFlushDirtyPages(Target %lu)\n", Target);
183
184 (*Count) = 0;
185 ZeroTimeout.QuadPart = 0;
186
187 KeEnterCriticalRegion();
188 KeAcquireGuardedMutex(&ViewLock);
189
190 current_entry = DirtyVacbListHead.Flink;
191 if (current_entry == &DirtyVacbListHead)
192 {
193 DPRINT("No Dirty pages\n");
194 }
195
196 while ((current_entry != &DirtyVacbListHead) && (Target > 0))
197 {
198 current = CONTAINING_RECORD(current_entry,
199 ROS_VACB,
200 DirtyVacbListEntry);
201 current_entry = current_entry->Flink;
202
203 CcRosVacbIncRefCount(current);
204
205 /* When performing lazy write, don't handle temporary files */
206 if (CalledFromLazy &&
207 BooleanFlagOn(current->SharedCacheMap->FileObject->Flags, FO_TEMPORARY_FILE))
208 {
209 CcRosVacbDecRefCount(current);
210 continue;
211 }
212
213 Locked = current->SharedCacheMap->Callbacks->AcquireForLazyWrite(
214 current->SharedCacheMap->LazyWriteContext, Wait);
215 if (!Locked)
216 {
217 CcRosVacbDecRefCount(current);
218 continue;
219 }
220
221 Status = CcRosAcquireVacbLock(current,
222 Wait ? NULL : &ZeroTimeout);
223 if (Status != STATUS_SUCCESS)
224 {
225 current->SharedCacheMap->Callbacks->ReleaseFromLazyWrite(
226 current->SharedCacheMap->LazyWriteContext);
227 CcRosVacbDecRefCount(current);
228 continue;
229 }
230
231 ASSERT(current->Dirty);
232
233 /* One reference is added above */
234 if ((current->ReferenceCount > 2 && current->PinCount == 0) ||
235 (current->ReferenceCount > 3 && current->PinCount > 1))
236 {
237 CcRosReleaseVacbLock(current);
238 current->SharedCacheMap->Callbacks->ReleaseFromLazyWrite(
239 current->SharedCacheMap->LazyWriteContext);
240 CcRosVacbDecRefCount(current);
241 continue;
242 }
243
244 KeReleaseGuardedMutex(&ViewLock);
245
246 Status = CcRosFlushVacb(current);
247
248 CcRosReleaseVacbLock(current);
249 current->SharedCacheMap->Callbacks->ReleaseFromLazyWrite(
250 current->SharedCacheMap->LazyWriteContext);
251
252 KeAcquireGuardedMutex(&ViewLock);
253 CcRosVacbDecRefCount(current);
254
255 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE) &&
256 (Status != STATUS_MEDIA_WRITE_PROTECTED))
257 {
258 DPRINT1("CC: Failed to flush VACB.\n");
259 }
260 else
261 {
262 ULONG PagesFreed;
263
264 /* How many pages did we free? */
265 PagesFreed = VACB_MAPPING_GRANULARITY / PAGE_SIZE;
266 (*Count) += PagesFreed;
267
268 /* Make sure we don't overflow target! */
269 if (Target < PagesFreed)
270 {
271 /* If we would have, jump to zero directly */
272 Target = 0;
273 }
274 else
275 {
276 Target -= PagesFreed;
277 }
278 }
279
280 current_entry = DirtyVacbListHead.Flink;
281 }
282
283 KeReleaseGuardedMutex(&ViewLock);
284 KeLeaveCriticalRegion();
285
286 DPRINT("CcRosFlushDirtyPages() finished\n");
287 return STATUS_SUCCESS;
288 }
289
290 NTSTATUS
291 CcRosTrimCache (
292 ULONG Target,
293 ULONG Priority,
294 PULONG NrFreed)
295 /*
296 * FUNCTION: Try to free some memory from the file cache.
297 * ARGUMENTS:
298 * Target - The number of pages to be freed.
299 * Priority - The priority of free (currently unused).
300 * NrFreed - Points to a variable where the number of pages
301 * actually freed is returned.
302 */
303 {
304 PLIST_ENTRY current_entry;
305 PROS_VACB current;
306 ULONG PagesFreed;
307 KIRQL oldIrql;
308 LIST_ENTRY FreeList;
309 PFN_NUMBER Page;
310 ULONG i;
311 BOOLEAN FlushedPages = FALSE;
312
313 DPRINT("CcRosTrimCache(Target %lu)\n", Target);
314
315 InitializeListHead(&FreeList);
316
317 *NrFreed = 0;
318
319 retry:
320 KeAcquireGuardedMutex(&ViewLock);
321
322 current_entry = VacbLruListHead.Flink;
323 while (current_entry != &VacbLruListHead)
324 {
325 current = CONTAINING_RECORD(current_entry,
326 ROS_VACB,
327 VacbLruListEntry);
328 current_entry = current_entry->Flink;
329
330 KeAcquireSpinLock(&current->SharedCacheMap->CacheMapLock, &oldIrql);
331
332 /* Reference the VACB */
333 CcRosVacbIncRefCount(current);
334
335 /* Check if it's mapped and not dirty */
336 if (current->MappedCount > 0 && !current->Dirty)
337 {
338 /* We have to break these locks because Cc sucks */
339 KeReleaseSpinLock(&current->SharedCacheMap->CacheMapLock, oldIrql);
340 KeReleaseGuardedMutex(&ViewLock);
341
342 /* Page out the VACB */
343 for (i = 0; i < VACB_MAPPING_GRANULARITY / PAGE_SIZE; i++)
344 {
345 Page = (PFN_NUMBER)(MmGetPhysicalAddress((PUCHAR)current->BaseAddress + (i * PAGE_SIZE)).QuadPart >> PAGE_SHIFT);
346
347 MmPageOutPhysicalAddress(Page);
348 }
349
350 /* Reacquire the locks */
351 KeAcquireGuardedMutex(&ViewLock);
352 KeAcquireSpinLock(&current->SharedCacheMap->CacheMapLock, &oldIrql);
353 }
354
355 /* Dereference the VACB */
356 CcRosVacbDecRefCount(current);
357
358 /* Check if we can free this entry now */
359 if (current->ReferenceCount == 0)
360 {
361 ASSERT(!current->Dirty);
362 ASSERT(!current->MappedCount);
363
364 RemoveEntryList(&current->CacheMapVacbListEntry);
365 RemoveEntryList(&current->VacbLruListEntry);
366 InsertHeadList(&FreeList, &current->CacheMapVacbListEntry);
367
368 /* Calculate how many pages we freed for Mm */
369 PagesFreed = min(VACB_MAPPING_GRANULARITY / PAGE_SIZE, Target);
370 Target -= PagesFreed;
371 (*NrFreed) += PagesFreed;
372 }
373
374 KeReleaseSpinLock(&current->SharedCacheMap->CacheMapLock, oldIrql);
375 }
376
377 KeReleaseGuardedMutex(&ViewLock);
378
379 /* Try flushing pages if we haven't met our target */
380 if ((Target > 0) && !FlushedPages)
381 {
382 /* Flush dirty pages to disk */
383 CcRosFlushDirtyPages(Target, &PagesFreed, FALSE, FALSE);
384 FlushedPages = TRUE;
385
386 /* We can only swap as many pages as we flushed */
387 if (PagesFreed < Target) Target = PagesFreed;
388
389 /* Check if we flushed anything */
390 if (PagesFreed != 0)
391 {
392 /* Try again after flushing dirty pages */
393 DPRINT("Flushed %lu dirty cache pages to disk\n", PagesFreed);
394 goto retry;
395 }
396 }
397
398 while (!IsListEmpty(&FreeList))
399 {
400 current_entry = RemoveHeadList(&FreeList);
401 current = CONTAINING_RECORD(current_entry,
402 ROS_VACB,
403 CacheMapVacbListEntry);
404 CcRosInternalFreeVacb(current);
405 }
406
407 DPRINT("Evicted %lu cache pages\n", (*NrFreed));
408
409 return STATUS_SUCCESS;
410 }
411
412 NTSTATUS
413 NTAPI
414 CcRosReleaseVacb (
415 PROS_SHARED_CACHE_MAP SharedCacheMap,
416 PROS_VACB Vacb,
417 BOOLEAN Valid,
418 BOOLEAN Dirty,
419 BOOLEAN Mapped)
420 {
421 ASSERT(SharedCacheMap);
422
423 DPRINT("CcRosReleaseVacb(SharedCacheMap 0x%p, Vacb 0x%p, Valid %u)\n",
424 SharedCacheMap, Vacb, Valid);
425
426 Vacb->Valid = Valid;
427
428 if (Dirty && !Vacb->Dirty)
429 {
430 CcRosMarkDirtyVacb(Vacb);
431 }
432
433 if (Mapped)
434 {
435 Vacb->MappedCount++;
436 }
437 CcRosVacbDecRefCount(Vacb);
438 if (Mapped && (Vacb->MappedCount == 1))
439 {
440 CcRosVacbIncRefCount(Vacb);
441 }
442
443 CcRosReleaseVacbLock(Vacb);
444
445 return STATUS_SUCCESS;
446 }
447
448 /* Returns with VACB Lock Held! */
449 PROS_VACB
450 NTAPI
451 CcRosLookupVacb (
452 PROS_SHARED_CACHE_MAP SharedCacheMap,
453 LONGLONG FileOffset)
454 {
455 PLIST_ENTRY current_entry;
456 PROS_VACB current;
457 KIRQL oldIrql;
458
459 ASSERT(SharedCacheMap);
460
461 DPRINT("CcRosLookupVacb(SharedCacheMap 0x%p, FileOffset %I64u)\n",
462 SharedCacheMap, FileOffset);
463
464 KeAcquireGuardedMutex(&ViewLock);
465 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql);
466
467 current_entry = SharedCacheMap->CacheMapVacbListHead.Flink;
468 while (current_entry != &SharedCacheMap->CacheMapVacbListHead)
469 {
470 current = CONTAINING_RECORD(current_entry,
471 ROS_VACB,
472 CacheMapVacbListEntry);
473 if (IsPointInRange(current->FileOffset.QuadPart,
474 VACB_MAPPING_GRANULARITY,
475 FileOffset))
476 {
477 CcRosVacbIncRefCount(current);
478 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
479 KeReleaseGuardedMutex(&ViewLock);
480 CcRosAcquireVacbLock(current, NULL);
481 return current;
482 }
483 if (current->FileOffset.QuadPart > FileOffset)
484 break;
485 current_entry = current_entry->Flink;
486 }
487
488 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
489 KeReleaseGuardedMutex(&ViewLock);
490
491 return NULL;
492 }
493
494 VOID
495 NTAPI
496 CcRosMarkDirtyVacb (
497 PROS_VACB Vacb)
498 {
499 KIRQL oldIrql;
500 PROS_SHARED_CACHE_MAP SharedCacheMap;
501
502 SharedCacheMap = Vacb->SharedCacheMap;
503
504 KeAcquireGuardedMutex(&ViewLock);
505 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql);
506
507 ASSERT(!Vacb->Dirty);
508
509 InsertTailList(&DirtyVacbListHead, &Vacb->DirtyVacbListEntry);
510 CcTotalDirtyPages += VACB_MAPPING_GRANULARITY / PAGE_SIZE;
511 Vacb->SharedCacheMap->DirtyPages += VACB_MAPPING_GRANULARITY / PAGE_SIZE;
512 CcRosVacbIncRefCount(Vacb);
513
514 /* Move to the tail of the LRU list */
515 RemoveEntryList(&Vacb->VacbLruListEntry);
516 InsertTailList(&VacbLruListHead, &Vacb->VacbLruListEntry);
517
518 Vacb->Dirty = TRUE;
519
520 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
521 KeReleaseGuardedMutex(&ViewLock);
522
523 /* FIXME: lock master */
524 if (!LazyWriter.ScanActive)
525 {
526 CcScheduleLazyWriteScan(FALSE);
527 }
528 }
529
530 VOID
531 NTAPI
532 CcRosUnmarkDirtyVacb (
533 PROS_VACB Vacb,
534 BOOLEAN LockViews)
535 {
536 KIRQL oldIrql;
537 PROS_SHARED_CACHE_MAP SharedCacheMap;
538
539 SharedCacheMap = Vacb->SharedCacheMap;
540
541 if (LockViews)
542 {
543 KeAcquireGuardedMutex(&ViewLock);
544 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql);
545 }
546
547 ASSERT(Vacb->Dirty);
548
549 Vacb->Dirty = FALSE;
550
551 RemoveEntryList(&Vacb->DirtyVacbListEntry);
552 CcTotalDirtyPages -= VACB_MAPPING_GRANULARITY / PAGE_SIZE;
553 Vacb->SharedCacheMap->DirtyPages -= VACB_MAPPING_GRANULARITY / PAGE_SIZE;
554 CcRosVacbDecRefCount(Vacb);
555
556 if (LockViews)
557 {
558 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
559 KeReleaseGuardedMutex(&ViewLock);
560 }
561 }
562
563 NTSTATUS
564 NTAPI
565 CcRosMarkDirtyFile (
566 PROS_SHARED_CACHE_MAP SharedCacheMap,
567 LONGLONG FileOffset)
568 {
569 PROS_VACB Vacb;
570
571 ASSERT(SharedCacheMap);
572
573 DPRINT("CcRosMarkDirtyVacb(SharedCacheMap 0x%p, FileOffset %I64u)\n",
574 SharedCacheMap, FileOffset);
575
576 Vacb = CcRosLookupVacb(SharedCacheMap, FileOffset);
577 if (Vacb == NULL)
578 {
579 KeBugCheck(CACHE_MANAGER);
580 }
581
582 if (!Vacb->Dirty)
583 {
584 CcRosMarkDirtyVacb(Vacb);
585 }
586
587 CcRosReleaseVacbLock(Vacb);
588
589 return STATUS_SUCCESS;
590 }
591
592 NTSTATUS
593 NTAPI
594 CcRosUnmapVacb (
595 PROS_SHARED_CACHE_MAP SharedCacheMap,
596 LONGLONG FileOffset,
597 BOOLEAN NowDirty)
598 {
599 PROS_VACB Vacb;
600
601 ASSERT(SharedCacheMap);
602
603 DPRINT("CcRosUnmapVacb(SharedCacheMap 0x%p, FileOffset %I64u, NowDirty %u)\n",
604 SharedCacheMap, FileOffset, NowDirty);
605
606 Vacb = CcRosLookupVacb(SharedCacheMap, FileOffset);
607 if (Vacb == NULL)
608 {
609 return STATUS_UNSUCCESSFUL;
610 }
611
612 if (NowDirty && !Vacb->Dirty)
613 {
614 CcRosMarkDirtyVacb(Vacb);
615 }
616
617 ASSERT(Vacb->MappedCount != 0);
618 Vacb->MappedCount--;
619
620 CcRosVacbDecRefCount(Vacb);
621 if (Vacb->MappedCount == 0)
622 {
623 CcRosVacbDecRefCount(Vacb);
624 }
625
626 CcRosReleaseVacbLock(Vacb);
627
628 return STATUS_SUCCESS;
629 }
630
631 static
632 NTSTATUS
633 CcRosMapVacb(
634 PROS_VACB Vacb)
635 {
636 ULONG i;
637 NTSTATUS Status;
638 ULONG_PTR NumberOfPages;
639
640 /* Create a memory area. */
641 MmLockAddressSpace(MmGetKernelAddressSpace());
642 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
643 0, // nothing checks for VACB mareas, so set to 0
644 &Vacb->BaseAddress,
645 VACB_MAPPING_GRANULARITY,
646 PAGE_READWRITE,
647 (PMEMORY_AREA*)&Vacb->MemoryArea,
648 0,
649 PAGE_SIZE);
650 MmUnlockAddressSpace(MmGetKernelAddressSpace());
651 if (!NT_SUCCESS(Status))
652 {
653 DPRINT1("MmCreateMemoryArea failed with %lx for VACB %p\n", Status, Vacb);
654 return Status;
655 }
656
657 ASSERT(((ULONG_PTR)Vacb->BaseAddress % PAGE_SIZE) == 0);
658 ASSERT((ULONG_PTR)Vacb->BaseAddress > (ULONG_PTR)MmSystemRangeStart);
659
660 /* Create a virtual mapping for this memory area */
661 NumberOfPages = BYTES_TO_PAGES(VACB_MAPPING_GRANULARITY);
662 for (i = 0; i < NumberOfPages; i++)
663 {
664 PFN_NUMBER PageFrameNumber;
665
666 MI_SET_USAGE(MI_USAGE_CACHE);
667 Status = MmRequestPageMemoryConsumer(MC_CACHE, TRUE, &PageFrameNumber);
668 if (PageFrameNumber == 0)
669 {
670 DPRINT1("Unable to allocate page\n");
671 KeBugCheck(MEMORY_MANAGEMENT);
672 }
673
674 Status = MmCreateVirtualMapping(NULL,
675 (PVOID)((ULONG_PTR)Vacb->BaseAddress + (i * PAGE_SIZE)),
676 PAGE_READWRITE,
677 &PageFrameNumber,
678 1);
679 if (!NT_SUCCESS(Status))
680 {
681 DPRINT1("Unable to create virtual mapping\n");
682 KeBugCheck(MEMORY_MANAGEMENT);
683 }
684 }
685
686 return STATUS_SUCCESS;
687 }
688
689 static
690 NTSTATUS
691 CcRosCreateVacb (
692 PROS_SHARED_CACHE_MAP SharedCacheMap,
693 LONGLONG FileOffset,
694 PROS_VACB *Vacb)
695 {
696 PROS_VACB current;
697 PROS_VACB previous;
698 PLIST_ENTRY current_entry;
699 NTSTATUS Status;
700 KIRQL oldIrql;
701
702 ASSERT(SharedCacheMap);
703
704 DPRINT("CcRosCreateVacb()\n");
705
706 if (FileOffset >= SharedCacheMap->SectionSize.QuadPart)
707 {
708 *Vacb = NULL;
709 return STATUS_INVALID_PARAMETER;
710 }
711
712 current = ExAllocateFromNPagedLookasideList(&VacbLookasideList);
713 current->BaseAddress = NULL;
714 current->Valid = FALSE;
715 current->Dirty = FALSE;
716 current->PageOut = FALSE;
717 current->FileOffset.QuadPart = ROUND_DOWN(FileOffset, VACB_MAPPING_GRANULARITY);
718 current->SharedCacheMap = SharedCacheMap;
719 #if DBG
720 if (SharedCacheMap->Trace)
721 {
722 DPRINT1("CacheMap 0x%p: new VACB: 0x%p\n", SharedCacheMap, current);
723 }
724 #endif
725 current->MappedCount = 0;
726 current->DirtyVacbListEntry.Flink = NULL;
727 current->DirtyVacbListEntry.Blink = NULL;
728 current->ReferenceCount = 1;
729 current->PinCount = 0;
730 KeInitializeMutex(&current->Mutex, 0);
731 CcRosAcquireVacbLock(current, NULL);
732 KeAcquireGuardedMutex(&ViewLock);
733
734 *Vacb = current;
735 /* There is window between the call to CcRosLookupVacb
736 * and CcRosCreateVacb. We must check if a VACB for the
737 * file offset exist. If there is a VACB, we release
738 * our newly created VACB and return the existing one.
739 */
740 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql);
741 current_entry = SharedCacheMap->CacheMapVacbListHead.Flink;
742 previous = NULL;
743 while (current_entry != &SharedCacheMap->CacheMapVacbListHead)
744 {
745 current = CONTAINING_RECORD(current_entry,
746 ROS_VACB,
747 CacheMapVacbListEntry);
748 if (IsPointInRange(current->FileOffset.QuadPart,
749 VACB_MAPPING_GRANULARITY,
750 FileOffset))
751 {
752 CcRosVacbIncRefCount(current);
753 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
754 #if DBG
755 if (SharedCacheMap->Trace)
756 {
757 DPRINT1("CacheMap 0x%p: deleting newly created VACB 0x%p ( found existing one 0x%p )\n",
758 SharedCacheMap,
759 (*Vacb),
760 current);
761 }
762 #endif
763 CcRosReleaseVacbLock(*Vacb);
764 KeReleaseGuardedMutex(&ViewLock);
765 ExFreeToNPagedLookasideList(&VacbLookasideList, *Vacb);
766 *Vacb = current;
767 CcRosAcquireVacbLock(current, NULL);
768 return STATUS_SUCCESS;
769 }
770 if (current->FileOffset.QuadPart < FileOffset)
771 {
772 ASSERT(previous == NULL ||
773 previous->FileOffset.QuadPart < current->FileOffset.QuadPart);
774 previous = current;
775 }
776 if (current->FileOffset.QuadPart > FileOffset)
777 break;
778 current_entry = current_entry->Flink;
779 }
780 /* There was no existing VACB. */
781 current = *Vacb;
782 if (previous)
783 {
784 InsertHeadList(&previous->CacheMapVacbListEntry, &current->CacheMapVacbListEntry);
785 }
786 else
787 {
788 InsertHeadList(&SharedCacheMap->CacheMapVacbListHead, &current->CacheMapVacbListEntry);
789 }
790 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
791 InsertTailList(&VacbLruListHead, &current->VacbLruListEntry);
792 KeReleaseGuardedMutex(&ViewLock);
793
794 MI_SET_USAGE(MI_USAGE_CACHE);
795 #if MI_TRACE_PFNS
796 if ((SharedCacheMap->FileObject) && (SharedCacheMap->FileObject->FileName.Buffer))
797 {
798 PWCHAR pos;
799 ULONG len = 0;
800 pos = wcsrchr(SharedCacheMap->FileObject->FileName.Buffer, '\\');
801 if (pos)
802 {
803 len = wcslen(pos) * sizeof(WCHAR);
804 snprintf(MI_PFN_CURRENT_PROCESS_NAME, min(16, len), "%S", pos);
805 }
806 else
807 {
808 snprintf(MI_PFN_CURRENT_PROCESS_NAME, min(16, len), "%wZ", &SharedCacheMap->FileObject->FileName);
809 }
810 }
811 #endif
812
813 Status = CcRosMapVacb(current);
814 if (!NT_SUCCESS(Status))
815 {
816 RemoveEntryList(&current->CacheMapVacbListEntry);
817 RemoveEntryList(&current->VacbLruListEntry);
818 CcRosReleaseVacbLock(current);
819 ExFreeToNPagedLookasideList(&VacbLookasideList, current);
820 }
821
822 return Status;
823 }
824
825 NTSTATUS
826 NTAPI
827 CcRosGetVacb (
828 PROS_SHARED_CACHE_MAP SharedCacheMap,
829 LONGLONG FileOffset,
830 PLONGLONG BaseOffset,
831 PVOID* BaseAddress,
832 PBOOLEAN UptoDate,
833 PROS_VACB *Vacb)
834 {
835 PROS_VACB current;
836 NTSTATUS Status;
837
838 ASSERT(SharedCacheMap);
839
840 DPRINT("CcRosGetVacb()\n");
841
842 /*
843 * Look for a VACB already mapping the same data.
844 */
845 current = CcRosLookupVacb(SharedCacheMap, FileOffset);
846 if (current == NULL)
847 {
848 /*
849 * Otherwise create a new VACB.
850 */
851 Status = CcRosCreateVacb(SharedCacheMap, FileOffset, &current);
852 if (!NT_SUCCESS(Status))
853 {
854 return Status;
855 }
856 }
857
858 KeAcquireGuardedMutex(&ViewLock);
859
860 /* Move to the tail of the LRU list */
861 RemoveEntryList(&current->VacbLruListEntry);
862 InsertTailList(&VacbLruListHead, &current->VacbLruListEntry);
863
864 KeReleaseGuardedMutex(&ViewLock);
865
866 /*
867 * Return information about the VACB to the caller.
868 */
869 *UptoDate = current->Valid;
870 *BaseAddress = current->BaseAddress;
871 DPRINT("*BaseAddress %p\n", *BaseAddress);
872 *Vacb = current;
873 *BaseOffset = current->FileOffset.QuadPart;
874 return STATUS_SUCCESS;
875 }
876
877 NTSTATUS
878 NTAPI
879 CcRosRequestVacb (
880 PROS_SHARED_CACHE_MAP SharedCacheMap,
881 LONGLONG FileOffset,
882 PVOID* BaseAddress,
883 PBOOLEAN UptoDate,
884 PROS_VACB *Vacb)
885 /*
886 * FUNCTION: Request a page mapping for a shared cache map
887 */
888 {
889 LONGLONG BaseOffset;
890
891 ASSERT(SharedCacheMap);
892
893 if (FileOffset % VACB_MAPPING_GRANULARITY != 0)
894 {
895 DPRINT1("Bad fileoffset %I64x should be multiple of %x",
896 FileOffset, VACB_MAPPING_GRANULARITY);
897 KeBugCheck(CACHE_MANAGER);
898 }
899
900 return CcRosGetVacb(SharedCacheMap,
901 FileOffset,
902 &BaseOffset,
903 BaseAddress,
904 UptoDate,
905 Vacb);
906 }
907
908 static
909 VOID
910 CcFreeCachePage (
911 PVOID Context,
912 MEMORY_AREA* MemoryArea,
913 PVOID Address,
914 PFN_NUMBER Page,
915 SWAPENTRY SwapEntry,
916 BOOLEAN Dirty)
917 {
918 ASSERT(SwapEntry == 0);
919 if (Page != 0)
920 {
921 ASSERT(MmGetReferenceCountPage(Page) == 1);
922 MmReleasePageMemoryConsumer(MC_CACHE, Page);
923 }
924 }
925
926 NTSTATUS
927 CcRosInternalFreeVacb (
928 PROS_VACB Vacb)
929 /*
930 * FUNCTION: Releases a VACB associated with a shared cache map
931 */
932 {
933 DPRINT("Freeing VACB 0x%p\n", Vacb);
934 #if DBG
935 if (Vacb->SharedCacheMap->Trace)
936 {
937 DPRINT1("CacheMap 0x%p: deleting VACB: 0x%p\n", Vacb->SharedCacheMap, Vacb);
938 }
939 #endif
940
941 MmLockAddressSpace(MmGetKernelAddressSpace());
942 MmFreeMemoryArea(MmGetKernelAddressSpace(),
943 Vacb->MemoryArea,
944 CcFreeCachePage,
945 NULL);
946 MmUnlockAddressSpace(MmGetKernelAddressSpace());
947
948 ExFreeToNPagedLookasideList(&VacbLookasideList, Vacb);
949 return STATUS_SUCCESS;
950 }
951
952 /*
953 * @implemented
954 */
955 VOID
956 NTAPI
957 CcFlushCache (
958 IN PSECTION_OBJECT_POINTERS SectionObjectPointers,
959 IN PLARGE_INTEGER FileOffset OPTIONAL,
960 IN ULONG Length,
961 OUT PIO_STATUS_BLOCK IoStatus)
962 {
963 PROS_SHARED_CACHE_MAP SharedCacheMap;
964 LARGE_INTEGER Offset;
965 LONGLONG RemainingLength;
966 PROS_VACB current;
967 NTSTATUS Status;
968 KIRQL oldIrql;
969
970 CCTRACE(CC_API_DEBUG, "SectionObjectPointers=%p FileOffset=%p Length=%lu\n",
971 SectionObjectPointers, FileOffset, Length);
972
973 DPRINT("CcFlushCache(SectionObjectPointers 0x%p, FileOffset 0x%p, Length %lu, IoStatus 0x%p)\n",
974 SectionObjectPointers, FileOffset, Length, IoStatus);
975
976 if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap)
977 {
978 SharedCacheMap = SectionObjectPointers->SharedCacheMap;
979 ASSERT(SharedCacheMap);
980 if (FileOffset)
981 {
982 Offset = *FileOffset;
983 RemainingLength = Length;
984 }
985 else
986 {
987 Offset.QuadPart = 0;
988 RemainingLength = SharedCacheMap->FileSize.QuadPart;
989 }
990
991 if (IoStatus)
992 {
993 IoStatus->Status = STATUS_SUCCESS;
994 IoStatus->Information = 0;
995 }
996
997 while (RemainingLength > 0)
998 {
999 current = CcRosLookupVacb(SharedCacheMap, Offset.QuadPart);
1000 if (current != NULL)
1001 {
1002 if (current->Dirty)
1003 {
1004 Status = CcRosFlushVacb(current);
1005 if (!NT_SUCCESS(Status) && IoStatus != NULL)
1006 {
1007 IoStatus->Status = Status;
1008 }
1009 }
1010
1011 CcRosReleaseVacbLock(current);
1012
1013 KeAcquireGuardedMutex(&ViewLock);
1014 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql);
1015 CcRosVacbDecRefCount(current);
1016 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
1017 KeReleaseGuardedMutex(&ViewLock);
1018 }
1019
1020 Offset.QuadPart += VACB_MAPPING_GRANULARITY;
1021 RemainingLength -= min(RemainingLength, VACB_MAPPING_GRANULARITY);
1022 }
1023 }
1024 else
1025 {
1026 if (IoStatus)
1027 {
1028 IoStatus->Status = STATUS_INVALID_PARAMETER;
1029 }
1030 }
1031 }
1032
1033 NTSTATUS
1034 NTAPI
1035 CcRosDeleteFileCache (
1036 PFILE_OBJECT FileObject,
1037 PROS_SHARED_CACHE_MAP SharedCacheMap)
1038 /*
1039 * FUNCTION: Releases the shared cache map associated with a file object
1040 */
1041 {
1042 PLIST_ENTRY current_entry;
1043 PROS_VACB current;
1044 LIST_ENTRY FreeList;
1045 KIRQL oldIrql;
1046
1047 ASSERT(SharedCacheMap);
1048
1049 SharedCacheMap->OpenCount++;
1050 KeReleaseGuardedMutex(&ViewLock);
1051
1052 CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, NULL);
1053
1054 KeAcquireGuardedMutex(&ViewLock);
1055 SharedCacheMap->OpenCount--;
1056 if (SharedCacheMap->OpenCount == 0)
1057 {
1058 KIRQL OldIrql;
1059
1060 FileObject->SectionObjectPointer->SharedCacheMap = NULL;
1061
1062 /*
1063 * Release all VACBs
1064 */
1065 InitializeListHead(&FreeList);
1066 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql);
1067 while (!IsListEmpty(&SharedCacheMap->CacheMapVacbListHead))
1068 {
1069 current_entry = RemoveTailList(&SharedCacheMap->CacheMapVacbListHead);
1070 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
1071
1072 current = CONTAINING_RECORD(current_entry, ROS_VACB, CacheMapVacbListEntry);
1073 CcRosAcquireVacbLock(current, NULL);
1074 RemoveEntryList(&current->VacbLruListEntry);
1075 if (current->Dirty)
1076 {
1077 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql);
1078 CcRosUnmarkDirtyVacb(current, FALSE);
1079 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
1080 DPRINT1("Freeing dirty VACB\n");
1081 }
1082 InsertHeadList(&FreeList, &current->CacheMapVacbListEntry);
1083 CcRosReleaseVacbLock(current);
1084
1085 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql);
1086 }
1087 #if DBG
1088 SharedCacheMap->Trace = FALSE;
1089 #endif
1090 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql);
1091
1092 KeReleaseGuardedMutex(&ViewLock);
1093 ObDereferenceObject(SharedCacheMap->FileObject);
1094
1095 while (!IsListEmpty(&FreeList))
1096 {
1097 current_entry = RemoveTailList(&FreeList);
1098 current = CONTAINING_RECORD(current_entry, ROS_VACB, CacheMapVacbListEntry);
1099 CcRosInternalFreeVacb(current);
1100 }
1101
1102 KeAcquireSpinLock(&iSharedCacheMapLock, &OldIrql);
1103 RemoveEntryList(&SharedCacheMap->SharedCacheMapLinks);
1104 KeReleaseSpinLock(&iSharedCacheMapLock, OldIrql);
1105
1106 ExFreeToNPagedLookasideList(&SharedCacheMapLookasideList, SharedCacheMap);
1107 KeAcquireGuardedMutex(&ViewLock);
1108 }
1109 return STATUS_SUCCESS;
1110 }
1111
1112 VOID
1113 NTAPI
1114 CcRosReferenceCache (
1115 PFILE_OBJECT FileObject)
1116 {
1117 PROS_SHARED_CACHE_MAP SharedCacheMap;
1118 KeAcquireGuardedMutex(&ViewLock);
1119 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
1120 ASSERT(SharedCacheMap);
1121 ASSERT(SharedCacheMap->OpenCount != 0);
1122 SharedCacheMap->OpenCount++;
1123 KeReleaseGuardedMutex(&ViewLock);
1124 }
1125
1126 VOID
1127 NTAPI
1128 CcRosRemoveIfClosed (
1129 PSECTION_OBJECT_POINTERS SectionObjectPointer)
1130 {
1131 PROS_SHARED_CACHE_MAP SharedCacheMap;
1132 DPRINT("CcRosRemoveIfClosed()\n");
1133 KeAcquireGuardedMutex(&ViewLock);
1134 SharedCacheMap = SectionObjectPointer->SharedCacheMap;
1135 if (SharedCacheMap && SharedCacheMap->OpenCount == 0)
1136 {
1137 CcRosDeleteFileCache(SharedCacheMap->FileObject, SharedCacheMap);
1138 }
1139 KeReleaseGuardedMutex(&ViewLock);
1140 }
1141
1142
1143 VOID
1144 NTAPI
1145 CcRosDereferenceCache (
1146 PFILE_OBJECT FileObject)
1147 {
1148 PROS_SHARED_CACHE_MAP SharedCacheMap;
1149 KeAcquireGuardedMutex(&ViewLock);
1150 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
1151 ASSERT(SharedCacheMap);
1152 if (SharedCacheMap->OpenCount > 0)
1153 {
1154 SharedCacheMap->OpenCount--;
1155 if (SharedCacheMap->OpenCount == 0)
1156 {
1157 MmFreeSectionSegments(SharedCacheMap->FileObject);
1158 CcRosDeleteFileCache(FileObject, SharedCacheMap);
1159 }
1160 }
1161 KeReleaseGuardedMutex(&ViewLock);
1162 }
1163
1164 NTSTATUS
1165 NTAPI
1166 CcRosReleaseFileCache (
1167 PFILE_OBJECT FileObject)
1168 /*
1169 * FUNCTION: Called by the file system when a handle to a file object
1170 * has been closed.
1171 */
1172 {
1173 PROS_SHARED_CACHE_MAP SharedCacheMap;
1174
1175 KeAcquireGuardedMutex(&ViewLock);
1176
1177 if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
1178 {
1179 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
1180 if (FileObject->PrivateCacheMap != NULL)
1181 {
1182 FileObject->PrivateCacheMap = NULL;
1183 if (SharedCacheMap->OpenCount > 0)
1184 {
1185 SharedCacheMap->OpenCount--;
1186 if (SharedCacheMap->OpenCount == 0)
1187 {
1188 MmFreeSectionSegments(SharedCacheMap->FileObject);
1189 CcRosDeleteFileCache(FileObject, SharedCacheMap);
1190 }
1191 }
1192 }
1193 }
1194 KeReleaseGuardedMutex(&ViewLock);
1195 return STATUS_SUCCESS;
1196 }
1197
1198 NTSTATUS
1199 NTAPI
1200 CcTryToInitializeFileCache (
1201 PFILE_OBJECT FileObject)
1202 {
1203 PROS_SHARED_CACHE_MAP SharedCacheMap;
1204 NTSTATUS Status;
1205
1206 KeAcquireGuardedMutex(&ViewLock);
1207
1208 ASSERT(FileObject->SectionObjectPointer);
1209 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
1210 if (SharedCacheMap == NULL)
1211 {
1212 Status = STATUS_UNSUCCESSFUL;
1213 }
1214 else
1215 {
1216 if (FileObject->PrivateCacheMap == NULL)
1217 {
1218 FileObject->PrivateCacheMap = SharedCacheMap;
1219 SharedCacheMap->OpenCount++;
1220 }
1221 Status = STATUS_SUCCESS;
1222 }
1223 KeReleaseGuardedMutex(&ViewLock);
1224
1225 return Status;
1226 }
1227
1228
1229 NTSTATUS
1230 NTAPI
1231 CcRosInitializeFileCache (
1232 PFILE_OBJECT FileObject,
1233 PCC_FILE_SIZES FileSizes,
1234 BOOLEAN PinAccess,
1235 PCACHE_MANAGER_CALLBACKS CallBacks,
1236 PVOID LazyWriterContext)
1237 /*
1238 * FUNCTION: Initializes a shared cache map for a file object
1239 */
1240 {
1241 PROS_SHARED_CACHE_MAP SharedCacheMap;
1242
1243 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
1244 DPRINT("CcRosInitializeFileCache(FileObject 0x%p, SharedCacheMap 0x%p)\n",
1245 FileObject, SharedCacheMap);
1246
1247 KeAcquireGuardedMutex(&ViewLock);
1248 if (SharedCacheMap == NULL)
1249 {
1250 KIRQL OldIrql;
1251
1252 SharedCacheMap = ExAllocateFromNPagedLookasideList(&SharedCacheMapLookasideList);
1253 if (SharedCacheMap == NULL)
1254 {
1255 KeReleaseGuardedMutex(&ViewLock);
1256 return STATUS_INSUFFICIENT_RESOURCES;
1257 }
1258 RtlZeroMemory(SharedCacheMap, sizeof(*SharedCacheMap));
1259 ObReferenceObjectByPointer(FileObject,
1260 FILE_ALL_ACCESS,
1261 NULL,
1262 KernelMode);
1263 SharedCacheMap->FileObject = FileObject;
1264 SharedCacheMap->Callbacks = CallBacks;
1265 SharedCacheMap->LazyWriteContext = LazyWriterContext;
1266 SharedCacheMap->SectionSize = FileSizes->AllocationSize;
1267 SharedCacheMap->FileSize = FileSizes->FileSize;
1268 SharedCacheMap->PinAccess = PinAccess;
1269 SharedCacheMap->DirtyPageThreshold = 0;
1270 SharedCacheMap->DirtyPages = 0;
1271 KeInitializeSpinLock(&SharedCacheMap->CacheMapLock);
1272 InitializeListHead(&SharedCacheMap->CacheMapVacbListHead);
1273 FileObject->SectionObjectPointer->SharedCacheMap = SharedCacheMap;
1274
1275 KeAcquireSpinLock(&iSharedCacheMapLock, &OldIrql);
1276 InsertTailList(&CcCleanSharedCacheMapList, &SharedCacheMap->SharedCacheMapLinks);
1277 KeReleaseSpinLock(&iSharedCacheMapLock, OldIrql);
1278 }
1279 if (FileObject->PrivateCacheMap == NULL)
1280 {
1281 FileObject->PrivateCacheMap = SharedCacheMap;
1282 SharedCacheMap->OpenCount++;
1283 }
1284 KeReleaseGuardedMutex(&ViewLock);
1285
1286 return STATUS_SUCCESS;
1287 }
1288
1289 /*
1290 * @implemented
1291 */
1292 PFILE_OBJECT
1293 NTAPI
1294 CcGetFileObjectFromSectionPtrs (
1295 IN PSECTION_OBJECT_POINTERS SectionObjectPointers)
1296 {
1297 PROS_SHARED_CACHE_MAP SharedCacheMap;
1298
1299 CCTRACE(CC_API_DEBUG, "SectionObjectPointers=%p\n", SectionObjectPointers);
1300
1301 if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap)
1302 {
1303 SharedCacheMap = SectionObjectPointers->SharedCacheMap;
1304 ASSERT(SharedCacheMap);
1305 return SharedCacheMap->FileObject;
1306 }
1307 return NULL;
1308 }
1309
1310 VOID
1311 INIT_FUNCTION
1312 NTAPI
1313 CcInitView (
1314 VOID)
1315 {
1316 DPRINT("CcInitView()\n");
1317
1318 InitializeListHead(&DirtyVacbListHead);
1319 InitializeListHead(&VacbLruListHead);
1320 InitializeListHead(&CcDeferredWrites);
1321 InitializeListHead(&CcCleanSharedCacheMapList);
1322 KeInitializeSpinLock(&CcDeferredWriteSpinLock);
1323 KeInitializeSpinLock(&iSharedCacheMapLock);
1324 KeInitializeGuardedMutex(&ViewLock);
1325 ExInitializeNPagedLookasideList(&iBcbLookasideList,
1326 NULL,
1327 NULL,
1328 0,
1329 sizeof(INTERNAL_BCB),
1330 TAG_BCB,
1331 20);
1332 ExInitializeNPagedLookasideList(&SharedCacheMapLookasideList,
1333 NULL,
1334 NULL,
1335 0,
1336 sizeof(ROS_SHARED_CACHE_MAP),
1337 TAG_SHARED_CACHE_MAP,
1338 20);
1339 ExInitializeNPagedLookasideList(&VacbLookasideList,
1340 NULL,
1341 NULL,
1342 0,
1343 sizeof(ROS_VACB),
1344 TAG_VACB,
1345 20);
1346
1347 MmInitializeMemoryConsumer(MC_CACHE, CcRosTrimCache);
1348
1349 CcInitCacheZeroPage();
1350 }
1351
1352 #if DBG && defined(KDBG)
1353 BOOLEAN
1354 ExpKdbgExtFileCache(ULONG Argc, PCHAR Argv[])
1355 {
1356 PLIST_ENTRY ListEntry;
1357 UNICODE_STRING NoName = RTL_CONSTANT_STRING(L"No name for File");
1358
1359 KdbpPrint(" Usage Summary (in kb)\n");
1360 KdbpPrint("Shared\t\tValid\tDirty\tName\n");
1361 /* No need to lock the spin lock here, we're in DBG */
1362 for (ListEntry = CcCleanSharedCacheMapList.Flink;
1363 ListEntry != &CcCleanSharedCacheMapList;
1364 ListEntry = ListEntry->Flink)
1365 {
1366 PLIST_ENTRY Vacbs;
1367 ULONG Valid = 0, Dirty = 0;
1368 PROS_SHARED_CACHE_MAP SharedCacheMap;
1369 PUNICODE_STRING FileName;
1370
1371 SharedCacheMap = CONTAINING_RECORD(ListEntry, ROS_SHARED_CACHE_MAP, SharedCacheMapLinks);
1372
1373 /* Dirty size */
1374 Dirty = (SharedCacheMap->DirtyPages * PAGE_SIZE) / 1024;
1375
1376 /* First, count for all the associated VACB */
1377 for (Vacbs = SharedCacheMap->CacheMapVacbListHead.Flink;
1378 Vacbs != &SharedCacheMap->CacheMapVacbListHead;
1379 Vacbs = Vacbs->Flink)
1380 {
1381 PROS_VACB Vacb;
1382
1383 Vacb = CONTAINING_RECORD(Vacbs, ROS_VACB, CacheMapVacbListEntry);
1384 if (Vacb->Valid)
1385 {
1386 Valid += VACB_MAPPING_GRANULARITY / 1024;
1387 }
1388 }
1389
1390 /* Setup name */
1391 if (SharedCacheMap->FileObject != NULL &&
1392 SharedCacheMap->FileObject->FileName.Length != 0)
1393 {
1394 FileName = &SharedCacheMap->FileObject->FileName;
1395 }
1396 else
1397 {
1398 FileName = &NoName;
1399 }
1400
1401 /* And print */
1402 KdbpPrint("%p\t%d\t%d\t%wZ\n", SharedCacheMap, Valid, Dirty, FileName);
1403 }
1404
1405 return TRUE;
1406 }
1407 #endif
1408
1409 /* EOF */