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