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