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