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