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