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