2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cc/cacheman.c
5 * PURPOSE: Cache manager
7 * PROGRAMMERS: David Welch (welch@cwcom.net)
8 * Pierre Schweitzer (pierre@reactos.org)
11 /* INCLUDES *****************************************************************/
17 BOOLEAN CcPfEnablePrefetcher
;
18 PFSN_PREFETCHER_GLOBALS CcPfGlobals
;
19 MM_SYSTEMSIZE CcCapturedSystemSize
;
21 static ULONG BugCheckFileId
= 0x4 << 16;
23 /* FUNCTIONS *****************************************************************/
28 CcPfInitializePrefetcher(VOID
)
31 DbgPrintEx(DPFLTR_PREFETCHER_ID
,
33 "CCPF: InitializePrefetecher()\n");
35 /* Setup the Prefetcher Data */
36 InitializeListHead(&CcPfGlobals
.ActiveTraces
);
37 InitializeListHead(&CcPfGlobals
.CompletedTraces
);
38 ExInitializeFastMutex(&CcPfGlobals
.CompletedTracesLock
);
40 /* FIXME: Setup the rest of the prefetecher */
46 CcInitializeCacheManager(VOID
)
52 /* Initialize lazy-writer lists */
53 InitializeListHead(&CcIdleWorkerThreadList
);
54 InitializeListHead(&CcExpressWorkQueue
);
55 InitializeListHead(&CcRegularWorkQueue
);
56 InitializeListHead(&CcPostTickWorkQueue
);
58 /* Define lazy writer threshold and the amount of workers,
59 * depending on the system type
61 CcCapturedSystemSize
= MmQuerySystemSize();
62 switch (CcCapturedSystemSize
)
65 CcNumberWorkerThreads
= ExCriticalWorkerThreads
- 1;
66 CcDirtyPageThreshold
= MmNumberOfPhysicalPages
/ 8;
70 CcNumberWorkerThreads
= ExCriticalWorkerThreads
- 1;
71 CcDirtyPageThreshold
= MmNumberOfPhysicalPages
/ 4;
75 CcNumberWorkerThreads
= ExCriticalWorkerThreads
- 2;
76 CcDirtyPageThreshold
= MmNumberOfPhysicalPages
/ 8 + MmNumberOfPhysicalPages
/ 4;
80 CcNumberWorkerThreads
= 1;
81 CcDirtyPageThreshold
= MmNumberOfPhysicalPages
/ 8;
85 /* Allocate a work item for all our threads */
86 for (Thread
= 0; Thread
< CcNumberWorkerThreads
; ++Thread
)
88 PWORK_QUEUE_ITEM Item
;
90 Item
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(WORK_QUEUE_ITEM
), 'qWcC');
96 /* By default, it's obviously idle */
97 ExInitializeWorkItem(Item
, CcWorkerThread
, Item
);
98 InsertTailList(&CcIdleWorkerThreadList
, &Item
->List
);
101 /* Initialize our lazy writer */
102 RtlZeroMemory(&LazyWriter
, sizeof(LazyWriter
));
103 InitializeListHead(&LazyWriter
.WorkQueue
);
104 /* Delay activation of the lazy writer */
105 KeInitializeDpc(&LazyWriter
.ScanDpc
, CcScanDpc
, NULL
);
106 KeInitializeTimer(&LazyWriter
.ScanTimer
);
108 /* Lookaside list for our work items */
109 ExInitializeNPagedLookasideList(&CcTwilightLookasideList
, NULL
, NULL
, 0, sizeof(WORK_QUEUE_ENTRY
), 'KWcC', 0);
116 CcShutdownSystem(VOID
)
126 CcGetFlushedValidData (
127 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
128 IN BOOLEAN BcbListHeld
158 CcScheduleReadAhead (
159 IN PFILE_OBJECT FileObject
,
160 IN PLARGE_INTEGER FileOffset
,
165 LARGE_INTEGER NewOffset
;
166 PROS_SHARED_CACHE_MAP SharedCacheMap
;
167 PPRIVATE_CACHE_MAP PrivateCacheMap
;
170 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
171 PrivateCacheMap
= FileObject
->PrivateCacheMap
;
173 /* If file isn't cached, or if read ahead is disabled, this is no op */
174 if (SharedCacheMap
== NULL
|| PrivateCacheMap
== NULL
||
175 BooleanFlagOn(SharedCacheMap
->Flags
, READAHEAD_DISABLED
))
180 /* Round read length with read ahead mask */
181 Length
= ROUND_UP(Length
, PrivateCacheMap
->ReadAheadMask
+ 1);
182 /* Compute the offset we'll reach */
183 NewOffset
.QuadPart
= FileOffset
->QuadPart
+ Length
;
185 /* Lock read ahead spin lock */
186 KeAcquireSpinLock(&PrivateCacheMap
->ReadAheadSpinLock
, &OldIrql
);
187 /* Easy case: the file is sequentially read */
188 if (BooleanFlagOn(FileObject
->Flags
, FO_SEQUENTIAL_ONLY
))
190 /* If we went backward, this is no go! */
191 if (NewOffset
.QuadPart
< PrivateCacheMap
->ReadAheadOffset
[1].QuadPart
)
193 KeReleaseSpinLock(&PrivateCacheMap
->ReadAheadSpinLock
, OldIrql
);
197 /* FIXME: hackish, but will do the job for now */
198 PrivateCacheMap
->ReadAheadOffset
[1].QuadPart
= NewOffset
.QuadPart
;
199 PrivateCacheMap
->ReadAheadLength
[1] = Length
;
201 /* Other cases: try to find some logic in that mess... */
204 /* Let's check if we always read the same way (like going down in the file)
205 * and pretend it's enough for now
207 if (PrivateCacheMap
->FileOffset2
.QuadPart
>= PrivateCacheMap
->FileOffset1
.QuadPart
&&
208 FileOffset
->QuadPart
>= PrivateCacheMap
->FileOffset2
.QuadPart
)
210 /* FIXME: hackish, but will do the job for now */
211 PrivateCacheMap
->ReadAheadOffset
[1].QuadPart
= NewOffset
.QuadPart
;
212 PrivateCacheMap
->ReadAheadLength
[1] = Length
;
216 /* FIXME: handle the other cases */
217 KeReleaseSpinLock(&PrivateCacheMap
->ReadAheadSpinLock
, OldIrql
);
218 if (!Warn
++) UNIMPLEMENTED
;
223 /* If read ahead isn't active yet */
224 if (!PrivateCacheMap
->Flags
.ReadAheadActive
)
226 PWORK_QUEUE_ENTRY WorkItem
;
229 * Be careful with the mask, you don't want to mess with node code
231 InterlockedOr((volatile long *)&PrivateCacheMap
->UlongFlags
, PRIVATE_CACHE_MAP_READ_AHEAD_ACTIVE
);
232 KeReleaseSpinLock(&PrivateCacheMap
->ReadAheadSpinLock
, OldIrql
);
234 /* Get a work item */
235 WorkItem
= ExAllocateFromNPagedLookasideList(&CcTwilightLookasideList
);
236 if (WorkItem
!= NULL
)
238 /* Reference our FO so that it doesn't go in between */
239 ObReferenceObject(FileObject
);
241 /* We want to do read ahead! */
242 WorkItem
->Function
= ReadAhead
;
243 WorkItem
->Parameters
.Read
.FileObject
= FileObject
;
245 /* Queue in the read ahead dedicated queue */
246 CcPostWorkQueue(WorkItem
, &CcExpressWorkQueue
);
251 /* Fail path: lock again, and revert read ahead active */
252 KeAcquireSpinLock(&PrivateCacheMap
->ReadAheadSpinLock
, &OldIrql
);
253 InterlockedAnd((volatile long *)&PrivateCacheMap
->UlongFlags
, ~PRIVATE_CACHE_MAP_READ_AHEAD_ACTIVE
);
257 KeReleaseSpinLock(&PrivateCacheMap
->ReadAheadSpinLock
, OldIrql
);
265 CcSetAdditionalCacheAttributes (
266 IN PFILE_OBJECT FileObject
,
267 IN BOOLEAN DisableReadAhead
,
268 IN BOOLEAN DisableWriteBehind
272 PROS_SHARED_CACHE_MAP SharedCacheMap
;
274 CCTRACE(CC_API_DEBUG
, "FileObject=%p DisableReadAhead=%d DisableWriteBehind=%d\n",
275 FileObject
, DisableReadAhead
, DisableWriteBehind
);
277 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
279 OldIrql
= KeAcquireQueuedSpinLock(LockQueueMasterLock
);
281 if (DisableReadAhead
)
283 SetFlag(SharedCacheMap
->Flags
, READAHEAD_DISABLED
);
287 ClearFlag(SharedCacheMap
->Flags
, READAHEAD_DISABLED
);
290 if (DisableWriteBehind
)
292 /* FIXME: also set flag 0x200 */
293 SetFlag(SharedCacheMap
->Flags
, WRITEBEHIND_DISABLED
);
297 ClearFlag(SharedCacheMap
->Flags
, WRITEBEHIND_DISABLED
);
299 KeReleaseQueuedSpinLock(LockQueueMasterLock
, OldIrql
);
307 CcSetBcbOwnerPointer (
312 PINTERNAL_BCB iBcb
= Bcb
;
314 CCTRACE(CC_API_DEBUG
, "Bcb=%p Owner=%p\n",
317 if (!ExIsResourceAcquiredExclusiveLite(&iBcb
->Lock
) && !ExIsResourceAcquiredSharedLite(&iBcb
->Lock
))
319 DPRINT1("Current thread doesn't own resource!\n");
323 ExSetResourceOwnerPointer(&iBcb
->Lock
, Owner
);
331 CcSetDirtyPageThreshold (
332 IN PFILE_OBJECT FileObject
,
333 IN ULONG DirtyPageThreshold
336 PFSRTL_COMMON_FCB_HEADER Fcb
;
337 PROS_SHARED_CACHE_MAP SharedCacheMap
;
339 CCTRACE(CC_API_DEBUG
, "FileObject=%p DirtyPageThreshold=%lu\n",
340 FileObject
, DirtyPageThreshold
);
342 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
343 if (SharedCacheMap
!= NULL
)
345 SharedCacheMap
->DirtyPageThreshold
= DirtyPageThreshold
;
348 Fcb
= FileObject
->FsContext
;
349 if (!BooleanFlagOn(Fcb
->Flags
, FSRTL_FLAG_LIMIT_MODIFIED_PAGES
))
351 SetFlag(Fcb
->Flags
, FSRTL_FLAG_LIMIT_MODIFIED_PAGES
);
360 CcSetReadAheadGranularity (
361 IN PFILE_OBJECT FileObject
,
365 PPRIVATE_CACHE_MAP PrivateMap
;
367 CCTRACE(CC_API_DEBUG
, "FileObject=%p Granularity=%lu\n",
368 FileObject
, Granularity
);
370 PrivateMap
= FileObject
->PrivateCacheMap
;
371 PrivateMap
->ReadAheadMask
= Granularity
- 1;