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