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