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