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