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