ntoskrnl header cleanups
[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(NULL,
661 MmGetKernelAddressSpace(),
662 MEMORY_AREA_CACHE_SEGMENT,
663 &current->BaseAddress,
664 Bcb->CacheSegmentSize,
665 PAGE_READWRITE,
666 (PMEMORY_AREA*)&current->MemoryArea,
667 FALSE,
668 FALSE,
669 BoundaryAddressMultiple);
670 MmUnlockAddressSpace(MmGetKernelAddressSpace());
671 if (!NT_SUCCESS(Status))
672 {
673 KEBUGCHECKCC;
674 }
675 #endif
676 Pfn = alloca(sizeof(PFN_TYPE) * (Bcb->CacheSegmentSize / PAGE_SIZE));
677 for (i = 0; i < (Bcb->CacheSegmentSize / PAGE_SIZE); i++)
678 {
679 Status = MmRequestPageMemoryConsumer(MC_CACHE, TRUE, &Pfn[i]);
680 if (!NT_SUCCESS(Status))
681 {
682 KEBUGCHECKCC;
683 }
684 }
685 Status = MmCreateVirtualMapping(NULL,
686 current->BaseAddress,
687 PAGE_READWRITE,
688 Pfn,
689 Bcb->CacheSegmentSize / PAGE_SIZE);
690 if (!NT_SUCCESS(Status))
691 {
692 KEBUGCHECKCC;
693 }
694 return(STATUS_SUCCESS);
695 }
696
697 NTSTATUS
698 NTAPI
699 CcRosGetCacheSegmentChain(PBCB Bcb,
700 ULONG FileOffset,
701 ULONG Length,
702 PCACHE_SEGMENT* CacheSeg)
703 {
704 PCACHE_SEGMENT current;
705 ULONG i;
706 PCACHE_SEGMENT* CacheSegList;
707 PCACHE_SEGMENT Previous = NULL;
708
709 ASSERT(Bcb);
710
711 DPRINT("CcRosGetCacheSegmentChain()\n");
712
713 Length = ROUND_UP(Length, Bcb->CacheSegmentSize);
714
715 #if defined(__GNUC__)
716 CacheSegList = alloca(sizeof(PCACHE_SEGMENT) *
717 (Length / Bcb->CacheSegmentSize));
718 #elif defined(_MSC_VER)
719 CacheSegList = _alloca(sizeof(PCACHE_SEGMENT) *
720 (Length / Bcb->CacheSegmentSize));
721 #else
722 #error Unknown compiler for alloca intrinsic stack allocation "function"
723 #endif
724
725 /*
726 * Look for a cache segment already mapping the same data.
727 */
728 for (i = 0; i < (Length / Bcb->CacheSegmentSize); i++)
729 {
730 ULONG CurrentOffset = FileOffset + (i * Bcb->CacheSegmentSize);
731 current = CcRosLookupCacheSegment(Bcb, CurrentOffset);
732 if (current != NULL)
733 {
734 CacheSegList[i] = current;
735 }
736 else
737 {
738 CcRosCreateCacheSegment(Bcb, CurrentOffset, &current);
739 CacheSegList[i] = current;
740 }
741 }
742
743 for (i = 0; i < (Length / Bcb->CacheSegmentSize); i++)
744 {
745 if (i == 0)
746 {
747 *CacheSeg = CacheSegList[i];
748 Previous = CacheSegList[i];
749 }
750 else
751 {
752 Previous->NextInChain = CacheSegList[i];
753 Previous = CacheSegList[i];
754 }
755 }
756 Previous->NextInChain = NULL;
757
758 return(STATUS_SUCCESS);
759 }
760
761 NTSTATUS
762 NTAPI
763 CcRosGetCacheSegment(PBCB Bcb,
764 ULONG FileOffset,
765 PULONG BaseOffset,
766 PVOID* BaseAddress,
767 PBOOLEAN UptoDate,
768 PCACHE_SEGMENT* CacheSeg)
769 {
770 PCACHE_SEGMENT current;
771 NTSTATUS Status;
772
773 ASSERT(Bcb);
774
775 DPRINT("CcRosGetCacheSegment()\n");
776
777 /*
778 * Look for a cache segment already mapping the same data.
779 */
780 current = CcRosLookupCacheSegment(Bcb, FileOffset);
781 if (current == NULL)
782 {
783 /*
784 * Otherwise create a new segment.
785 */
786 Status = CcRosCreateCacheSegment(Bcb, FileOffset, &current);
787 if (!NT_SUCCESS(Status))
788 {
789 return Status;
790 }
791 }
792 /*
793 * Return information about the segment to the caller.
794 */
795 *UptoDate = current->Valid;
796 *BaseAddress = current->BaseAddress;
797 DPRINT("*BaseAddress 0x%.8X\n", *BaseAddress);
798 *CacheSeg = current;
799 *BaseOffset = current->FileOffset;
800 return(STATUS_SUCCESS);
801 }
802
803 NTSTATUS STDCALL
804 CcRosRequestCacheSegment(PBCB Bcb,
805 ULONG FileOffset,
806 PVOID* BaseAddress,
807 PBOOLEAN UptoDate,
808 PCACHE_SEGMENT* CacheSeg)
809 /*
810 * FUNCTION: Request a page mapping for a BCB
811 */
812 {
813 ULONG BaseOffset;
814
815 ASSERT(Bcb);
816
817 if ((FileOffset % Bcb->CacheSegmentSize) != 0)
818 {
819 CPRINT("Bad fileoffset %x should be multiple of %x",
820 FileOffset, Bcb->CacheSegmentSize);
821 KEBUGCHECKCC;
822 }
823
824 return(CcRosGetCacheSegment(Bcb,
825 FileOffset,
826 &BaseOffset,
827 BaseAddress,
828 UptoDate,
829 CacheSeg));
830 }
831 #ifdef CACHE_BITMAP
832 #else
833 STATIC VOID
834 CcFreeCachePage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
835 PFN_TYPE Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
836 {
837 ASSERT(SwapEntry == 0);
838 if (Page != 0)
839 {
840 MmReleasePageMemoryConsumer(MC_CACHE, Page);
841 }
842 }
843 #endif
844 NTSTATUS
845 CcRosInternalFreeCacheSegment(PCACHE_SEGMENT CacheSeg)
846 /*
847 * FUNCTION: Releases a cache segment associated with a BCB
848 */
849 {
850 #ifdef CACHE_BITMAP
851 ULONG i;
852 ULONG RegionSize;
853 ULONG Base;
854 PFN_TYPE Page;
855 KIRQL oldIrql;
856 #endif
857 DPRINT("Freeing cache segment 0x%p\n", CacheSeg);
858 #if defined(DBG) || defined(KDBG)
859 if ( CacheSeg->Bcb->Trace )
860 {
861 DPRINT1("CacheMap 0x%p: deleting Cache Segment: 0x%p\n", CacheSeg->Bcb, CacheSeg );
862 }
863 #endif
864 #ifdef CACHE_BITMAP
865 RegionSize = CacheSeg->Bcb->CacheSegmentSize / PAGE_SIZE;
866
867 /* Unmap all the pages. */
868 for (i = 0; i < RegionSize; i++)
869 {
870 MmDeleteVirtualMapping(NULL,
871 CacheSeg->BaseAddress + (i * PAGE_SIZE),
872 FALSE,
873 NULL,
874 &Page);
875 MmReleasePageMemoryConsumer(MC_CACHE, Page);
876 }
877
878 KeAcquireSpinLock(&CiCacheSegMappingRegionLock, &oldIrql);
879 /* Deallocate all the pages used. */
880 Base = (ULONG)(CacheSeg->BaseAddress - CiCacheSegMappingRegionBase) / PAGE_SIZE;
881
882 RtlClearBits(&CiCacheSegMappingRegionAllocMap, Base, RegionSize);
883
884 CiCacheSegMappingRegionHint = min (CiCacheSegMappingRegionHint, Base);
885
886 KeReleaseSpinLock(&CiCacheSegMappingRegionLock, oldIrql);
887 #else
888 MmLockAddressSpace(MmGetKernelAddressSpace());
889 MmFreeMemoryArea(MmGetKernelAddressSpace(),
890 CacheSeg->MemoryArea,
891 CcFreeCachePage,
892 NULL);
893 MmUnlockAddressSpace(MmGetKernelAddressSpace());
894 #endif
895 ExFreeToNPagedLookasideList(&CacheSegLookasideList, CacheSeg);
896 return(STATUS_SUCCESS);
897 }
898
899 NTSTATUS
900 NTAPI
901 CcRosFreeCacheSegment(PBCB Bcb, PCACHE_SEGMENT CacheSeg)
902 {
903 NTSTATUS Status;
904 KIRQL oldIrql;
905
906 ASSERT(Bcb);
907
908 DPRINT("CcRosFreeCacheSegment(Bcb 0x%p, CacheSeg 0x%p)\n",
909 Bcb, CacheSeg);
910
911 ExAcquireFastMutex(&ViewLock);
912 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
913 RemoveEntryList(&CacheSeg->BcbSegmentListEntry);
914 RemoveEntryList(&CacheSeg->CacheSegmentListEntry);
915 RemoveEntryList(&CacheSeg->CacheSegmentLRUListEntry);
916 if (CacheSeg->Dirty)
917 {
918 RemoveEntryList(&CacheSeg->DirtySegmentListEntry);
919 DirtyPageCount -= Bcb->CacheSegmentSize / PAGE_SIZE;
920
921 }
922 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
923 ExReleaseFastMutex(&ViewLock);
924
925 Status = CcRosInternalFreeCacheSegment(CacheSeg);
926 return(Status);
927 }
928
929 /*
930 * @implemented
931 */
932 VOID STDCALL
933 CcFlushCache(IN PSECTION_OBJECT_POINTERS SectionObjectPointers,
934 IN PLARGE_INTEGER FileOffset OPTIONAL,
935 IN ULONG Length,
936 OUT PIO_STATUS_BLOCK IoStatus)
937 {
938 PBCB Bcb;
939 LARGE_INTEGER Offset;
940 PCACHE_SEGMENT current;
941 NTSTATUS Status;
942 KIRQL oldIrql;
943
944 DPRINT("CcFlushCache(SectionObjectPointers 0x%p, FileOffset 0x%p, Length %d, IoStatus 0x%p)\n",
945 SectionObjectPointers, FileOffset, Length, IoStatus);
946
947 if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap)
948 {
949 Bcb = (PBCB)SectionObjectPointers->SharedCacheMap;
950 ASSERT(Bcb);
951 if (FileOffset)
952 {
953 Offset = *FileOffset;
954 }
955 else
956 {
957 Offset.QuadPart = (LONGLONG)0;
958 Length = Bcb->FileSize.u.LowPart;
959 }
960
961 if (IoStatus)
962 {
963 IoStatus->Status = STATUS_SUCCESS;
964 IoStatus->Information = 0;
965 }
966
967 while (Length > 0)
968 {
969 current = CcRosLookupCacheSegment (Bcb, Offset.u.LowPart);
970 if (current != NULL)
971 {
972 if (current->Dirty)
973 {
974 Status = CcRosFlushCacheSegment(current);
975 if (!NT_SUCCESS(Status) && IoStatus != NULL)
976 {
977 IoStatus->Status = Status;
978 }
979 }
980 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
981 ExReleaseFastMutex(&current->Lock);
982 CcRosCacheSegmentDecRefCount(current);
983 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
984 }
985
986 Offset.QuadPart += Bcb->CacheSegmentSize;
987 if (Length > Bcb->CacheSegmentSize)
988 {
989 Length -= Bcb->CacheSegmentSize;
990 }
991 else
992 {
993 Length = 0;
994 }
995 }
996 }
997 else
998 {
999 if (IoStatus)
1000 {
1001 IoStatus->Status = STATUS_INVALID_PARAMETER;
1002 }
1003 }
1004 }
1005
1006 NTSTATUS
1007 NTAPI
1008 CcRosDeleteFileCache(PFILE_OBJECT FileObject, PBCB Bcb)
1009 /*
1010 * FUNCTION: Releases the BCB associated with a file object
1011 */
1012 {
1013 PLIST_ENTRY current_entry;
1014 PCACHE_SEGMENT current;
1015 NTSTATUS Status;
1016 LIST_ENTRY FreeList;
1017 KIRQL oldIrql;
1018
1019 ASSERT(Bcb);
1020
1021 Bcb->RefCount++;
1022 ExReleaseFastMutex(&ViewLock);
1023
1024 CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, NULL);
1025
1026 ExAcquireFastMutex(&ViewLock);
1027 Bcb->RefCount--;
1028 if (Bcb->RefCount == 0)
1029 {
1030 if (Bcb->BcbRemoveListEntry.Flink != NULL)
1031 {
1032 RemoveEntryList(&Bcb->BcbRemoveListEntry);
1033 Bcb->BcbRemoveListEntry.Flink = NULL;
1034 }
1035
1036 FileObject->SectionObjectPointer->SharedCacheMap = NULL;
1037
1038 /*
1039 * Release all cache segments.
1040 */
1041 InitializeListHead(&FreeList);
1042 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
1043 current_entry = Bcb->BcbSegmentListHead.Flink;
1044 while (!IsListEmpty(&Bcb->BcbSegmentListHead))
1045 {
1046 current_entry = RemoveTailList(&Bcb->BcbSegmentListHead);
1047 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
1048 RemoveEntryList(&current->CacheSegmentListEntry);
1049 RemoveEntryList(&current->CacheSegmentLRUListEntry);
1050 if (current->Dirty)
1051 {
1052 RemoveEntryList(&current->DirtySegmentListEntry);
1053 DirtyPageCount -= Bcb->CacheSegmentSize / PAGE_SIZE;
1054 DPRINT1("Freeing dirty segment\n");
1055 }
1056 InsertHeadList(&FreeList, &current->BcbSegmentListEntry);
1057 }
1058 #if defined(DBG) || defined(KDBG)
1059 Bcb->Trace = FALSE;
1060 #endif
1061 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
1062
1063 ExReleaseFastMutex(&ViewLock);
1064 ObDereferenceObject (Bcb->FileObject);
1065
1066 while (!IsListEmpty(&FreeList))
1067 {
1068 current_entry = RemoveTailList(&FreeList);
1069 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
1070 Status = CcRosInternalFreeCacheSegment(current);
1071 }
1072 ExFreeToNPagedLookasideList(&BcbLookasideList, Bcb);
1073 ExAcquireFastMutex(&ViewLock);
1074 }
1075 return(STATUS_SUCCESS);
1076 }
1077
1078 VOID
1079 NTAPI
1080 CcRosReferenceCache(PFILE_OBJECT FileObject)
1081 {
1082 PBCB Bcb;
1083 ExAcquireFastMutex(&ViewLock);
1084 Bcb = (PBCB)FileObject->SectionObjectPointer->SharedCacheMap;
1085 ASSERT(Bcb);
1086 if (Bcb->RefCount == 0)
1087 {
1088 ASSERT(Bcb->BcbRemoveListEntry.Flink != NULL);
1089 RemoveEntryList(&Bcb->BcbRemoveListEntry);
1090 Bcb->BcbRemoveListEntry.Flink = NULL;
1091
1092 }
1093 else
1094 {
1095 ASSERT(Bcb->BcbRemoveListEntry.Flink == NULL);
1096 }
1097 Bcb->RefCount++;
1098 ExReleaseFastMutex(&ViewLock);
1099 }
1100
1101 VOID
1102 NTAPI
1103 CcRosSetRemoveOnClose(PSECTION_OBJECT_POINTERS SectionObjectPointer)
1104 {
1105 PBCB Bcb;
1106 DPRINT("CcRosSetRemoveOnClose()\n");
1107 ExAcquireFastMutex(&ViewLock);
1108 Bcb = (PBCB)SectionObjectPointer->SharedCacheMap;
1109 if (Bcb)
1110 {
1111 Bcb->RemoveOnClose = TRUE;
1112 if (Bcb->RefCount == 0)
1113 {
1114 CcRosDeleteFileCache(Bcb->FileObject, Bcb);
1115 }
1116 }
1117 ExReleaseFastMutex(&ViewLock);
1118 }
1119
1120
1121 VOID
1122 NTAPI
1123 CcRosDereferenceCache(PFILE_OBJECT FileObject)
1124 {
1125 PBCB Bcb;
1126 ExAcquireFastMutex(&ViewLock);
1127 Bcb = (PBCB)FileObject->SectionObjectPointer->SharedCacheMap;
1128 ASSERT(Bcb);
1129 if (Bcb->RefCount > 0)
1130 {
1131 Bcb->RefCount--;
1132 if (Bcb->RefCount == 0)
1133 {
1134 MmFreeSectionSegments(Bcb->FileObject);
1135 if (Bcb->RemoveOnClose)
1136 {
1137 CcRosDeleteFileCache(FileObject, Bcb);
1138 }
1139 else
1140 {
1141 Bcb->TimeStamp = CcTimeStamp;
1142 InsertHeadList(&ClosedListHead, &Bcb->BcbRemoveListEntry);
1143 }
1144 }
1145 }
1146 ExReleaseFastMutex(&ViewLock);
1147 }
1148
1149 NTSTATUS STDCALL
1150 CcRosReleaseFileCache(PFILE_OBJECT FileObject)
1151 /*
1152 * FUNCTION: Called by the file system when a handle to a file object
1153 * has been closed.
1154 */
1155 {
1156 PBCB Bcb;
1157
1158 ExAcquireFastMutex(&ViewLock);
1159
1160 if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
1161 {
1162 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
1163 if (FileObject->PrivateCacheMap != NULL)
1164 {
1165 FileObject->PrivateCacheMap = NULL;
1166 if (Bcb->RefCount > 0)
1167 {
1168 Bcb->RefCount--;
1169 if (Bcb->RefCount == 0)
1170 {
1171 MmFreeSectionSegments(Bcb->FileObject);
1172 if (Bcb->RemoveOnClose)
1173 {
1174 CcRosDeleteFileCache(FileObject, Bcb);
1175 }
1176 else
1177 {
1178 Bcb->TimeStamp = CcTimeStamp;
1179 InsertHeadList(&ClosedListHead, &Bcb->BcbRemoveListEntry);
1180 }
1181 }
1182 }
1183 }
1184 }
1185 ExReleaseFastMutex(&ViewLock);
1186 return(STATUS_SUCCESS);
1187 }
1188
1189 NTSTATUS
1190 NTAPI
1191 CcTryToInitializeFileCache(PFILE_OBJECT FileObject)
1192 {
1193 PBCB Bcb;
1194 NTSTATUS Status;
1195
1196 ExAcquireFastMutex(&ViewLock);
1197
1198 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
1199 if (Bcb == NULL)
1200 {
1201 Status = STATUS_UNSUCCESSFUL;
1202 }
1203 else
1204 {
1205 if (FileObject->PrivateCacheMap == NULL)
1206 {
1207 FileObject->PrivateCacheMap = Bcb;
1208 Bcb->RefCount++;
1209 }
1210 if (Bcb->BcbRemoveListEntry.Flink != NULL)
1211 {
1212 RemoveEntryList(&Bcb->BcbRemoveListEntry);
1213 Bcb->BcbRemoveListEntry.Flink = NULL;
1214 }
1215 Status = STATUS_SUCCESS;
1216 }
1217 ExReleaseFastMutex(&ViewLock);
1218
1219 return Status;
1220 }
1221
1222
1223 NTSTATUS STDCALL
1224 CcRosInitializeFileCache(PFILE_OBJECT FileObject,
1225 ULONG CacheSegmentSize)
1226 /*
1227 * FUNCTION: Initializes a BCB for a file object
1228 */
1229 {
1230 PBCB Bcb;
1231
1232 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
1233 DPRINT("CcRosInitializeFileCache(FileObject 0x%p, Bcb 0x%p, CacheSegmentSize %d)\n",
1234 FileObject, Bcb, CacheSegmentSize);
1235
1236 ExAcquireFastMutex(&ViewLock);
1237 if (Bcb == NULL)
1238 {
1239 Bcb = ExAllocateFromNPagedLookasideList(&BcbLookasideList);
1240 if (Bcb == NULL)
1241 {
1242 ExReleaseFastMutex(&ViewLock);
1243 return(STATUS_UNSUCCESSFUL);
1244 }
1245 memset(Bcb, 0, sizeof(BCB));
1246 ObReferenceObjectByPointer(FileObject,
1247 FILE_ALL_ACCESS,
1248 NULL,
1249 KernelMode);
1250 Bcb->FileObject = FileObject;
1251 Bcb->CacheSegmentSize = CacheSegmentSize;
1252 if (FileObject->FsContext)
1253 {
1254 Bcb->AllocationSize =
1255 ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->AllocationSize;
1256 Bcb->FileSize =
1257 ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize;
1258 }
1259 KeInitializeSpinLock(&Bcb->BcbLock);
1260 InitializeListHead(&Bcb->BcbSegmentListHead);
1261 FileObject->SectionObjectPointer->SharedCacheMap = Bcb;
1262 }
1263 if (FileObject->PrivateCacheMap == NULL)
1264 {
1265 FileObject->PrivateCacheMap = Bcb;
1266 Bcb->RefCount++;
1267 }
1268 if (Bcb->BcbRemoveListEntry.Flink != NULL)
1269 {
1270 RemoveEntryList(&Bcb->BcbRemoveListEntry);
1271 Bcb->BcbRemoveListEntry.Flink = NULL;
1272 }
1273 ExReleaseFastMutex(&ViewLock);
1274
1275 return(STATUS_SUCCESS);
1276 }
1277
1278 /*
1279 * @implemented
1280 */
1281 PFILE_OBJECT STDCALL
1282 CcGetFileObjectFromSectionPtrs(IN PSECTION_OBJECT_POINTERS SectionObjectPointers)
1283 {
1284 PBCB Bcb;
1285 if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap)
1286 {
1287 Bcb = (PBCB)SectionObjectPointers->SharedCacheMap;
1288 ASSERT(Bcb);
1289 return Bcb->FileObject;
1290 }
1291 return NULL;
1292 }
1293
1294 VOID STDCALL
1295 CmLazyCloseThreadMain(PVOID Ignored)
1296 {
1297 LARGE_INTEGER Timeout;
1298 PLIST_ENTRY current_entry;
1299 PBCB current;
1300 ULONG RemoveTimeStamp;
1301 NTSTATUS Status;
1302
1303 KeQuerySystemTime (&Timeout);
1304
1305 while (1)
1306 {
1307 Timeout.QuadPart += (LONGLONG)100000000; // 10sec
1308 Status = KeWaitForSingleObject(&LazyCloseThreadEvent,
1309 0,
1310 KernelMode,
1311 FALSE,
1312 &Timeout);
1313
1314 DPRINT("LazyCloseThreadMain %d\n", CcTimeStamp);
1315
1316 if (!NT_SUCCESS(Status))
1317 {
1318 DbgPrint("LazyCloseThread: Wait failed\n");
1319 KEBUGCHECKCC;
1320 break;
1321 }
1322 if (LazyCloseThreadShouldTerminate)
1323 {
1324 DbgPrint("LazyCloseThread: Terminating\n");
1325 break;
1326 }
1327
1328 ExAcquireFastMutex(&ViewLock);
1329 CcTimeStamp++;
1330 if (CcTimeStamp >= 30)
1331 {
1332 RemoveTimeStamp = CcTimeStamp - 30; /* 5min = 10sec * 30 */
1333 while (!IsListEmpty(&ClosedListHead))
1334 {
1335 current_entry = ClosedListHead.Blink;
1336 current = CONTAINING_RECORD(current_entry, BCB, BcbRemoveListEntry);
1337 if (current->TimeStamp >= RemoveTimeStamp)
1338 {
1339 break;
1340 }
1341 CcRosDeleteFileCache(current->FileObject, current);
1342 }
1343 }
1344 ExReleaseFastMutex(&ViewLock);
1345 }
1346 }
1347
1348 VOID
1349 INIT_FUNCTION
1350 NTAPI
1351 CcInitView(VOID)
1352 {
1353 #ifdef CACHE_BITMAP
1354 PMEMORY_AREA marea;
1355 PVOID Buffer;
1356 PHYSICAL_ADDRESS BoundaryAddressMultiple;
1357 #endif
1358 NTSTATUS Status;
1359 KPRIORITY Priority;
1360
1361 DPRINT("CcInitView()\n");
1362 #ifdef CACHE_BITMAP
1363 BoundaryAddressMultiple.QuadPart = 0;
1364 CiCacheSegMappingRegionHint = 0;
1365 CiCacheSegMappingRegionBase = NULL;
1366
1367 MmLockAddressSpace(MmGetKernelAddressSpace());
1368
1369 Status = MmCreateMemoryArea(NULL,
1370 MmGetKernelAddressSpace(),
1371 MEMORY_AREA_CACHE_SEGMENT,
1372 &CiCacheSegMappingRegionBase,
1373 CI_CACHESEG_MAPPING_REGION_SIZE,
1374 0,
1375 &marea,
1376 FALSE,
1377 FALSE,
1378 BoundaryAddressMultiple);
1379 MmUnlockAddressSpace(MmGetKernelAddressSpace());
1380 if (!NT_SUCCESS(Status))
1381 {
1382 KEBUGCHECKCC;
1383 }
1384
1385 Buffer = ExAllocatePool(NonPagedPool, CI_CACHESEG_MAPPING_REGION_SIZE / (PAGE_SIZE * 8));
1386
1387 RtlInitializeBitMap(&CiCacheSegMappingRegionAllocMap, Buffer, CI_CACHESEG_MAPPING_REGION_SIZE / PAGE_SIZE);
1388 RtlClearAllBits(&CiCacheSegMappingRegionAllocMap);
1389
1390 KeInitializeSpinLock(&CiCacheSegMappingRegionLock);
1391 #endif
1392 InitializeListHead(&CacheSegmentListHead);
1393 InitializeListHead(&DirtySegmentListHead);
1394 InitializeListHead(&CacheSegmentLRUListHead);
1395 InitializeListHead(&ClosedListHead);
1396 ExInitializeFastMutex(&ViewLock);
1397 ExInitializeNPagedLookasideList (&iBcbLookasideList,
1398 NULL,
1399 NULL,
1400 0,
1401 sizeof(INTERNAL_BCB),
1402 TAG_IBCB,
1403 20);
1404 ExInitializeNPagedLookasideList (&BcbLookasideList,
1405 NULL,
1406 NULL,
1407 0,
1408 sizeof(BCB),
1409 TAG_BCB,
1410 20);
1411 ExInitializeNPagedLookasideList (&CacheSegLookasideList,
1412 NULL,
1413 NULL,
1414 0,
1415 sizeof(CACHE_SEGMENT),
1416 TAG_CSEG,
1417 20);
1418
1419 MmInitializeMemoryConsumer(MC_CACHE, CcRosTrimCache);
1420
1421 CcInitCacheZeroPage();
1422
1423 CcTimeStamp = 0;
1424 LazyCloseThreadShouldTerminate = FALSE;
1425 KeInitializeEvent (&LazyCloseThreadEvent, SynchronizationEvent, FALSE);
1426 Status = PsCreateSystemThread(&LazyCloseThreadHandle,
1427 THREAD_ALL_ACCESS,
1428 NULL,
1429 NULL,
1430 &LazyCloseThreadId,
1431 (PKSTART_ROUTINE)CmLazyCloseThreadMain,
1432 NULL);
1433 if (NT_SUCCESS(Status))
1434 {
1435 Priority = LOW_REALTIME_PRIORITY;
1436 NtSetInformationThread(LazyCloseThreadHandle,
1437 ThreadPriority,
1438 &Priority,
1439 sizeof(Priority));
1440 }
1441
1442 }
1443
1444 /* EOF */
1445
1446
1447
1448
1449
1450
1451